gregwar/captcha可解决L与1混淆问题:支持自定义等宽衬线字体(如DejaVuSans.ttf)、禁用易混字符(I/O/l/1)、设4位长度及最小宽度130px,并需用v3.0+适配Laravel 10+与PHP 8.2+。

验证码图片里字母 L 和数字 1 怎么区分
默认的 Laravel 验证码(如 laravel/captcha)用的字体太细、间距太小,L 和 1 在小尺寸下几乎一样。这不是配置问题,是底层 GD 库渲染时字形压缩导致的视觉混淆。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 改用支持自定义字体的包,比如
gregwar/captcha,它允许你指定一个等宽、带明显衬线的字体文件(如DejaVuSans.ttf) - 在生成配置中禁用数字
1和字母I、O、l,只保留易辨识字符:ABCDEFGHJKMNPQRSTUVWXYZ23456789 - 把验证码长度设为 4(别用 5),并调高图片宽度至
130以上,给每个字符留足横向空间
Laravel 10+ 中集成 Gregwar/Captcha 的关键步骤
新版 Laravel 默认不带 GD 扩展,且 gregwar/captcha 的 v2.x 不兼容 PHP 8.2+,必须用 v3.0+。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 运行
composer require gregwar/captcha:~3.0(注意波浪号,避免装到 v2) - 发布配置:执行
php artisan vendor:publish --provider="Gregwar\Captcha\CaptchaServiceProvider",会生成config/captcha.php - 在
config/captcha.php中修改:'characters' => 'ABCDEFGHJKMNPQRSTUVWXYZ23456789',并设置'font' => public_path('fonts/DejaVuSans.ttf')(需提前把字体文件放好) - 路由里不要直接返回
Captcha::create(),它返回的是数组,要封装成 JSON:return response()->json(['captcha' => Captcha::create('default')]);
前端刷新验证码时后端 Session 不同步
常见现象是点刷新按钮,图片变了,但提交时总提示“验证码错误”——本质是前端没把新生成的 phrase 值传给后端校验逻辑,或前后端 session_id 不一致。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 后端生成验证码时,必须把
phrase存进 session:session(['captcha_phrase' => $captcha['phrase']]); - 前端 AJAX 刷新时,接口要返回新的
phrasehash(不能只返图片 URL),否则校验时拿不到比对值 - 确保 Nginx/Apache 没启用
fastcgi_buffering off类配置,这类设置可能截断 session cookie 的 Set-Cookie 头 - 如果用了 API 路由(
api/*),默认不启用 session,得在app/Http/Middleware/VerifyCsrfToken.php的$except里加对应路径,并确认中间件组包含StartSession
验证码校验失败却无日志输出
默认情况下 gregwar/captcha 校验失败不抛异常,也不记录日志,只静默返回 false,导致调试困难。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 手动加日志:在校验前 dump 当前 session 值:
Log::debug('Captcha session phrase:', ['stored' => session('captcha_phrase'), 'input' => $request->input('captcha')]); - 检查大小写:默认校验是严格大小写的,前端输入
AbC1,后端存的是abc1就会失败;可在生成时加'lowercase' => true配置项 - 留意缓存干扰:如果用了 Redis 或 APCu 做 session 驱动,重启服务后旧 session 可能残留,清空一次
php artisan cache:clear && php artisan config:clear再试
phrase 值的流转,少一步就全链路失效。



















