图形验证码必须在$builder->build()后立刻调用getphrase()并存入session,否则因gregwar/captcha设计机制清空缓存而返回空;多表单需用随机key,多worker须切redis驱动。

图形验证码必须立刻存 session,否则 getPhrase() 返回空
Webman 中用 CaptchaBuilder 生成图形验证码时,getPhrase() 只能调一次——这是 Gregwar/Captcha 的设计机制,不是 bug。调完就清空内部缓存,第二次再调返回空字符串。
常见错误是:在 $builder->build() 后没立刻取值,而是等到登录校验时才调 getPhrase(),结果比对永远失败。
-
$builder->build()后必须紧跟着$request->session()->set('captcha', strtolower($builder->getPhrase())) - 不能复用固定 key(如
'captcha')支持多表单,应改用带随机后缀的 key,例如'captcha_'.uniqid() - 多 worker 进程下,file 驱动的 session 会因进程隔离失效,必须切到
redis驱动
短信验证码必须走 Cache::put,键名和过期时间要显式控制
图形码依赖 session 单次性,短信码必须走缓存,两者生命周期、存储路径、失效逻辑完全不同,混用必出问题。
发码成功但校验总失败?90% 是缓存键名不一致:存的是 sms:138xxxx,取的时候却用了 phone:138xxxx 或 code_138xxxx。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 发码前先限流:
if (Cache::has('sms_sent:'.$phone)) { return response(['msg' => '请稍后再试'], 429); } - 发码成功后写两份缓存:
Cache::put('sms:'.$phone, $code, 300)(校验用)、Cache::put('sms_sent:'.$phone, true, 60)(限流用) - 校验时必须用完全相同的 key:
Cache::get('sms:'.$phone),大小写、冒号、前缀一个字符都不能差 - 别用数据库存待验证短信码——高并发下容易锁表,缓存更轻量也更准
/login/captcha 接口返回乱码?GD 对响应体零容忍
浏览器显示空白或触发下载,不是前端问题,而是响应体被污染了。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;不是就说明有前置输出
刷新验证码后旧值仍能通过校验?session 没删干净
Webman 的 CaptchaBuilder 不自带自动失效机制。“刷新”只是生成新图,但旧 session 值还在,用户输旧码仍能比对成功——这不是 bug,是漏掉了清理动作。
- 刷新接口(如 GET
/login/captcha/refresh)中,必须先删旧值:$request->session()->delete('captcha') - 生成新图后立刻 set 新值,顺序不能颠倒
- 校验成功后,**立即**
$request->session()->delete('captcha'),防止重放 - 如果页面含多个表单(如注册+登录共用),不要复用固定 key,避免交叉干扰
关键点其实就两个:图形码靠 session 单次覆盖保安全,短信码靠 cache 键名与 TTL 精确控制;一旦把它们当“同一种验证码”来处理,session 和缓存的生命周期错位、键名冲突、重放风险就会立刻暴露。










