在 PHP 中验证信用卡的最佳方法是什么?

如果给定一个信用卡号码而没有其他信息,那么在 PHP 中确定该号码是否为有效号码的最佳方法是什么?

现在我需要的东西,将工作与美国运通,发现,万事达卡,和 Visa,但它可能会有帮助,如果它也将与其他类型的工作。

81877 次浏览

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

注意,这不会检查某个人是否正在使用这些数字。

Http://www.roscripts.com/how_to_validate_credit_card_numbers-106.html

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

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

信用卡验证-检查数字

对号入座

验证卡号有三个部分:

  1. PATTERN -是否匹配发行者模式(例如 VISA/Mastercard/etc.)
  2. CHECKSUM -它实际上是校验和(例如,不仅仅是“34”后面的13个随机数字,使它成为一个 AMEX 卡号)
  3. 真实存在 -它是否真的有一个相关联的帐户(如果没有商人帐户,你不太可能得到这个帐户)

模式

  • MASTERCARD 前缀 = 51-55,长度 = 16(Mod10校验总和)
  • VISA 前缀 = 4,长度 = 13或16(Mod10)
  • AMEX 前缀 = 34或37,长度 = 15(Mod10)
  • 大来俱乐部/点菜前缀 = 300-305,36或38,长度 = 14(Mod10)
  • 发现前缀 = 6011,622126-622925,644-649,65,长度 = 16,(Mod10)
  • 等(前缀的详细列表)

对号入座

大多数卡片使用 Luhn 算法进行校验和:

维基百科上描述的鲁恩算法

在 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;


}
?>

Luhn 算法是一个校验和,可以用来验证许多信用卡格式的格式(以及加拿大社会保险号码...)

这篇 Wikipedia 文章还链接到许多不同的实现; 下面是一个 PHP 实现:

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

来自 PHP 中离不开的10个正则表达式:

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

这给了我们

4111 1111 1111 1111 - Visa

有一个 PEAR 包可以处理许多金融数字的验证,也可以处理信用卡验证: http://pear.php.net/package/Validate_Finance_CreditCard

顺便说一下,这里有一些由贝宝 测试信用卡帐号

最好不要在代码中进行验证。将信用卡信息发送到您的支付网关,然后处理他们的反应。如果你不像 Luhn 那样首先检查,它可以帮助他们发现欺诈——让他们看到失败的尝试。

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

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

验证:

>>> 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 函数

功能“ ccc”和“ ccd”(信用卡检查和信用卡数字)

注意,“ ccc”函数有一个额外的检查,如果计算出的和为0,返回的结果总是 FALSE,所以一个完全为零的 CC 数字将永远不会被验证为正确(在正常行为下,它将正确地验证)。这个特性可以根据需要添加/删除; 也许有用,这取决于特定的需求。

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 (l-i) 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 (l-i) 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)