| Erfahrener Benutzer
Registriert seit: 21.05.2008
Beiträge: 9.937
| PHP: Kreditkartenvalidierung Hallo,
ich habe mir soeben eine Klasse gebastelt, mit der sich Kreditkarten-Numbern validieren lassen. Dies erfolgt ausschliesslich per Formatpruefung. Ein Modul fuer Authorize.net ist geplant, ebenso wie eine Auslagerung der Sprachen in der Exception-Klasse. PHP-Code: <?php
try {
CreditCard::SetTestMode();
$objCC = new CreditCard();
$objCC->AllowType(CreditCard::Discover, CreditCard::MasterCard);
$objCC->Type = CreditCard::Visa; // check type
$objCC->Number = NULL; // test your credit card number here
$objCC->ExpirationYear = 2008;
$objCC->ExpirationMonth = 3;
$objCC->Check();
printf("Your credit card (%s) is valid.", $objCC->Xnumber);
} catch (CreditCardException $objExc) {
$objExc->RenderHtml();
}
// the input should be denied for multiple reasons:
// "Visa" is not allowed, no number entered, expired.
?> Ganz laessig finde ich auch den TestMode (eigentlich dafuer gedacht um einen teuren Online-Check zu vermeiden), der entsprechend des Fehlers eine andere Ausgabe erzeugt. Beispielsweise soll der User im Livemodus keine naeheren Informationen darueber erhalten, weshalb seine Kreditkarten Nummer nicht akzeptiert wurde, um Fakes zu vermeiden. Ein Blick auf die Kreditkarte (wenn sie denn existiert) sollte dem Benutzer Klarheit verschaffen.
Ebenfalls steht die Methode GetXnumber() bzw. die Eigenschaft Xnumber zur Verfuegung, um alles bis auf die letzten 4 Zeichen der Kreditkarte durch Xe zu ersetzen.
Ich wuerde mich freuen, wenn ihr eure Kreditkarten damit testet, ich konnte bisher nur meine Visa-Karte erfolgreich testen, das ist leider etwas wenig. Postet mir dann bitte NICHT eure Kreditkarten Nummern - die Exception reicht aus (obwohl, ..)
Zur Lizenz: Ihr koennt die Klasse frei verwenden, privat oder kommerziel, ihr koennt sie auch weiterentwickeln, wuerde mich ueber Feedback freuen.
In den naechsten Tagen werde ich die Klasse um einige weitere Kreditkartentypen und Kommentare (am Ende hatte ich keine Lust mehr) erweitern. PHP-Code: <?php
/**
* @desc
* Provides a credit card checking functionality. You can check type, number and expiration date for consistency.
* This class handles the credit card number as string, not as integer to prevent integer overflows.
*
* @author Christian Reinecke <christian.reinecke@web.de>
* @date 2008-04-11
* @version 0.1 beta
*
* @licence
* Free for usage in any project, private or commercial. Just keep this author comments in the file.
*
* @warning
* Never checked in a real production system.
*
* @example
* <code>
* try {
* CreditCard::SetTestMode(); // detailed error messages
*
* $objCC = new CreditCard();
* // $objCC->AllowAllTypes();
* $objCC->AllowType(CreditCard::Visa, CreditCard::MasterCard);
* $objCC->Type = "Visa";
* $objCC->Number = "1234-abcd-5678-9101-1121"; // your credit card here, format not important, but use a string
* $objCC->ExpirationYear = 12;
* $objCC->ExpirationMonth = 3;
*
* $objCC->Check();
* printf("Your credit card (%s) is valid.", $objCC->Xnumber);
* } catch (CreditCardException $objExc) {
* $objExc->RenderHtml();
* }
* </code>
*/
class CreditCard {
/**
* @desc
* The default mode provide has yet no effect to this class, but to the CreditCardException.
*/
const TestModeDefault = true;
/**
* @desc Abbreviations for the provided cc types.
* @see $CreditCard->GetAllowedTypesAsOptions()
*/
const AmericanExpress = "AmEx";
const Discover = "Disc";
const MasterCard = "MC";
const Visa = "Visa";
/**
* @desc
* Using integer constants instead of associate string keys to address key index in the $arrTypes array.
*
* @warning internal use only
*/
const Name = 0;
const Abbrev = 1;
const Length = 2;
const Prefix = 3;
const CheckDigit = 4;
/**
* @desc information about credit card checks, feel free to extend the array
* @var array
*/
protected $arrTypes = array(
self::AmericanExpress => array(self::Name => "American Express",
self::Abbrev => "AmEx",
self::Length => 15,
self::Prefix => array("34", "37"), // using string to prevent integer overflow
self::CheckDigit => true),
self::Discover => array(self::Name => "Discover",
self::Abbrev => "Disc",
self::Length => 16,
self::Prefix => "6011",
self::CheckDigit => true),
self::MasterCard => array(self::Name => "MasterCard",
self::Abbrev => "MC",
self::Length => 16,
self::Prefix => array("51", "52", "53", "54", "55"),
self::CheckDigit => true),
self::Visa => array(self::Name => "Visa",
self::Abbrev => "Visa",
self::Length => array(13, 16),
self::Prefix => "4",
self::CheckDigit => true),
);
/**
* @desc current test mode status
* @staticvar bool
*/
protected static $blnTestMode = self::TestModeDefault;
/**
* @desc each cc object has its own list of allowed cc types, because you might accept not every cc type
* @var array
*/
protected $arrAllowedTypes = array();
/**
* @desc information about the cc type, should be a value of the class constants
* @see CreditCard::Visa, CreditCard::MasterCard, ..
* @see $CreditCard->Type
* @see $CreditCard->SetType()
* @see $CreditCard->OriginalType
* @see $CreditCard->CheckType()
* @var string
*/
protected $strType;
/**
* @desc user's cc card number, might be cleaned up, let's use string here (otherwise we get an integer overflow)
* @see $CreditCard->Number
* @see $CreditCard->OriginalNumber
* @see $CreditCard->CheckNumber()
* @var string
*/
protected $strNumber;
/**
* @desc
* The user's cc card expiration full year, that means that this integer has 4 digits (f.e. 2008), even if the user
* entered a 2-digit year (08).
*
* @see $CreditCard->ExpirationFullYear
* @see $CreditCard->OriginalExpirationYear
* @see $CreditCard->ExpirationMonth
* @see $CreditCard->OriginalExpirationMonth
* @see $CreditCard->CheckExpirationDate()
* @var int
*/
protected $intExpirationFullYear;
/**
* @desc user's cc card expiration month
* @see $CreditCard->ExpirationMonth
* @see $CreditCard->OriginalExpirationMonth
* @see $CreditCard->ExpirationFullYear
* @see $CreditCard->OriginalExpirationYear
* @see $CreditCard->CheckExpirationDate()
* @var int
*/
protected $intExpirationMonth;
/**
* @desc
* The card security code is the security code on the back side of most credit cards, we are using a string
* to loose leading zeros.
*
* @warning not yet implemented
* @todo implement
* @see
* @see CreditCard::CheckCsc()
* @var string
*/
protected $strCsc;
/**
* @desc the original user-provided string (just trimmed) for his cc type, we probably don't need this
* @warning might be removed in the next version
* @see $CreditCard->OriginalType
*/
protected $strOriginalType;
/**
* @desc
* The original user-provided string (just trimmed) for his cc number, it's used for displaying the x-number,
* because we want to use the user's input syntax (1235-4567-.. -> XXXX-XXXX-..) instead of using the
* normalized cc number (12354567.. -> XXXXXXXX).
*
* @see $CreditCard->OriginalNumber
*/
protected $strOriginalNumber;
/**
* @desc
* The original user-provided string (just trimmed) for his expiration year, might be different from the
* expiration *full* year (8 -> 2008).
*
* @warning might be removed in the next version
* @see $CreditCard->OriginalExpirationYear
*/
protected $strOriginalExpirationYear;
/**
* @desc the original user-provided string (just trimmed) for his expiration month, we probably don't need this
* @warning might be removed in the next version
* @see $CreditCard->OriginalExpirationMonth
*/
protected $strOriginalExpirationMonth;
/**
* @desc the original user-provided string (just trimmed) for his cc security code, we probably don't need this
* @warning might be removed in the next version
* @see $CreditCard->OriginalCsc
*/
protected $strOriginalCsc;
/**
* @desc constructor
* @warning the arguments may change in future versions
* @param string optional allowed cc type (use as much arguments as you need)
*/
public function __construct() {
$arrAllowedTypes = func_get_args();
foreach ($arrAllowedTypes as $strAllowedType) {
$this->AllowType($strAllowedType);
}
}
/**
* @desc magic setter method
* @see $CreditCard->GetSetterProperties()
* @see $CreditCard->Set*()
*/
public function __set($strProperty, $strValue) {
if (!in_array($strProperty, $this->GetSetterProperties())) {
throw new CreditCardException(CreditCardException::UndefinedSetProperty, $strProperty, $this->GetSetterProperties());
}
$strMethod = "Set$strProperty";
if (!method_exists($this, $strMethod)) {
throw new CreditCardException(CreditCardException::UndefinedSetMethod, $strMethod, $strProperty, $strValue);
}
$this->$strMethod($strValue);
}
/**
* @desc magic getter method
* @see $CreditCard->GetGetterProperties()
* @see $CreditCard->Get*()
*/
public function __get($strProperty) {
if (!in_array($strProperty, $this->GetGetterProperties())) {
throw new CreditCardException(CreditCardException::UndefinedGetProperty, $strProperty, $this->GetGetterProperties());
}
$strMethod = "Get$strProperty";
if (!method_exists($this, $strMethod)) {
throw new CreditCardException(CreditCardException::UndefinedGetMethod, $strMethod, $strProperty);
}
return $this->$strMethod();
}
/**
* @desc set test mode to TRUE
* @see CreditCard::SetLiveMode()
* @see CreditCard::IsTestMode()
* @return void
*/
public static function SetTestMode() {
self::$blnTestMode = true;
}
/**
* @desc set test mode to FALSE
* @see CreditCard::SetTestMode()
* @see CreditCard::IsLivetMode()
* @return void
*/
public static function SetLiveMode() {
// feel free to comment the following line, but in a good live system, you shouldn't see any E_NOTICE errors
trigger_error(sprintf("PHP user class %s has been set to *LIVE* mode", __CLASS__), E_USER_NOTICE);
self::$blnTestMode = false;
}
/**
* @desc checks your current test mode status
* @see CreditCard::SetTestMode()
* @see CreditCard::IsLiveMode()
* @return bool
*/
public static function IsTestMode() {
return self::$blnTestMode;
}
/**
* @desc checks your current test mode status
* @see CreditCard::SetLiveMode()
* @see CreditCard::IsTestMode()
* @return bool
*/
public static function IsLiveMode() {
return !self::$blnTestMode;
}
/**
* @desc
* Validate and checks the user's input. This method has no return value, it case of an error it throws an
* exception and it is up to you to catch this exception. In case of success, nothing happens.
*
* @example
* <code>
* try {
* $objCC = new CreditCard();
* // set user's input
* $objCC->Check();
* $blnSuccess = true;
* } catch (CreditCardException $objExc) {
* $blnSuccess = false;
* }
* </code>
*
* @see $CreditCard->CheckType()
* @see $CreditCard->CheckNumber()
* @see $CreditCard->CheckExpirationDate()
* @see $CreditCard->CheckCsc()
* @link [url]http://php.net/exceptions[/url]
*
* @param bool optional check also CSC
* @return void
*/
public function Check($blnCheckCsc = false) {
$this->CheckType();
$this->CheckNumber();
$this->CheckExpirationDate();
if ($blnCheckCsc) {
$this->CheckCsc();
}
}
/**
* @desc allow public "setting" for these properties
* @return array
*/
protected function GetSetterProperties() {
return array("Type", "Number", "ExpirationYear", "ExpirationMonth", "Csc");
}
/**
* @desc allow public "getting" for these properties
* @return array
*/
protected function GetGetterProperties() {
return array("Type", "OriginalType", "Number", "OriginalNumber", "ExpirationFullYear", "OriginalExpirationYear",
"ExpirationMonth", "OriginalExpirationMonth", "Csc", "OriginalCsc", "Xnumber");
}
/**
* @desc getter method for number
* @see $CreditCard->Number
* @return string
*/
public function GetNumber() {
return $this->strNumber;
}
/**
* @desc getter method for original number
* @see $CreditCard->Number
* @return mix
*/
public function GetOriginalNumber() {
return $this->strOriginalNumber;
}
/**
* @desc
* Public getter method for the x-number. The x-number replaces all digits of the original number,
* except the last 4 with an X.
*
* @example XXXX-XXXX-XXXX-6789
* @see $CreditCard->Xnumber
* @see $CreditCard->OriginalNumber
* @return string
*/
public function GetXnumber() {
// x-fill credit card number left-handed except for the last 4 digits
$arrMatches = NULL;
if (!preg_match("#^(.+)(([0-9][^0-9]*){4})$#", trim($this->OriginalNumber), $arrMatches)) {
return preg_replace("#[0-9]#", "X", $this->OriginalNumber);
}
$strPrefix = $arrMatches[1];
$strPostfix = $arrMatches[2];
return preg_replace("#[0-9]#", "X", $strPrefix) . $strPostfix;
}
/**
* @desc setter method for type
* @see $CreditCard->Type
* @return string
*/
public function SetType($strType) {
$this->strOriginalType = $strType;
$this->strType = (string)trim($this->strOriginalType);
}
/**
* @desc getter method for type
* @see $CreditCard->Type
* @see $CreditCard->OriginalType
* @return string
*/
public function GetType() {
return $this->strType;
}
/**
* @desc getter method for expiration full year
* @see $CreditCard->ExpirationFullYear
* @see $CreditCard->OriginalExpirationYear
* @return string
*/
public function GetExpirationFullYear() {
return $this->intExpirationFullYear;
}
/**
* @desc getter method for expiration month
* @see $CreditCard->ExpirationMonth
* @see $CreditCard->OriginalExpirationMonth
* @return string
*/
public function GetExpirationMonth() {
return $this->intExpirationMonth;
}
/**
* @desc getter method for original expiration year
* @warning might be removed in future versions
* @see $CreditCard->OriginalExpirationYear
* @return mix
*/
public function GetOriginalExpirationYear() {
return $this->strOriginalExpirationYear;
}
/**
* @desc getter method for original expiration month
* @warning might be removed in future versions
* @see $CreditCard->OriginalExpirationMonth
* @return mix
*/
public function GetOriginalExpirationMonth() {
return $this->strOriginalExpirationMonth;
}
/**
* @desc getter method for cc security code
* @see $CreditCard->Csc
* @return string
*/
public function GetCsc() {
return $this->strCsc;
}
/**
* @desc
* You can use this method after adding the allowed types for your cc check. The return value is an array,
* the keys are the abbreviations, the values the name of the credit card. You might use this to build
* your html <select>/<options> formular.
*
* @example
* array("Visa" => "Visa", "MC" => "MasterCard", ..)
*
* @see $CreditCard->AllowType()
* @see $CreditCard->AllowAllTypes()
* @return array
*/
public function GetAllowedTypesAsOptions() {
$arrSelectOptions = array();
foreach ($this->GetAllowedTypes() as $strAllowedType) {
$arrSelectOptions[$strAllowedType] = $this->arrTypes[$strAllowedType][self::Name];
}
ksort($arrSelectOptions);
return $arrSelectOptions;
}
/**
* @desc checks your cc type and throws an exception if there has been any error found
*/
protected function CheckType() {
if (is_null($this->Type)) {
throw new CreditCardException(CreditCardException::CheckFailedTypeUnset);
}
if (strlen($this->Type) == 0) {
throw new CreditCardException(CreditCardException::EmptyType);
}
if (!$this->IsType($this->Type)) {
throw new CreditCardException(CreditCardException::UnknownType, $this->Type, $this->GetAllTypes());
}
if (!$this->IsAllowedType()) {
throw new CreditCardException(CreditCardException::DisallowedType, $this->GetTypeName(), $this->GetAllowedTypesNames());
}
}
public function SetNumber($strNumber, $blnIsOriginal = true) {
$strOriginalNumber = trim($strNumber);
if ($blnIsOriginal) {
$this->strOriginalNumber = trim($strOriginalNumber);
}
$this->strNumber = (string)trim($strOriginalNumber);
// do not clean up number here, we should check for bad characters first
// it might be a feature to just ignore every non-digit, but I felt uncomfortable to accept
// credit card numbers like these: "1234-hello-5678-91011-1213"
// so clean it up later
}
protected function CheckNumber() {
if (is_null($this->Number)) {
throw new CreditCardException(CreditCardException::CheckFailedNumberUnset);
}
if (strlen($this->strNumber) == 0) {
throw new CreditCardException(CreditCardException::EmptyNumber);
}
if (is_null($this->Type)) {
throw new CreditCardException(CreditCardException::SetTypeFirst);
}
if (preg_match("#([^0-9 \-\/\|\+])+#", $this->Number, $arrMatch)) {
throw new CreditCardException(CreditCardException::DisallowedCharacterInNumber, $arrMatch[1]);
}
// ok bad character test passed, let's clean it up
$this->SetNumber(preg_replace("#[^0-9]#", "", $this->Number), false);
$arrAllowedLengths = (array)$this->arrTypes[$this->Type][self::Length];
if (!in_array(strlen($this->Number), $arrAllowedLengths)) {
throw new CreditCardException(CreditCardException::WrongNumberLength, $intLength, $arrAllowedLengths);
}
$blnPrefixFound = false;
$arrPrefix = (array)$this->arrTypes[$this->Type][self::Prefix];
foreach ($arrPrefix as $strPrefix) {
$blnPrefixFound = (strpos($this->Number, $strPrefix) === 0);
if ($blnPrefixFound) {
break;
}
}
if (!$blnPrefixFound) {
throw new CreditCardException(CreditCardException::WrongNumberPrefix, $arrPrefix);
}
$this->CheckDigit();
}
public function SetExpirationYear($strExpirationYear) {
$this->strOriginalExpirationYear = $strExpirationYear;
$intExpirationYear = (int)$this->strOriginalExpirationYear;
$this->intExpirationFullYear = ($intExpirationYear < 100) ? ($intExpirationYear + 2000) : $intExpirationYear;
}
public function SetExpirationMonth($strExpirationMonth) {
$this->strOriginalExpirationMonth = $strExpirationMonth;
$this->intExpirationMonth = (int)$this->strOriginalExpirationMonth;
}
protected function CheckExpirationDate() {
if (is_null($this->ExpirationFullYear)) {
throw new CreditCardException(CreditCardException::CheckFailedExpirationFullYearUnset);
}
if (is_null($this->ExpirationMonth)) {
throw new CreditCardException(CreditCardException::CheckFailedExpirationMonthUnset);
}
if ($this->ExpirationFullYear < @date("Y")) { // suppress E_STRICT timezone error
throw new CreditCardException(CreditCardException::Expired, $this->ExpirationFullYear);
}
if ($this->ExpirationFullYear > @date("Y") + 15) {
throw new CreditCardException(CreditCardException::UnlikelyExpirationYear, $this->ExpirationFullYear);
}
if ($this->ExpirationMonth < 1 || $this->ExpirationMonth > 12) {
throw new CreditCardException(CreditCardException::InvalidExpirationMonth, $this->ExpirationMonth);
}
if ($this->ExpirationFullYear == @date("Y") && $this->ExpirationMonth < @date("n")) { // year check (for being smaller) is already done
throw new CreditCardException(CreditCardException::Expired, array($this->ExpirationFullYear, $this->ExpirationMonth));
}
}
public function SetCsc($strCsc) {
$this->strOriginalCsc = $strCsc;
$this->strCsc = (string)trim($this->strOriginalCsc);
}
protected function CheckCsc() {
throw new CreditCardException(CreditCardException::NotYetImplemented, __METHOD__);
}
protected function CheckDigit() {
// external code
$checksum = 0; // running checksum total
$mychar = ""; // next char to process
$j = 1; // takes value of 1 or 2
// Process each digit one by one starting at the right
for ($i = strlen($this->Number) - 1; $i >= 0; $i--) {
// Extract the next digit and multiply by 1 or 2 on alternative digits.
$calc = $this->Number{$i} * $j;
// If the result is in two digits add 1 to the checksum total
if ($calc > 9) {
$checksum = $checksum + 1;
$calc = $calc - 10;
}
// Add the units element to the checksum total
$checksum = $checksum + $calc;
// Switch the value of j
if ($j ==1) {$j = 2;} else {$j = 1;};
}
// All done - if checksum is divisible by 10, it is a valid modulus 10.
// If not, report an error.
if ($checksum % 10 != 0) {
throw new CreditCardException(CreditCardException::CheckDigitFailed, $checksum);
}
}
protected function IsType($strType) {
return in_array($strType, $this->GetAllTypes());
}
protected function GetAllTypes() {
if (empty($this->arrTypes)) {
throw new CreditCardException(CreditCardException::NoTypesDefined);
}
$arrTypesAbbrev = array();
foreach ($this->arrTypes as $arrType) {
$arrTypesAbbrev[] = $arrType[self::Abbrev];
}
return $arrTypesAbbrev;
}
protected function GetAllTypesNames() {
$arrNames = array();
foreach ($this->arrTypes as $arrType) {
$arrNames[] = $arrType[self::Name];
}
return $arrNames;
}
public function AllowAllTypes() {
$this->arrAllowedTypes = array_keys($this->arrTypes);
}
public function AllowType() {
$arrArg = func_get_args();
for ($i = 0, $x = func_num_args(); $i < $x; ++$i) {
if (!$this->IsType($arrArg[$i])) {
throw new CreditCardException(CreditCardException::AllowingUnknownType, $arrArg[$i], $this->GetAllTypes());
}
$this->arrAllowedTypes[] = $arrArg[$i];
}
}
public function GetTypeName() {
return $this->arrTypes[$this->Type][self::Name];
}
protected function IsAllowedType() {
return in_array($this->Type, $this->GetAllowedTypes());
}
protected function GetAllowedTypes() {
if (empty($this->arrAllowedTypes)) {
throw new CreditCardException(CreditCardException::NoAllowedTypesDefined, $this->GetAllTypes());
}
return $this->arrAllowedTypes;
}
protected function GetAllowedTypesNames() {
$arrNames = array();
foreach ($this->arrAllowedTypes as $strType) {
$arrNames[] = $this->arrTypes[$strType][self::Name];
}
return $arrNames;
}
}
class CreditCardException extends Exception {
const UndefinedSetProperty = 1001;
const UndefinedGetProperty = 1002;
const EmptyType = 3;
const UnknownType = 4;
const DisallowedType = 5;
const EmptyNumber = 6;
const SetTypeFirst = 1007;
const ValidateNumberMethodNotFound = 1008;
const Expired = 9;
const UnlikelyExpirationYear = 10;
const InvalidExpirationMonth = 11;
//const SetExpirationYearFirst = 1012;
const EmptyCsc = 13;
const SetNumberFirst = 1014;
const ValidateCscMethodNotFound = 1015;
const NoTypesDefined = 1016;
const AllowingUnknownType = 1017;
const NoAllowedTypesDefined = 1018;
const UndefinedSetMethod = 1019;
const UndefinedGetMethod = 1020;
const NotYetImplemented = 1021;
const CheckFailedTypeUnset = 1022;
const CheckDigitFailed = 23;
const CheckFailedExpirationMonthUnset = 1024;
const CheckFailedExpirationFullYearUnset = 1025;
const WrongNumberPrefix = 26;
const WrongNumberLength = 27;
const CheckFailedNumberUnset = 1028;
const DisallowedCharacterInNumber = 29;
const NumberError = 999;
const DevelopmentError = 1000; // any error greater than this is an development error
protected $arrMessages = array(
self::UndefinedSetProperty => "Trying to set undefined property (%s), should be one of these: %s.",
self::UndefinedSetMethod => "Trying to call undefined setter method (%s) for property (%s), value (%s).",
self::UndefinedGetProperty => "Trying to get undefined property (%s), should be one of these: %s.",
self::UndefinedGetMethod => "Trying to call undefined getter method (%s) for property (%s).",
self::EmptyType => "The given credit card type must not be empty.",
self::UnknownType => "The given credit card type (%s) is unknown, only these are allowed: %s.",
self::DisallowedType => "The given credit card type (%s) is unfortunatelly not allowed, please choose one of these: %s.",
self::EmptyNumber => "The given credit card number must not be empty.",
self::SetTypeFirst => "Please set the credit card type first.",
self::ValidateNumberMethodNotFound => "Trying to call non-existing method (%s) to validate the credit card number by its credit card type (%s).",
self::Expired => "The given credit card expiration date (%s) has already been expired.",
self::UnlikelyExpirationYear => "The given credit card expiration year seem to be unlikely high and could not be accepted; please contact the support.",
self::InvalidExpirationMonth => "The given credit card expiration month (%s) is not valid (must be between 1 and 12).",
self::EmptyCsc => "The given card security code (CSC) must not be empty.",
self::SetNumberFirst => "Please set the credit card number first.",
self::ValidateCscMethodNotFound => "Trying to call non-existing method (%s) to validate the card's security code (CSC) by its credit card type (%s) and number (%s).",
self::NoTypesDefined => "There are no credit card types defined.",
self::AllowingUnknownType => "Trying to allow unknown credit card type (%s), please choose one of these: %s.",
self::NoAllowedTypesDefined => "There are no allowed credit card types defined, please choose at least one of these: %s.",
self::NotYetImplemented => "Trying to call not yet implemented method (%s).",
self::CheckFailedTypeUnset => "Checking credit card type failed, type is not set.",
self::CheckDigitFailed => "Checking credit card digit failed.",
self::CheckFailedExpirationMonthUnset => "Checking credit card month failed, month is not set.",
self::CheckFailedExpirationFullYearUnset => "Checking credit card year failed, year is not set.",
self::WrongNumberPrefix => "Checking prefix of credit card number failed, prefix is wrong, should be one of these: %s.",
self::WrongNumberLength => "Checking length of credit card number (%s) failed, should be this/one of these: %s)",
self::CheckFailedNumberUnset => "Checking credit card number failed, number is not set.",
self::DisallowedCharacterInNumber => "There are characters in your credit card number (%s) which are not allowed.",
self::NumberError => "The credit card number is not valid.",
self::DevelopmentError => "We are sorry - but an unexpected error occured while checking the credit card information; please contact the support.",
);
public function __construct($intCode) {
$arrArgs = func_get_args();
array_shift($arrArgs); // remove first argument, $intCode
if (!empty($arrArgs)) {
// convert arrays into comma-separated string
foreach ($arrArgs as $i => $mixArg) {
if (is_array($mixArg)) {
$arrArgs[$i] = implode(", ", $mixArg);
}
}
$arrArgs = array_merge($arrArgs); // reset array indexes
}
$strMessage = vsprintf($this->arrMessages[$intCode], $arrArgs);
parent::__construct($strMessage, $intCode);
}
public function __toString() {
$strMessage = $this->GetMessage();
if (CreditCard::IsLiveMode()) {
if ($this->GetCode() > self::DevelopmentError) {
// don't show any development errors in live mode
// please have a look at the error code, it still tells you what error occured
$strMessage = $this->arrMessages[self::DevelopmentError]; // correct now
} else if (in_array($this->GetCode(), $this->GetCodesToMergeNumber())) {
$strMessage = $this->arrMessages[self::NumberError];
}
} else {
$strMessage .= "\n\n" . $this->GetTraceAsString();
}
return sprintf("(%u) %s", $this->GetCode(), $strMessage);
}
public function RenderHtml() {
printf('<div class="error-message">%s</div>', nl2br($this->__toString()));
}
protected function GetCodesToMergeNumber() {
return array(self::CheckDigitFailed, self::WrongNumberPrefix, self::WrongNumberLength);
}
}
?> Edit OK auch hier die Klassenkonstante umbenannt, sollte richtig sein. |