ThinkPHP6验证码依赖topthink/think-captcha扩展,需启用Session中间件、正确配置captcha.php,并通过{:captcha_img()}输出或专用路由生成,校验失败多因Session不一致、验证码已消耗或大小写不匹配。

ThinkPHP6 的验证码不是内置功能,而是依赖 topthink/think-captcha 扩展包实现的“服务端生成 + Session 存储 + 前端提交比对”机制。核心在于:图像和对应文本必须来自同一会话周期,否则必然失败。
验证码生成的关键前提
生成环节失效,90% 是环境没配好,不是代码写错:
- 必须用
composer require topthink/think-captcha安装扩展,TP6 不自带 - Session 中间件必须启用:检查
app/middleware.php中\think\middleware\SessionInit::class是否已取消注释(TP6 默认是注释状态) - 不能手动调
session_start()—— 必须靠中间件自动初始化,否则$_SESSION不可用 - 验证 Session 是否真生效:在控制器里写
session('test', 'ok'); var_dump(session('test'));,输出string(2) "ok"才算通过
安全又稳定的图像输出方式
直接在控制器 return new Captcha()->create() 容易因输出顺序、空白字符或响应头问题导致图片损坏(浏览器显示“无法加载”):
- 模板中优先用
{:captcha_img()}—— 它自动生成带时间戳参数的<img src="/captcha?_=1717232520" alt="ThinkPHP6验证码原理详解:从生成到验证的最佳实践" >,天然防缓存、点击可刷新 - 若需自定义路由,应绑定到专用方法,例如:
Route::get('captcha', [\think\captcha\facade\Captcha::class, 'create']); - 该方法体内严禁任何
echo、var_dump或布局模板中的空行,哪怕一个换行符都会破坏 PNG 流
验证码校验失败的常见原因与对策
captcha_check($input) 返回 false,多数不是逻辑错误,而是上下文不一致:
立即学习“PHP免费学习笔记(深入)”;
- 用户输入为空或全是空格:前端应
.trim()后再提交,后端也建议先trim($input) - Session ID 不一致:登录页和提交页跨子域名(如
login.example.comvswww.example.com),或前后端分离时未携带 cookie,导致存一份、查另一份 - 验证码已被消耗:默认一次有效,check 成功后自动清除 session 中值;JS 重复提交、F5 刷新后重试旧值都会失败
- 大小写不匹配:默认区分大小写;若前端输入小写但验证码含大写字母,需统一转大写比对,或配置
'useZh' => false, 'codeSet' => '0123456789'纯数字避免歧义
实用配置与增强建议
在 config/captcha.php 中调整可显著提升可用性与安全性:
- 降低识别难度:设
'useCurve' => false, 'useNoise' => false适合内部系统;对外公开页面建议保留 true - 控制有效期:
'expire' => 300(5分钟),避免长期有效被复用 - 精简字符集:设
'codeSet' => '23456789'排除 0/o/O/1/l/i,减少用户输错概率 - 限制长度:
'length' => 4平衡安全与体验,超过 5 位易引发用户抵触 - 字体与尺寸:
'fontSize' => 22, 'imageW' => 130, 'imageH' => 45更适配移动端表单宽度


















