create_captcha() 静默失败的三大主因是:GD库未启用、img_path与img_url路径不匹配或不可写、验证码过期逻辑未通过session或数据库控制,导致前端空白且验证失效。

create_captcha() 不是“调用就出图”的函数——它在 GD 库缺失、img_path 不可写、或 img_url 无法映射到该路径时,会静默返回空数组,前端只看到一个空白 <img alt="CodeIgniter如何实现图片验证码_CodeIgniter防止机器人攻击【防御】" > 标签。
GD 库未启用导致 create_captcha() 静默失败
CodeIgniter 的图片验证码完全依赖 PHP 的 GD 扩展生成 PNG 文件。如果服务器没装 GD,或 Docker 镜像(如 php:8.2-cli)默认未启用,create_captcha() 就不会报错,而是返回 ['image' => '', 'word' => '']。
- 验证方法:在控制器里加一行
var_dump(extension_loaded('gd'));,输出false就确认缺失 - Docker 用户需安装
libgd-dev和php-gd,并重启 PHP-FPM 或容器 - 开发环境用
phpinfo()搜索 “gd” 是最快确认方式 - 不依赖图像的备用方案:用
rand(1000,9999)生成纯数字,存入 session,跳过create_captcha(),但失去防自动化能力
img_path 和 img_url 必须严格匹配且可访问
这两个参数不是“可选配置”,而是硬性前提。哪怕你只打算用 word 做 session 验证,create_captcha() 内部仍会尝试写入图片文件;路径不合法,图片就永远加载不出来。
-
img_path必须是 Web 服务器进程可写的绝对路径(如'./captcha/'),目录要手动创建,权限设为755或777 -
img_url必须是浏览器能直接请求的 URL(如base_url().'captcha/'),且必须与img_path映射一致——常见错误是写成'application/captcha/',这个路径在 Web 根目录外,HTTP 请求 404 - 检查方式:在浏览器地址栏直接访问
http://yoursite.com/captcha/xxx.png,看是否能下载图片 - 不要用相对 URL 如
'./captcha/'作为img_url,它会被当作文本拼接进<img src alt="CodeIgniter如何实现图片验证码_CodeIgniter防止机器人攻击【防御】" >,导致路径错乱
验证码过期与重复提交必须靠数据库或 session 主动控制
expiration 参数只控制图片文件在 img_path 目录里保留多久(单位秒),并不影响验证逻辑本身。用户提交旧验证码、或反复刷新重放同一组 word,框架不会自动拦截。
- 推荐做法:把
$cap['word']+$this->input->ip_address()+time()存进数据库表captcha,带captcha_time字段 - 验证时查库:只接受
captcha_time > time() - 300(5 分钟内)且未被使用过的记录 - session 方案更轻量:用
$this->session->set_tempdata('captcha_word', $cap['word'], 300),避免 DB 查询,但无法按 IP 限频 - 注意:CI3 默认不自动清理过期图片,得自己写脚本或用
system/helpers/captcha_helper.php里的delete_expired_captchas()函数定期调用
中文验证码需要自定义类,原生 create_captcha() 不支持
官方 create_captcha() 只支持英文、数字和 GD 默认字体,传入中文字符串会显示方块或乱码,即使指定了 font_path 也大概率失效——因为 GD 对中文字体渲染支持极弱,且不处理 UTF-8 编码。
- 绕过方式:改用纯文本 + session 验证,前端用 CSS 遮罩+旋转模拟“图像感”,后端只比对 session 中的汉字字符串
- 硬核方案:自己写一个继承
CI_Image_lib的类,用 imagettftext() 手动绘制,指定支持 Unicode 的 TTF(如 Noto Sans CJK),并确保服务器有该字体文件 - 更现实的选择:换用第三方库(如
gregwar/captcha),它原生支持中文、SVG 输出、无 GD 依赖,只需 Composer 加载即可集成
真正卡住人的从来不是“怎么写出来”,而是 GD 是否启用、路径是否真能写入、过期逻辑有没有落在数据库或 tempdata 上——这三个点漏掉任何一个,验证码就只是个摆设。


















