ThinkPHP验证码生成失败主因是GD扩展未启用、Session未初始化或响应头被污染;GD未启导致create()静默失败,Session未启使check()恒为false,响应头含HTML或无image/png则图片无法渲染。

ThinkPHP验证码生成失败,通常不是代码写错了,而是底层运行环境或流程链断了。最常卡在三个环节:GD库没开、Session没启、响应头被污染。下面按排查优先级说明。
GD扩展未启用
验证码图片本质是GD库画出来的。没GD,Captcha::create() 或 $cap->entry() 会静默返回空,或直接报 Call to undefined function imagecreate()。
- 终端执行
php -m | grep gd,有输出才表示已启用 - 没输出就去
php.ini取消注释extension=gd(Windows 下可能是php_gd2.dll),改完重启 Web 服务 - Docker 环境常见于基础镜像不带 GD,需手动安装依赖并编译:
apt install libpng-dev libjpeg-dev && docker-php-ext-configure gd --with-jpeg-dir=/usr/include/ && docker-php-ext-install gd
Session未初始化
验证码文本(如 7Fk2)靠 Session 存储,前端提交的只是用户输入。Session 没启,check() 永远返回 false,且生成端可能只出空白图,无明显报错。
- TP6:确认
app/middleware.php中已启用\think\middleware\SessionInit::class - TP5.1:检查
application/tags.php的app_init数组是否含\think\middleware\SessionInit::class - 快速验证:控制器里加
session('test', 'ok'); dump(session('test'));,输出null就说明 Session 失效
响应头被意外覆盖
验证码接口必须返回纯二进制 PNG 数据,并带 Content-Type: image/png。只要中间件、钩子或方法里提前 echo、dump()、return json() 或输出空格,图片就会损坏——浏览器显示“加载失败”,Network 面板看到乱码或 HTML 片段。
立即学习“PHP免费学习笔记(深入)”;
- 验证码方法里禁止任何非图像输出,不要混用
return view()或return json() - 标准写法只用一行:
return Captcha::create();(TP6)或$cap = new Captcha(); return $cap->entry();(TP5/6),它们内部已处理 header 和输出 - 调试时用
curl -I http://your.site/captcha查响应头,确认含Content-Type: image/png,且没有text/html
其他易忽略点
有些问题不致命但高频出现,也值得顺手检查:
-
runtime 目录不可写:尤其 TP5/6 使用 File 缓存驱动时,
runtime/session写失败会导致验证码值存不进去 -
缓存干扰:前端
<img src="/captcha">被浏览器缓存,点击刷新要加时间戳:src="/captcha?t="+Math.random() -
ob_clean() 补救:TP5 旧版本存在输出缓冲残留问题,可在生成方法开头加
ob_clean();强制清空缓冲区 -
大小写敏感:默认区分大小写,用户输小写而验证码含大写字母就会失败;可配置
'codeSet' => '0123456789'强制纯数字,或校验时统一转小写



















