核心问题是二级域名间Session未共享:Cookie域未设为顶级域(如'.example.com'),导致验证码生成与校验时Session断链;需统一domain配置、确保GD启用、清理输出缓冲、使用绝对字体路径并验证session_id一致性。

ThinkPHP配置二级域名后验证码不显示,核心问题不是路由或跨域本身,而是 Session 在多域名场景下无法共享或写入失败。二级域名(如 admin.example.com 和 user.example.com)默认属于不同 Cookie 作用域,导致验证码生成时存的 Session 值,验证时根本读不到——看起来是“图片空白”或“始终提示错误”,实则是 Session 断链。
Session Cookie 域名范围未统一
验证码依赖 Session 存储真实字符(如 8Km2),而 ThinkPHP 默认用 PHP 原生 Session,其 Cookie 的 domain 属性若未显式设为顶级域(.example.com),各二级域名间 Session 就互不可见。
- 在 config/session.php 中确认已设置:
'domain' => '.example.com',(注意开头的点) - 避免写成 'domain' => 'admin.example.com' 或留空,否则 Session 只绑定当前子域
- 同时检查 'use_cookies' => true 和 'type' => 'file'(或其他驱动)是否启用
Session 存储路径权限与隔离问题
多个二级域名共用同一套后端时,若 Session 文件驱动(file)的 save_path 目录被不同用户或权限隔离,可能导致写入失败或读取混乱。
- 检查 runtime/session 目录是否存在,且 Web 进程用户(如 www-data 或 nginx)有读写权限:
chmod -R 755 runtime/session - 若使用 Redis/Memcached 等共享存储,确保所有二级域名指向同一实例,且连接配置一致
- 临时加一行调试代码:
dump(session_id(), session_status(), ini_get('session.save_path'));
确认每次访问生成的 session_id 是否相同、状态是否为 PHP_SESSION_ACTIVE
GD 扩展与输出缓冲在子域环境下更易触发异常
二级域名常伴随独立 Nginx 配置或 Docker 容器,GD 库可能未启用,或入口文件/配置文件存在隐藏 BOM、空格,导致图像流被污染——这种问题在单域名下可能侥幸通过,一上多子域就暴露。
立即学习“PHP免费学习笔记(深入)”;
- 执行 php -m | grep gd,无输出则需启用 GD(尤其 Docker 镜像常默认不装)
- 用 Notepad++ 或 VS Code 检查 public/index.php 及所有 include 的配置文件:编码必须为 UTF-8 without BOM
- 在验证码方法开头强制清理输出缓冲:
ob_clean();
再调用 Captcha::create() 或 $cap->entry()
字体文件路径在子域部署中容易失效
TP6/TP8 默认字体路径(如 vendor/topthink/think-captcha/src/assets/simhei.ttf)在某些二级域名部署结构中可能因相对路径解析错位或中文路径编码问题失效,导致图像生成为空白背景。
- 改用绝对路径并显式指定字体:
'font' => public_path('static/font/DejaVuSans.ttf') - 下载 DejaVuSans.ttf 放入 public/static/font/,确保 Web 用户可读:
chmod 644 public/static/font/*.ttf - 禁用中文路径、空格路径;Windows 下若必须用 simhei.ttf,需 GBK 编码转换后再传入



















