captchabuilder->getphrase()调用一次即清空缓存是设计使然,非bug;必须在build()后立刻取值存入session,否则答案丢失。

Webman 中验证码“生成即失效”是默认行为,不是 bug —— CaptchaBuilder->getPhrase() 只能调用一次,不立刻存 session 就等于丢答案。
为什么 CaptchaBuilder->getPhrase() 调一次就变空?
Gregwar/Captcha 的 CaptchaBuilder 内部用 uniqid() + 随机 salt 生成 phrase 后,会立即清空缓存。第二次调用 getPhrase() 返回空字符串,不是 session 问题,是对象设计如此。
- 必须在
$builder->build()后**立刻**取值并写入 session:$request->session()->set('captcha', strtolower($builder->getPhrase())) - 绝不能在登录校验逻辑里再调
getPhrase()—— 此时 phrase 已销毁 - 如果用了多 worker(如 reload 模式),
file驱动的 session 会因进程隔离导致取不到值,必须切到redis驱动
/login/captcha 接口返回乱码或空白图片?
GD 图像输出对响应体零容忍:任何 warning、notice、echo、空格、BOM 或额外 header 都会让浏览器解析失败,显示为乱码或下载对话框。
- 确认控制器方法里没
echo/var_dump/print_r等调试输出 - 关掉 PHP 错误显示:
ini_set('display_errors', 'Off'),避免错误信息混进二进制流 - 强制指定响应头:
['Content-Type' => 'image/png'](别用 jpeg,GD 默认可能输出 png,格式不一致会导致部分浏览器拒绝渲染) - 用 curl 直接测原始响应:
curl -v http://127.0.0.1:8787/login/captcha | head -c 10,开头应为‰PNG;如果不是,说明有前置输出
刷新验证码后,旧值还能通过校验?
Webman 的 CaptchaBuilder 不自动管理生命周期,“刷新”只是生成新图,但旧 session 值还在,用户输旧码仍能比对成功 —— 这是典型的设计遗漏。
- 刷新接口(如
GET /login/captcha/refresh)中,必须先删旧值:$request->session()->delete('captcha') - 生成新图后,立刻 set 新值,顺序不能颠倒
- 若页面支持多个表单(如注册+登录共用一个页面),不要复用固定 key
'captcha',改用带随机后缀的 key,例如'captcha_'.uniqid() - 校验成功后,**立即** delete session 中的 captcha key,防止重放
多 worker 下 session 失效或取不到值?
Webman 默认基于 PHP 内置 session,但在 reload 模式或多进程常驻场景下,php session_start() 无法跨 worker 共享文件锁或内存状态,导致验证码存了却取不到。
- 必须切换 session 驱动:在
config/session.php中设'handler' => 'redis',并确保 Redis 连接正常 - 检查
session.gc_maxlifetime是否过短(建议设为 300 秒),否则验证码未输入就过期 - 别依赖
$_SESSION全局变量 —— Webman 的$request->session()是封装层,它在 redis 驱动下才真正可靠 - 上线前务必用 ab 或 wrk 压测并发刷新+提交,验证 session 一致性
最易被忽略的是:验证码不是“生成完就结束”,它的生命周期完全绑定在 session 存取时机和存储介质上;哪怕 GD 图像画得再复杂,session 断了,整个流程就崩了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











