Skip to content

Instantly share code, notes, and snippets.

@wesen
Created April 5, 2013 21:28
Show Gist options
  • Select an option

  • Save wesen/5322764 to your computer and use it in GitHub Desktop.

Select an option

Save wesen/5322764 to your computer and use it in GitHub Desktop.
function validateCreditCard($cardnumber, $cardname) {
if ($cardname[0]) {
// accept masked cc numbers
return true;
}
$ccErrorNo = 0;
$ccErrors = array ();
$ccErrors[0] = "Unknown card type.";
$ccErrors[1] = "No card number provided.";
$ccErrors[2] = "Credit card number is in invalid format.";
$ccErrors[3] = "Credit card number is invalid.";
$ccErrors[4] = "Credit card number has an inappropriate number of digits.";
// Array to hold the permitted card characteristics
$cards = array();
// Define the cards we support. You may add addtional card types.
// Name: As in the selection box of the form - must be same as user's
// Length: List of possible valid lengths of the card number for the card
// prefixes: List of possible prefixes for the card
// checkdigit Boolean to say whether there is a check digit
$cards[0] = array("name" => "Visa","length" => "13,16","prefixes" => "4","checkdigit" => true);
$cards[1] = array("name" => "MasterCard","length" => "16","prefixes" => "51,52,53,54,55","checkdigit" => true);
$cards[2] = array("name" => "DinersClub","length" => "14,16","prefixes" => "300,301,302,303,304,305,36,38,55","checkdigit" => true);
$cards[3] = array("name" => "CarteBlanche","length" => "14","prefixes" => "300,301,302,303,304,305,36,38","checkdigit" => true);
$cards[4] = array("name" => "AmEx","length" => "15","prefixes" => "34,37","checkdigit" => true);
$cards[5] = array("name" => "Discover","length" => "16","prefixes" => "6011,650","checkdigit" => true);
$cards[6] = array("name" => "JCB","length" => "15,16","prefixes" => "3,1800,2131","checkdigit" => true);
$cards[7] = array("name" => "enRoute","length" => "15","prefixes" => "2014,2149","checkdigit" => true);
$cards[8] = array("name" => "Solo","length" => "16,18,19","prefixes" => "6334, 6767","checkdigit" => true);
$cards[9] = array("name" => "Switch","length" => "16,18,19","prefixes" => "4903,4905,4911,4936,564182,633110,6333,6759","checkdigit" => true);
$cards[10] = array("name" => "Maestro", "length" => "16,18","prefixes" => "5020,6","checkdigit" => true);
$cards[11] = array("name" => "VisaElectron","length" => "16","prefixes" => "417500,4917,4913","checkdigit" => true);
// Establish card type
$cardType = -1;
for ($i=0; $i<count($cards); $i++) {
// See if it is this card (ignoring the case of the string)
if (strtolower($cardname.toLowerCase) == strtolower($cards[i]["name"])) {
$cardType = $i;
break;
}
}
// If card type not found, report an error
if ($cardType == -1) {
$ccErrorNo = 0;
return false;
}
// Ensure that the user has provided a credit card number
if (strlen($cardnumber) == 0) {
$ccErrorNo = 1;
return false;
}
// Now remove any spaces from the credit card number
$cardnumber = preg_replace("/\s/g", "",$cardnumber);
// Check that the number is numeric
$cardNo = $cardnumber;
$cardexp = "/^[0-9]{13,19}$/";
if(!preg_match('/^[0-9]{13,19}$/', $cardNo)) {
$ccErrorNo = 2;
return false;
}
// Now check the modulus 10 check digit - if required
if ($cards[$cardType]["checkdigit"]) {
$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
$calc;
for ($i = strlen($cardNo) - 1; $i >= 0; $i--) {
// Extract the next digit and multiply by 1 or 2 on alternative digits.
$calc = int(substr($cardNo,$i,1)) * 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) {
$ccErrorNo = 3;
return false;
}
}
// The following are the card-specific checks we undertake.
$LengthValid = false;
$PrefixValid = false;
$undefined;
// We use these for holding the valid lengths and prefixes of a card type
$prefix = array ();
$lengths = array ();
// Load an array with the valid prefixes for this card
$prefix = split(",",$cards[$cardType]["prefixes"]);
// Now see if any of them match what we have in the card number
for ($i=0; $i<count($prefix); $i++) {
$exp = "/^".$prefix[$i]."/";
if (preg_match($exp,$cardNo)) $PrefixValid = true;
}
// If it isn't a valid prefix there's no point at looking at the length
if (!$PrefixValid) {
$ccErrorNo = 3;
return false;
}
// See if the length is valid for this card
$lengths = split(",",$cards[$cardType]["length"]);
for ($j=0; j<count(lengths); $j++) {
if (strlen($cardNo) == $lengths[$j]) $LengthValid = true;
}
// See if all is OK by seeing if the length was valid. We only check the
// length if all else was hunky dory.
if (!$LengthValid) {
$ccErrorNo = 4;
return false;
};
// The credit card is in the required format.
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment