给定信用卡号并且没有其他信息,PHP中确定它是否是有效数字的最佳方法是什么?
现在我需要能够使用American Express,Discover,MasterCard和Visa的东西,但如果它也可以与其他类型一起使用可能会有所帮助.
验证卡号有三个部分:
PATTERN - 是否与发行人模式匹配(例如VISA/Mastercard /等)
CHECKSUM - 它实际上是校验和(例如,不是"34"之后的13个随机数,使其成为AMEX卡号)
真的存在 - 它实际上是否有一个关联的帐户(没有商家帐户你不太可能得到这个)
MASTERCARD前缀= 51-55,长度= 16(Mod10校验和)
VISA前缀= 4,长度= 13或16(Mod10)
AMEX前缀= 34或37,长度= 15(Mod10)
Diners Club/Carte Prefix = 300-305,36或38,长度= 14(Mod10)
发现前缀= 6011,622126-622925,644-649,65,长度= 16,(Mod10)
等(前缀的详细列表)
大多数卡使用Luhn算法进行校验和:
维基百科上描述的Luhn算法
维基百科链接上有许多实现的链接,包括PHP:
/* Luhn algorithm number checker - (c) 2005-2008 shaman - www.planzero.org * * This code has been released into the public domain, however please * * give credit to the original author where possible. */ function luhn_check($number) { // Strip any non-digits (useful for credit card numbers with spaces and hyphens) $number=preg_replace('/\D/', '', $number); // Set the string length and parity $number_length=strlen($number); $parity=$number_length % 2; // Loop through each digit and do the maths $total=0; for ($i=0; $i<$number_length; $i++) { $digit=$number[$i]; // Multiply alternate digits by two if ($i % 2 == $parity) { $digit*=2; // If the sum is two digits, add them together (in effect) if ($digit > 9) { $digit-=9; } } // Total up the digits $total+=$digit; } // If the total mod 10 equals 0, the number is valid return ($total % 10 == 0) ? TRUE : FALSE; } ?>
从10个正则表达式中你不能没有PHP:
function check_cc($cc, $extra_check = false){ $cards = array( "visa" => "(4\d{12}(?:\d{3})?)", "amex" => "(3[47]\d{13})", "jcb" => "(35[2-8][89]\d\d\d{10})", "maestro" => "((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?)", "solo" => "((?:6334|6767)\d{12}(?:\d\d)?\d?)", "mastercard" => "(5[1-5]\d{14})", "switch" => "(?:(?:(?:4903|4905|4911|4936|6333|6759)\d{12})|(?:(?:564182|633110)\d{10})(\d\d)?\d?)", ); $names = array("Visa", "American Express", "JCB", "Maestro", "Solo", "Mastercard", "Switch"); $matches = array(); $pattern = "#^(?:".implode("|", $cards).")$#"; $result = preg_match($pattern, str_replace(" ", "", $cc), $matches); if($extra_check && $result > 0){ $result = (validatecard($cc))?1:0; } return ($result>0)?$names[sizeof($matches)-2]:false; }
样本输入:
$cards = array( "4111 1111 1111 1111", ); foreach($cards as $c){ $check = check_cc($c, true); if($check!==false) echo $c." - ".$check; else echo "$c - Not a match"; echo "
"; }
这给了我们
4111 1111 1111 1111 - Visa
最好不要在最后验证代码.将卡信息直接发送到您的支付网关,然后处理他们的回复.如果你不先做Luhn检查,那么它可以帮助他们检测欺诈行为 - 让他们看到失败的尝试.
PHP代码
function validateCC($cc_num, $type) { if($type == "American") { $denum = "American Express"; } elseif($type == "Dinners") { $denum = "Diner's Club"; } elseif($type == "Discover") { $denum = "Discover"; } elseif($type == "Master") { $denum = "Master Card"; } elseif($type == "Visa") { $denum = "Visa"; } if($type == "American") { $pattern = "/^([34|37]{2})([0-9]{13})$/";//American Express if (preg_match($pattern,$cc_num)) { $verified = true; } else { $verified = false; } } elseif($type == "Dinners") { $pattern = "/^([30|36|38]{2})([0-9]{12})$/";//Diner's Club if (preg_match($pattern,$cc_num)) { $verified = true; } else { $verified = false; } } elseif($type == "Discover") { $pattern = "/^([6011]{4})([0-9]{12})$/";//Discover Card if (preg_match($pattern,$cc_num)) { $verified = true; } else { $verified = false; } } elseif($type == "Master") { $pattern = "/^([51|52|53|54|55]{2})([0-9]{14})$/";//Mastercard if (preg_match($pattern,$cc_num)) { $verified = true; } else { $verified = false; } } elseif($type == "Visa") { $pattern = "/^([4]{1})([0-9]{12,15})$/";//Visa if (preg_match($pattern,$cc_num)) { $verified = true; } else { $verified = false; } } if($verified == false) { //Do something here in case the validation fails echo "Credit card invalid. Please make sure that you entered a valid " . $denum . " credit card "; } else { //if it will pass...do something echo "Your " . $denum . " credit card is valid"; } }
用法
echo validateCC("1738292928284637", "Dinners");
更多理论信息可以在这里找到:
信用卡验证 - 检查数字
校验
我们可以使用以下方法验证信用卡.它对我来说很完美.
protected function luhn($number) { // Force the value to be a string as this method uses string functions. // Converting to an integer may pass PHP_INT_MAX and result in an error! $number = (string)$number; if (!ctype_digit($number)) { // Luhn can only be used on numbers! return FALSE; } // Check number length $length = strlen($number); // Checksum of the card number $checksum = 0; for ($i = $length - 1; $i >= 0; $i -= 2) { // Add up every 2nd digit, starting from the right $checksum += substr($number, $i, 1); } for ($i = $length - 2; $i >= 0; $i -= 2) { // Add up every 2nd digit doubled, starting from the right $double = substr($number, $i, 1) * 2; // Subtract 9 from the double where value is greater than 10 $checksum += ($double >= 10) ? ($double - 9) : $double; } // If the checksum is a multiple of 10, the number is valid return ($checksum % 10 === 0); } protected function ValidCreditcard($number) { $card_array = array( 'default' => array( 'length' => '13,14,15,16,17,18,19', 'prefix' => '', 'luhn' => TRUE, ), 'american express' => array( 'length' => '15', 'prefix' => '3[47]', 'luhn' => TRUE, ), 'diners club' => array( 'length' => '14,16', 'prefix' => '36|55|30[0-5]', 'luhn' => TRUE, ), 'discover' => array( 'length' => '16', 'prefix' => '6(?:5|011)', 'luhn' => TRUE, ), 'jcb' => array( 'length' => '15,16', 'prefix' => '3|1800|2131', 'luhn' => TRUE, ), 'maestro' => array( 'length' => '16,18', 'prefix' => '50(?:20|38)|6(?:304|759)', 'luhn' => TRUE, ), 'mastercard' => array( 'length' => '16', 'prefix' => '5[1-5]', 'luhn' => TRUE, ), 'visa' => array( 'length' => '13,16', 'prefix' => '4', 'luhn' => TRUE, ), ); // Remove all non-digit characters from the number if (($number = preg_replace('/\D+/', '', $number)) === '') return FALSE; // Use the default type $type = 'default'; $cards = $card_array; // Check card type $type = strtolower($type); if (!isset($cards[$type])) return FALSE; // Check card number length $length = strlen($number); // Validate the card length by the card type if (!in_array($length, preg_split('/\D+/', $cards[$type]['length']))) return FALSE; // Check card number prefix if (!preg_match('/^' . $cards[$type]['prefix'] . '/', $number)) return FALSE; // No Luhn check required if ($cards[$type]['luhn'] == FALSE) return TRUE; return $this->luhn($number); }