直接使用topthink/think-captcha扩展包即可,无需手写GD逻辑;需在项目根目录执行composer require topthink/think-captcha安装,确保session开启,验证码生成用Captcha::create()(非entry),校验用Captcha::check(),注意大小写敏感、过期时间及配置覆盖问题。

直接用 topthink/think-captcha 就行,别自己手写 GD 逻辑,除非你真要控制每个像素——但绝大多数项目根本不需要那么深的定制。
安装 think-captcha 扩展包必须用 Composer
ThinkPHP 6 默认不带验证码功能,得单独装扩展。命令只有一条:
composer require topthink/think-captcha
注意两点:
- 别在
thinkphp/framework目录下执行,得在项目根目录(即有composer.json的地方) - 如果报错说找不到包,先确认是否已配置国内镜像:
composer config -g repo.packagist https://packagist.phpcomposer.com或改用阿里云源 - 装完后无需手动注册服务提供者——ThinkPHP 6+ 自动发现并加载
think-captcha
生成验证码要用 Captcha::create() 而不是 entry()
很多老教程写 $captcha->entry(),那是 ThinkPHP 5.x 的写法,TP6 已废弃。现在标准流程是:
立即学习“PHP免费学习笔记(深入)”;
- 控制器里调用
Captcha::create(),它会自动输出图片并把验证码值存进 session - 返回值是
Response对象,不能直接 return 字符串或数组,否则图片无法渲染 - 路由必须是独立接口,比如
/captcha,不能塞在页面渲染逻辑里(否则响应头冲突)
示例代码:
use think\captcha\Captcha;
class IndexController extends Controller
{
public function captcha()
{
return Captcha::create();
}
}
Captcha::check() 校验失败的常见原因
用户输对了还是提示“验证码错误”,八成是下面几个点没对上:
- session 没开启:检查
session_start()是否被禁用,或配置里'type' => 'file'路径不可写 - 大小写敏感:默认
codeSet包含大小写字母,但前端输入框没限制 type="text",用户可能输成全大写,而服务端比对是严格匹配的 - 过期时间不一致:
expire配置单位是秒,设成60表示 1 分钟,但用户拖太久再提交就失效;别设成 0 或负数,那等于立刻过期 - 多次调用
create():每次调用都会覆盖 session 里的旧值,如果页面加载时触发一次、用户点击刷新又触发一次,第一次的验证码就作废了
自定义配置别只改 config/captcha.php 就完事
配置文件生效的前提是:你没在代码里传入新配置覆盖它。比如:
- 如果写了
Captcha::create(['length' => 6]),那config/captcha.php里的'length' => 4就被无视了 -
useNoise和useCurve开关要一起开才有明显效果,单开一个干扰太弱,OCR 工具几行 Python 就能绕过 - 字体文件路径要绝对可靠:如果指定
'fontttf' => './public/fonts/1.ttf',得确保该路径在 CLI 和 Web 环境下都可读,否则图像生成失败但无报错,只返回空白图 - 别把
imageW/imageH设得太小(如80x30),移动端点击区域太小,用户容易误点刷新
真正容易被忽略的是:验证码图像生成后,session 中存的是明文(比如 "aB3x"),不是 hash。这意味着只要 session 被窃取,验证码就等于白设——所以别在公共 WiFi 下做高敏操作,这不是框架能解决的问题。



















