默认区分大小写导致用户输入abc2或abc2失败,因gd存入$_session['captcha']的原始值与===严格比对要求完全一致;thinkphp的captcha_check()默认用===,需传true启用严格模式或手动原样比对。

captcha_check() 默认区分大小写,strcasecmp() 是最直接的忽略大小写比对方式,但你若明确需要「区分」大小写验证,就得绕开所有自动转义逻辑,用严格比较。
为什么默认区分大小写会出问题
用户看到验证码图片上是 AbC2,但输入 abc2 或 ABC2 就失败——这不是 bug,是 PHP 字符串默认行为。GD 生成时存进 $_SESSION['captcha'] 的原始值是什么样,就什么样;=== 比较时一个字母大小写不同就返回 false。
- ThinkPHP 的
captcha_check($input)内部用的是===直接比对,不自动转大小写 - 原生 GD 实现中,如果你自己写校验逻辑,比如
$_SESSION['captcha'] === $user_input,同样严格 - 常见误操作:调用
strtolower()后再比,结果反而变成“不区分”了
强制区分大小写的校验写法
核心就一条:不做任何标准化处理,原样比对。但得确保两边都没被意外修改。
- 读取用户输入时别用
trim()+strtoupper()这类组合,只做必要清理:$input = $_POST['captcha'] ?? '' - 从 Session 读值时确认没被其他逻辑覆盖或转换:
$server_code = $_SESSION['captcha'] ?? '' - 直接用
===:if ($server_code !== '' && $server_code === $input) { /* 通过 */ } - 如果用了 ThinkPHP,禁用它的大小写兼容层:
captcha_check($input, true)第二个参数为true表示启用严格模式(部分版本支持,需查文档)
GD 手写验证码生成时如何控制大小写敏感源
生成环节决定后续是否“天然区分”。如果你希望验证码本身只含大写或只含小写,就从字符池下手,而不是靠比对时控制。
- 要完全区分大小写 → 字符池必须同时包含大小写字母,例如:
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - 若只想让 A-Z 和 a-z 都可能出现,且用户必须输对大小写,就不要在生成后调用
strtoupper()存入 Session - 避免用
mb_strtoupper()或mb_strtolower()处理原始码——它们可能因编码问题截断中文字符,但更关键的是:它们破坏了大小写信息 - 调试时可临时加日志:
error_log("CAPTCHA STORED: " . $_SESSION['captcha']);,确认存进去的就是你看到的图片内容
容易被忽略的干扰点
你以为在比字符串,其实中间可能混进了不可见字符或编码陷阱。
- 前端表单提交时,某些富文本编辑器或自动补全插件可能插入零宽空格(
\u200B),导致肉眼看起来一样,实际===失败 - GD 图片里用
imagestring()写字时,如果字体不支持某些 Unicode 字符,可能 fallback 到方块,但 Session 里存的仍是原始字符串——这不算大小写问题,但会让“看起来一样却比对失败”更难排查 - PHP 8.5.5 对多字节字符串比较更严格,
strcmp()在非 UTF-8 环境下可能行为异常,此时坚持用===更稳妥
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











