必须在控制器的actions()方法中注册CCaptchaAction,返回包含'captcha'键的数组,class值严格为'CCaptchaAction',并配置backColor和foreColor;视图中用$this->widget('CCaptcha')渲染,表单name须为'verifyCode';模型rules中需按顺序添加'required'和'captcha'规则;验证码不匹配多因session异常、GD库或cookie问题。

CCaptchaAction 怎么在控制器里注册
Yii 1.x 中 CCaptchaAction 不是直接 new 出来调用的,必须通过控制器的 actions() 方法声明——漏掉这步,访问 /site/captcha 就会 404 或抛出 “Invalid action ID” 错误。
- 在控制器类中重写
actions()方法,返回含'captcha'键的数组 -
class值必须是'CCaptchaAction'(注意大小写,写成ccaptchaaction或CaptchaAction都会失败) - 建议显式配置
'backColor'和'foreColor',否则某些服务器 GD 库默认背景为黑色,文字看不见
public function actions()
{
return array(
'captcha' => array(
'class' => 'CCaptchaAction',
'backColor' => 0xFFFFFF,
'foreColor' => 0x333333,
),
);
}
视图里怎么渲染验证码图片和输入框
不能手写 <img src="/site/captcha"> 硬编码路径,得用 Yii 内置的 $this->widget(),否则 session 验证对不上——常见现象是图片能刷、输入正确却总提示“验证码错误”,本质是 widget 自动管理了 captcha/refresh 和 hidden field 的 yt0 参数。
- 用
Captchawidget 渲染图片和刷新按钮,它会自动输出<input type="hidden" name="YII_CSRF_TOKEN" ...>类似逻辑(实际是 captcha hash) - 表单里对应文本框的
name必须是'verifyCode'(除非你在 action 配置里改了'name'参数) - 如果页面有多个表单,确保每个验证码 widget 的
'id'不重复,否则 JS 刷新逻辑会串
$this->widget('CCaptcha', array(
'buttonOptions' => array('class' => 'btn'),
'imageOptions' => array('alt' => '点击换图'),
));
表单提交时怎么验证验证码
验证不是靠自己写 if 判断,而是把 verifyCode 字段加进模型规则,并触发 CRequiredValidator + CCaptchaValidator ——漏掉后者,就只校验非空,不校验值是否匹配 session 里的答案。
- 在模型的
rules()里加:array('verifyCode', 'required')和array('verifyCode', 'captcha') - 注意顺序:
'captcha'规则必须放在'required'后面,否则空提交时跳过 captcha 校验,直接报“不能为空” - 如果模型没继承
CFormModel或CActiveRecord,要手动在init()里调用parent::init(),否则 validator 找不到CCaptchaValidator
为什么本地能用,上线后验证码总不匹配
最常见原因是 session 存储异常或跨域 cookie 丢失,而不是代码写错了。典型表现:图片能刷新、输入框有值、服务端日志显示 CCaptchaAction::getVerifyCode() 返回空字符串。
- 检查
session.save_path是否可写(尤其 shared hosting),ini_get('session.save_path')能看到真实路径 - 确认 PHP 的
session.use_cookies是 on,且没被 Nginx/Apache 的secure或httponly策略拦截(比如 HTTPS 站点却发了 http-only=off 的 cookie) - 如果用了 CDN 或反向代理,确认没缓存
/site/captcha这个 URL(必须禁用缓存) -
CCaptchaAction默认用session_id()当 key 存验证码,如果某处调用了session_regenerate_id(),旧 session 里的验证码就丢了
验证码逻辑本身很薄,但卡在环境链路上的问题最多——session、GD、URL 路由、cookie 三者只要一个断,就表现为“输对了也错”。










