PHP实现信用卡号校验与有效期验证
在接入支付渠道时,对银行卡号进行本地预校验能有效降低无效请求。本文将展示一个PHP函数,支持主流信用卡的BIN段识别、长度检查、Luhn算法校验及有效期判断。
功能与原理说明
完整的信用卡验证通常包含三个核心步骤:首先是格式与长度的初步筛查,根据国际标准化组织(ISO/IEC 7812)标准,不同发卡机构的卡号具有特定的开头数字和固定长度;其次是数学逻辑校验,业界普遍采用Luhn算法检测输入错误;最后是当前状态的确认,即检查卡片是否仍在有效期内。
第1步:定义验证函数入口与预处理
目的:获取原始输入,清洗非数字字符,为后续逻辑处理提供干净的字符串。
- 函数命名:
PIPHP_ValidateCC - 参数说明:
$number:字符串形式的信用卡号。$expiry:有效期,格式支持MM/YY或纯数字MMYY。- 清洗操作:使用正则表达式
/[^\d]/移除所有非数字字符。
// 提取纯数字的卡号
$number = preg_replace('/[^\d]/', '', $number);
// 提取纯数字的有效期
$expiry = preg_replace('/[^\d]/', '', $expiry);
第2步:发卡机构识别与长度校验
目的:根据卡号的前4位数字(BIN/IIN范围),匹配支持的银行网络,并拒绝长度不符的卡号。
以下是常见卡段的识别规则:
- Diners Club:3000-3059, 3600-3699, 3800-3889(要求长度14位)
- JCB:3088-3094, 3096-3102, 3112-3120, 3158-3159, 3337-3349, 3528-3589(要求长度16位)
- American Express:3400-3499, 3700-3799(要求长度15位)
- Visa:4000-4999(允许长度13位或16位)
- MasterCard:5100-5599(要求长度16位)
- Discover/Carte Blanche/BankCard等:根据特定区间判断
若卡号不在上述范围内,或对应的长度条件不满足,则直接返回 FALSE。
第3步:执行Luhn算法验证
目的:通过加权求和并取模运算,确保输入的卡号符合国际标准,排除偶然录入错误。
- 从右向左数(偶数位加奇数位,具体取决于起始索引计算)。代码中通过循环变量
$j分别处理基数和偶数位。 - 对偶数位置上的数字乘以2,若结果大于等于10,则减去9(等价于各位数字之和)。
- 将所有数字累加得到
$chksum。 - 若
$chksum % 10不为0,则卡号无效。
第4步:有效期状态检查
目的:防止已过期但仍符合算法校验的旧卡号被使用。
- 将解析后的月份作为月份参数,当年当年的最后一天作为日期参数,创建时间戳。
- 如果该时间点早于当前服务器时间(
time()),说明已过期,返回FALSE。
完整源码参考
<?php
// 测试数据示例
$card = "4567 1234 5678 9101";
$exp = "06/11";
echo "Validating: $card : $exp<br>";
$result = PIPHP_ValidateCC($card, $exp);
if ($result != FALSE) {
echo "Card Validated Successfully";
} else {
echo "Card did not validate";
}
function PIPHP_ValidateCC($number, $expiry)
{
// 清理非数字字符
$number = preg_replace('/[^\d]/', '', $number);
$expiry = preg_replace('/[^\d]/', '', $expiry);
// 提取前4位用于识别发卡机构
$left = substr($number, 0, 4);
$cclen = strlen($number);
$chksum = 0;
// --- 发卡机构逻辑 ---
// Diners Club (Len 14)
if (($left >= 3000) && ($left <= 3059) ||
($left >= 3600) && ($left <= 3699) ||
($left >= 3800) && ($left <= 3889))
if ($cclen != 14) return FALSE;
// JCB (Len 16)
if (($left >= 3088) && ($left <= 3094) ||
($left >= 3096) && ($left <= 3102) ||
($left >= 3112) && ($left <= 3120) ||
($left >= 3158) && ($left <= 3159) ||
($left >= 3337) && ($left <= 3349) ||
($left >= 3528) && ($left <= 3589))
if ($cclen != 16) return FALSE;
// American Express (Len 15)
elseif (($left >= 3400) && ($left <= 3499) ||
($left >= 3700) && ($left <= 3799))
if ($cclen != 15) return FALSE;
// Carte Blanche (Len 14)
elseif (($left >= 3890) && ($left <= 3899))
if ($cclen != 14) return FALSE;
// Visa (Len 13 or 16)
elseif (($left >= 4000) && ($left <= 4999))
if ($cclen != 13 && $cclen != 16) return FALSE;
// MasterCard (Len 16)
elseif (($left >= 5100) && ($left <= 5599))
if ($cclen != 16) return FALSE;
// Australian BankCard (Len 16)
elseif ($left == 5610)
if ($cclen != 16) return FALSE;
// Discover (Len 16)
elseif ($left == 6011)
if ($cclen != 16) return FALSE;
// 未知类型
else return FALSE;
// --- Luhn 算法校验 ---
for ($j = 1 - ($cclen % 2); $j < $cclen; $j += 2)
$chksum += substr($number, $j, 1);
for ($j = $cclen % 2; $j < $cclen; $j += 2)
{
$d = substr($number, $j, 1) * 2;
$chksum += $d < 10 ? $d : $d - 9;
}
if ($chksum % 10 != 0) return FALSE;
// --- 有效期判断 ---
// 注意:该部分依赖服务器所在时区及年份逻辑,对于测试环境有效,生产环境建议由支付网关确认
$expiry_month = substr($expiry, 0, 2);
$expiry_year = substr($expiry, 2, 2);
// 构建当月最后一天的时间戳进行比较
if (@mktime(0, 0, 0, $expiry_month, date("t", mktime(0,0,0,$expiry_month,1,$expiry_year)), $expiry_year) < time())
return FALSE;
return TRUE;
}
?>
注意事项
- 安全性:本地JS或PHP脚本只能进行格式校验。真实的资金交易必须依赖银行或第三方支付网关(如Stripe、支付宝、银联)的异步回调来确认卡片真伪及余额。
- 兼容性:代码中包含的逻辑(如
mktime的使用)假设了较新的PHP版本特性,旧版本环境中可能需要调整日期的构造方式。
以上就是利用PHP实现信用卡通用规则验证的详细内容,更多关于PHP程序设计的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













