控制器必须定义public actions()方法返回配置数组,如'captcha'=>['class'=>'yii\captcha\CaptchaAction'],而非actionCaptcha();验证码校验规则中'captcha'须紧随'required'之后;API场景需改用Redis等替代session存储验证码。

控制器里必须定义 actions() 方法,不能写成 actionCaptcha()
Yii 的验证码不是靠单独一个 action 方法提供图片,而是通过 actions() 这个特殊方法注册一个「动作工厂」。它返回的是一个配置数组,其中 'captcha' 是路由别名,'class' => 'yii\captcha\CaptchaAction' 才是真正干活的类。
常见错误是误写成 actionCaptcha(),结果访问 /site/captcha 时 404;或者漏掉 actions(),导致整个验证码流程断在第一步。
-
actions()必须是 public 方法,返回关联数组,键名(如'captcha')会变成 URL 路径段 - 如果控制器在模块下(比如
admin/login),默认路由是/admin/login/captcha,不是/site/captcha -
CaptchaAction类本身不依赖 session 自动初始化,但它的校验逻辑强依赖 session —— 所以确保 PHP session 已启用且未被禁用
rules() 里 'captcha' 规则必须紧跟 'required',顺序不能颠倒
模型验证规则中写 ['verifyCode', 'required'] 和 ['verifyCode', 'captcha'] 看似只是两行,但顺序错就等于没校验。因为 CCaptchaValidator(Yii 1.x)或 CaptchaValidator(Yii 2+)内部会先检查字段是否为空:如果为空且没配 required,它直接跳过比对逻辑,只报“不能为空”;而如果 required 在后,空提交时根本不会走到 captcha 校验那步。
- 必须把
'captcha'放在'required'后面,否则用户输空也能过表单提交,只是卡在非空提示 - 如果模型没继承
CActiveRecord或CFormModel(Yii 1.x),要手动在init()里调parent::init(),否则框架找不到CCaptchaValidator类 - Yii 2+ 中,
'captchaAction'参数必须显式传,尤其是跨模块时,比如['verifyCode', 'captcha', 'captchaAction' => 'admin/login/captcha'],不然默认找site/captcha
视图里用 Captcha::widget(),别直接 echo $this->widget('CCaptcha')
Yii 2+ 废弃了 $this->widget() 这种写法,统一走 Captcha::widget() 静态工厂。传参看着差不多,但底层行为差异大:前者容易忽略命名空间、找不到类;后者能自动绑定 model 和 attribute,也支持 template 自定义布局。
-
template中{image}渲染的是<img src="/site/captcha">,URL 来自captchaAction配置,不是硬编码 - 如果页面有 CSS 覆盖了图片宽高(比如全局设了
img { max-width: 100% }),会导致验证码变形——此时应在imageOptions里加'style' => 'width:80px;height:40px;vertical-align:middle;' - 点击刷新功能默认关闭,要启用得设
'clickableImage' => true并配合 JS 绑定,不能只靠 HTML 属性
验证码值存在 session 里,但 API 场景要换存法
标准 Web 表单走 session 没问题,但如果是前后端分离或纯 API 接口(比如登录接口 /api/login),session 往往不可用或被禁用。这时候 CaptchaAction 默认机制会失效:图片能生成,但后端收不到匹配的 session 值。
- 必须重写
CaptchaAction,把getVerifyCode()和validate()的存储/读取逻辑替换成 Redis 或 Cache 组件 - 常见做法是生成时用 UUID 当 key,存验证码明文(小写)进缓存,有效期设为 120 秒;验证时用前端传来的 UUID 查缓存比对
- 千万别在 API 里强行启用 session —— 不仅破坏无状态原则,还可能因负载均衡、跨域 cookie 丢失导致校验随机失败


















