验证码总显示旧字母的根本原因是Session未失效、浏览器缓存响应或GD资源未释放。需在生成新码前unset对应SESSION键,设置Cache-Control禁止缓存,并调用imagedestroy()释放图像资源。

PHP验证码字母缓存清除,本质不是清“字母”,而是清掉它所依赖的存储载体——Session、GD图像缓存或浏览器对 captcha.php 的响应缓存。直接删字符没用,关键得断掉生成、传输、比对三环节中任一环节的旧状态。
为什么验证码总显示旧字母?
常见现象:刷新图片后文字不变、换浏览器仍显示同一串字母、改了生成逻辑但前端还是老码。根本原因不是代码没更新,而是:
- Session 未失效或未覆盖:
$_SESSION['captcha']还在,session_start()后直接读取旧值 - 浏览器缓存了
captcha.php的 PNG 响应(尤其没设Cache-Control) - GD 库内部可能复用资源(如未调用
imagedestroy()),极少数情况下影响下一次输出
清除 Session 中的验证码字母
不能只 unset($_SESSION['captcha']) 就完事——必须确保该操作发生在生成新码之前,且不被条件跳过。
- 在生成新验证码前,先清理旧值:
unset($_SESSION['captcha'], $_SESSION['captcha_time']); - 若用了时间戳过期机制,务必同步删掉
$_SESSION['captcha_time'],否则下次验证会因时间差误判超时 - 避免在生成脚本里写
session_destroy(),它会清空整个会话,导致登录态丢失 - 测试时可加一句
var_dump($_SESSION);确认键已消失,再刷新看是否真生成新字母
强制浏览器不缓存验证码图片
captcha.php 输出的是 PNG 图像,但默认 HTTP 头可能允许缓存,导致你点刷新,浏览器直接从内存返回旧图。
立即学习“PHP免费学习笔记(深入)”;
- 在
captcha.php开头、header('Content-Type: image/png')之前,加上这两行:header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');header('Expires: Thu, 01 Jan 1970 00:00:01 GMT'); - HTML 中引用时,给
<img>加时间戳参数防缓存:<img src="captcha.php?<?php echo time(); ?>"> - 不要依赖 JS 的
Math.random()拼 URL,某些 IE/Edge 会忽略 query 参数变化,time()更稳
GD 图像资源未释放导致字母残留?
极少见,但真实存在:多次快速请求 captcha.php 时,若前次 $image 未销毁,GD 可能复用画布内存,使新字符叠加在旧图上,看起来像“字母没变”。
- 每张图生成后必须调用
imagedestroy($image),且只能调用一次 - 别在循环里重复
imagecreate()却忘了imagedestroy(),尤其加了干扰线/点之后 - 如果用了
imagefttext()加字体,确认.ttf文件路径正确,路径错会导致图像创建失败,但 PHP 不报错,只输出空白或默认字符
真正难排查的,是 Session 和浏览器缓存双重生效:你以为清了 Session,其实浏览器还在用上周的图片;你以为加了时间戳,结果 CDN 把 query 参数过滤了。动手前先开开发者工具 Network 面板,看 captcha.php 的响应状态码和 Response Headers,那里才藏了真相。



















