在PHP中validation信用卡的最佳方式是什么?

给定一个信用卡号码,没有额外的信息,什么是最好的方式在PHP来确定它是否是一个有效的数字?

现在我需要一些能够与美国运通,Discover,MasterCard和Visa合作的东西,但是如果它也可以与其他types一起使用,这可能会有所帮助。

validation卡号有三个部分:

  1. 模式 – 它是否符合发行者模式(例如VISA /万事达卡等)
  2. CHECKSUM – 它是否实际检查总数(例如,“34”之后不只是13个随机数字,使其成为AMEX卡号)
  3. 真的存在 – 它实际上是否有关联的帐户(如果没有商家帐户,你不太可能得到这个帐户)

模式

  • 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)
  • 等等( 详细的前缀列表 )

校验

大多数卡片使用Luhnalgorithm进行校验:

在维基百科上描述的Luhnalgorithm

Wikipedia链接上有很多实现的链接,包括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个正则expression式中你不能没有生活在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; } 

示例input:

 $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 "<br/>"; } 

这给了我们

  4111 1111 1111 1111  -  Visa

最好不要在代码中进行validation。 将卡信息发送到您的支付网关,然后处理他们的回复。 它可以帮助他们检测到欺诈行为,如果你不做任何事情就像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 <em>" . $denum . "</em> credit card "; } else { //if it will pass...do something echo "Your <em>" . $denum . "</em> credit card is valid"; } } 

用法

 echo validateCC("1738292928284637", "Dinners"); 

更多的理论信息可以在这里find:

信用卡validation – 检查数字

校验

我们可以使用以下来validation信用卡。 这对我来说是完美的。

 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); } 

luhnalgorithm是一个校验和,可以用来validation很多信用卡格式的格式(还有加拿大的社会保险号码)

维基百科文章也链接到许多不同的实现; 这里是一个PHP的:

http://planzero.org/code/bits/viewcode.php?src=luhn_check.phps

有一个PEAR包处理许多财务数字的validation,也是信用卡validation: http : //pear.php.net/package/Validate_Finance_CreditCard

顺便说一下,这里有一些贝宝的testing信用卡帐号 。

只是抛出一些其他人可能会发现有用的代码片段(而不是PHP代码)。

PYTHON (单行代码;可能不那么高效)

validation:

 >>> not(sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('1234567890123452'))))))%10) True >>> not(sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('1234567890123451'))))))%10) False 

要返回所需的校验位:

 >>> (10-sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('123456789012345')), start=1)))))%10 2 >>> (10-sum(map(int, ''.join(str(n*(i%2+1)) for i, n in enumerate(map(int, reversed('234567890123451')), start=1)))))%10 1 

MySQL函数

function“ccc”和“ccd”(信用卡支票和信用卡号码)

请注意,“ccc”函数有一个额外的检查,如果计算的总和为0,返回的结果将始终为FALSE,所以一个全零CC号永远不会validation是正确的(正常情况下,它会validation正确)。 此function可以根据需要添加/删除; 也许有用,取决于具体的要求。

 DROP FUNCTION IF EXISTS ccc; DROP FUNCTION IF EXISTS ccd; DELIMITER // CREATE FUNCTION ccc (n TINYTEXT) RETURNS BOOL BEGIN DECLARE x TINYINT UNSIGNED; DECLARE l TINYINT UNSIGNED DEFAULT length(n); DECLARE i TINYINT UNSIGNED DEFAULT l; DECLARE s SMALLINT UNSIGNED DEFAULT 0; WHILE i > 0 DO SET x = mid(n,i,1); IF (li) mod 2 = 1 THEN SET x = x * 2; END IF; SET s = s + x div 10 + x mod 10; SET i = i - 1; END WHILE; RETURN s != 0 && s mod 10 = 0; END; CREATE FUNCTION ccd (n TINYTEXT) RETURNS TINYINT BEGIN DECLARE x TINYINT UNSIGNED; DECLARE l TINYINT UNSIGNED DEFAULT length(n); DECLARE i TINYINT UNSIGNED DEFAULT l; DECLARE s SMALLINT UNSIGNED DEFAULT 0; WHILE i > 0 DO SET x = mid(n,i,1); IF (li) mod 2 = 0 THEN SET x = x * 2; END IF; SET s = s + x div 10 + x mod 10; SET i = i - 1; END WHILE; RETURN ceil(s/10)*10-s; END; 

函数可以直接在SQL查询中使用:

 mysql> SELECT ccc(1234567890123452); +-----------------------+ | ccc(1234567890123452) | +-----------------------+ | 1 | +-----------------------+ 1 row in set (0.00 sec) mysql> SELECT ccc(1234567890123451); +-----------------------+ | ccc(1234567890123451) | +-----------------------+ | 0 | +-----------------------+ 1 row in set (0.00 sec) mysql> SELECT ccd(123456789012345); +----------------------+ | ccd(123456789012345) | +----------------------+ | 2 | +----------------------+ 1 row in set (0.00 sec) mysql> SELECT ccd(234567890123451); +----------------------+ | ccd(234567890123451) | +----------------------+ | 1 | +----------------------+ 1 row in set (0.00 sec) 

这只是为了确保数字是有效的使用一些基本的RegEX模式。

请注意,这不检查数字是否被某人使用。

http://www.roscripts.com/How_to_validate_credit_card_numbers-106.html