Laravel 原生无 Luhn 校验规则,需自定义 Rule 类实现;推荐使用 php artisan make:rule Luhn 创建,核心是双倍偶位、减9、求和模10为0,配合 str_replace 清洗空格短横线,并在 Form Request 中调用。

银行卡号校验该用哪个 Laravel 验证规则
直接说结论:Laravel 原生不提供 luhn 或 credit_card 验证规则,digits_between:16,19 只能拦长度,拦不住 16 个 0 这种假卡号。真要校验,得自己写规则或引入第三方包。
常见错误是只用 required|digits_between:16,19|regex:/^\d+$/,这会让 1234567890123456 过,但 Luhn 校验失败——它不是有效卡号。
- Visa 卡通常是 16 位,但也有 13/19 位;Mastercard 是 16 位;American Express 是 15 位;所以单靠长度不够
- Luhn 算法才是判断卡号是否“结构合法”的核心,它不验证卡是否存在,但能筛掉绝大多数输错、粘贴错、生成错的号码
- 别在前端 JS 里单独做 Luhn 校验就以为安全了——后端必须重做,否则绕过表单提交就能发脏数据
怎么写一个可复用的 Luhn 验证规则
推荐用 Laravel 的自定义验证规则类,比闭包更易测试和复用。运行 php artisan make:rule Luhn,然后在 app/Rules/Luhn.php 里填逻辑:
public function passes($attribute, $value)
{
if (! is_string($value) || ! preg_match('/^\d+$/', $value)) {
return false;
}
<pre class='brush:php;toolbar:false;'>$sum = 0;
$length = strlen($value);
for ($i = 0; $i < $length; $i++) {
$digit = (int) $value[$i];
if (($length - $i) % 2 === 0) {
$digit *= 2;
if ($digit > 9) $digit -= 9;
}
$sum += $digit;
}
return $sum % 10 === 0;}
使用时直接:'card_number' => ['required', 'string', new \App\Rules\Luhn]
- 注意:Luhn 不关心前缀(BIN),所以不能区分 Visa/Mastercard 类型,仅校验数字串本身合法性
- 别把空格、短横线(如
4512-3456-7890-1234)直接喂给 Luhn 规则——先用str_replace([' ', '-', '_'], '', $value)清洗 - 如果 API 允许带空格输入,建议在 Request 类的
prepareForValidation()里统一清理,而不是在规则里做字符串处理
要不要集成 laravel-validation-rules 包
有人会搜到 proengsoft/laravel-validation-rules 里的 luhn 规则,但它已多年未维护,且依赖旧版 Illuminate 组件,在 Laravel 10+ 上大概率报 Target class [validate.luhn] does not exist 错误。
- 它的
luhn规则底层逻辑没问题,但服务提供者注册方式和新版 Container 不兼容 - 如果你项目已用它其他规则(比如
iban),可以 fork 后手动适配,否则不建议为一个 Luhn 规则引入整个包 - 更轻量的做法是直接抄上面那段 Luhn 逻辑,5 行核心算法,无外部依赖,升级 Laravel 也不受影响
API 请求体字段校验放哪一层最合适
别在 Controller 里手写 if (! luhn_check($request->card_number)) ——这破坏了 Laravel 的验证契约,也难统一返回格式。正确位置是 Form Request。
- 运行
php artisan make:request StorePaymentRequest - 在
rules()方法里写:'card_number' => ['required', 'string', 'min:13', 'max:19', new \App\Rules\Luhn] - 这样错误会自动进
422 Unprocessable Entity响应,且字段名、消息都对齐 Laravel 的 JSON API 标准 - 如果还要查 BIN 前缀(比如只接受 Visa 和 Mastercard),建议额外加个
in:4,5或自定义规则,但别混进 Luhn 逻辑里——职责分离,方便以后替换或禁用
Luhn 算法本身很简单,但容易被当成“随便写几行就行”的事跳过测试。真上线前,至少拿几个公开的测试卡号(比如 4532015112830366)和故意改错一位的变体跑一遍单元测试,不然线上才发现校验没生效,就只能靠日志硬捞了。


















