验证码图片跨域显示空白或404,根本原因是captcha.php未设置Access-Control-Allow-Origin等CORS头,且GD未启用、BOM干扰或Session域名不匹配;需在脚本开头添加指定域名的CORS头、统一session_set_cookie_params作用域,并确保GD启用、无BOM及额外输出。

验证码图片在跨域环境下显示为空白或 404,根本原因不是字母本身的问题,而是 PHP 生成验证码的脚本(如 captcha.php)被浏览器拦截——因为它的响应头缺失或不兼容跨域规则,导致 <img src="http://api.example.com/captcha.php" alt="PHP验证码字母跨域显示修复" > 这类跨域图片请求被拒绝。
为什么 <img alt="PHP验证码字母跨域显示修复" > 也会触发跨域限制?
很多人误以为只有 fetch 或 XMLHttpRequest 才受同源策略约束,其实不然:<img alt="PHP验证码字母跨域显示修复" > 标签发起的资源请求虽不暴露响应体,但若目标 URL 涉及跨域且服务端未声明合法来源,现代浏览器(尤其是 Chrome 95+)会静默失败并报 CORS 错误(控制台可见 “CORS policy: No 'Access-Control-Allow-Origin' header”)。这直接导致验证码图片加载中断。
- PHP 脚本输出图片时(如
header('Content-type: image/png')),必须同时输出Access-Control-Allow-Origin头,否则浏览器拒绝渲染 - 该头不能只写在 API 接口里,而要写在
captcha.php这类静态资源生成脚本的最顶部 - 如果前端用了
credentials: 'include'或后端设置了session_start(),则Access-Control-Allow-Origin: *与Access-Control-Allow-Credentials: true不能共存——必须指定具体域名
captcha.php 必须加的三行 header
在验证码生成脚本开头(任何输出前,包括空格、BOM、echo),插入以下三行:
header('Access-Control-Allow-Origin: https://your-frontend-domain.com');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
- 第一行必须是具体协议+域名(如
https://admin.example.com),不可用*;否则配合 Session 会失效 - 第二行允许
GET(图片加载)和OPTIONS(预检,某些 CDN 或代理会触发) - 第三行可省略,但加上更稳妥;若脚本不读取请求头,可删
- 无需加
Access-Control-Allow-Credentials: true——<img alt="PHP验证码字母跨域显示修复" >不发送 Cookie,Session 依赖的是 PHPSESSID Cookie 自动携带,与该头无关
Session 跨域读取失败的典型表现与修复
验证码能显示,但提交时提示“验证码错误”,大概率是前端请求验证接口(如 /login)和 captcha.php 的 Session ID 不一致。常见于:
立即学习“PHP免费学习笔记(深入)”;
- 前后端域名不同(如前端
https://web.example.com,后端https://api.example.com),但 PHP 默认把 Session Cookie 绑定到生成页的域名 - 没调用
session_set_cookie_params()统一作用域
修复方式:在 captcha.php 和验证逻辑文件(如 check_login.php)开头都加入:
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '.example.com', // 注意开头的点,覆盖所有子域
'secure' => true,
'httponly' => true,
]);
session_start();
-
domain必须以.开头(如.example.com),才能让web和api子域共享同一 Cookie -
secure设为true时,HTTP 协议下 Session 将完全失效——确保你用的是 HTTPS - 两处脚本都必须执行这套流程,缺一不可
GD 库启用与输出干扰是最隐蔽的坑
验证码图片显示为乱码、红叉或空白,80% 是因为:
- GD 扩展未启用(
phpinfo()查gd模块是否 loaded) - 脚本开头有 UTF-8 BOM(如编辑器保存带签名),导致
header()报 “headers already sent” - 生成图片后多了一行
echo、var_dump或调试语句,破坏了二进制流
快速自检命令(Linux):
php -m | grep gd xxd -l 10 captcha.php | grep -i "ef bb bf"
- 第一行确认 GD 启用;若无输出,需安装
php-gd并重启 Web 服务 - 第二行检查 BOM:若有
ef bb bf输出,说明文件含 BOM,用 VS Code 或 Notepad++ 转为 “UTF-8 无 BOM” 编码 - 生成图片后,绝对不要有任何
echo、print、var_dump,连空行都不能有
真正卡住人的往往不是字母识别逻辑,而是跨域图片加载链路上的任意一环断掉:header 缺失、Session 域名不匹配、GD 未启用、BOM 干扰输出。逐项排除比重写验证码逻辑更有效。



















