thinkphp6默认验证码防识别效果差,实测ocr识别率达70%–90%;需禁用usenoise/usecurve,改用手动gd绘制:斜线干扰、单像素随机噪点、ttf字体差异化旋转与偏移,可将识别率压至15%以下。

ThinkPHP6内置的验证码图像防识别能力有限,不是靠“开了干扰线或噪点”就自动变安全,关键在于干扰是否真正有效、是否与字符形成合理对抗。实测发现:默认配置下,OCR工具(如Tesseract 4.1+)对标准长度4–5位、fontSize=20–25的验证码识别率普遍达70%–90%,尤其在useNoise=true + useCurve=true组合下,识别率反而更高——因为噪点糊字、曲线断裂,导致人眼也难读,但OCR预处理后更易提取轮廓。
干扰线的真实效果取决于绘制逻辑
ThinkPHP6的useCurve使用固定正弦函数路径,振幅、周期、偏移量均随机但范围窄(如A仅取1–imageH/2),在常规尺寸(120×40)下易生成短而直的线段,甚至只画出1–2个像素点,起不到遮挡作用。更严重的是,其曲线绘制依赖imagestring打点,未做抗锯齿,高DPI设备上常出现断线或粗细不均,既削弱干扰,又降低可读性。
- 真正有效的干扰线应覆盖字符主干区域,建议手动用imageline()绘制3–5条斜向细线(宽度1px,颜色灰度≥180),起点终点均在画布边缘
- 避免曲线穿过字符中心;若必须用正弦干扰,需扩大ω取值范围、增加采样密度,并改用imagesetpixel逐点绘制
- 禁用useCurve时,字符轮廓清晰,但单纯靠字体间距和旋转已不足以抵抗基础OCR
噪点不是越多越好,而是要“错位分布”
useNoise=true默认在字符周围撒10个随机字符(来自codeSet),每个以font=5渲染,实际表现为几个模糊小块。这类噪点集中在字符投影区,容易被OCR的连通域分析直接剔除,甚至成为辅助定位字符边界的线索。
- 有效噪点应为单像素点(imagesetpixel),数量控制在40–80个,坐标完全随机(x∈[0, imageW), y∈[0, imageH)),避开字符主区域±5px缓冲带
- 噪点颜色推荐rgb(192, 192, 192)至rgb(220, 220, 220),比背景略深但远浅于文字色,避免形成新视觉焦点
- 禁用useNoise后手动加噪,比开启默认选项识别率平均低25%以上
字体与变形才是识别瓶颈的关键变量
GD驱动下,ThinkPHP6不支持字符扭曲(distort)、黏连(join)或非线性拉伸。它仅提供±5°左右的微旋转,且所有字符统一角度,OCR通过Hough变换极易校正。而真实难识别的验证码,核心是破坏字符独立性——比如让“P”和“E”下半部分轻微重叠,或对单字符做纵向压缩+横向拉伸。
- 优先启用TTF字体(设置'fontttf' => 'path/to/font.ttf'),配合imagettftext的angle参数实现差异化旋转(每位±8°~±12°)
- 禁用默认字体后,手动逐字符绘制,加入x方向±2px、y方向±1px偏移,打破网格对齐感
- 避免使用等宽字体;无衬线体(如Helvetica、DejaVuSans)比宋体类更难被模板匹配
绕过Captcha类才能获得实质防护能力
只要停留在Captcha::create()或$cap->entry()层面,就只能调参,无法突破GD绘图模型限制。实测中,将验证码生成完全下沉到GD原生操作(imagecreatetruecolor → 手动填色 → imagettftext逐字 → imageline画线 → imagesetpixel撒点),并关闭所有内置干扰开关,识别率可压至15%以下。
- 自定义绘制时,图像尺寸建议≥130×50,fontSize≥22,length固定为4(5位以上反而因拥挤提升OCR置信度)
- 务必关闭useNoise和useCurve,它们与手动绘制逻辑冲突,易引发GD资源错误或图像错位
- Session校验必须同步改写:生成时存$_SESSION['verify_code'] = strtolower($code),验证时严格比对,且一次有效
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











