根本原因是Linux文件系统严格区分大小写,而ThinkPHP8模板路径匹配不作大小写归一化;必须确保控制器目录、视图目录、模板文件名全部小写,且{include}/{extend}路径大小写精准匹配。

ThinkPHP8项目在Windows开发时一切正常,一上Linux服务器就报“模板不存在”,文件明明上传了却死活找不到,根本原因在于Linux文件系统严格区分大小写,而ThinkPHP的模板路径匹配机制会原样拼接、不作大小写归一化。
确认模板路径是否全小写
打开你的控制器方法,例如 app/index/controller/Index.php 中的 index() 方法;它默认会去匹配 app/index/view/index/index.html —— 注意这个路径里所有目录名和文件名都【必须全小写】,包括 index、view、controller 这些目录本身。哪怕你写了 IndexController.php,对应的 view 目录也得是 index,不能是 Index 或 INDEX。
用 ls -l 命令逐级检查:cd app/index/view/ → ls -l → 看到的子目录名是否全为小写?再进 user/ 目录 → ls -l → 看 user.html 是否存在,而不是 User.html 或 USER.HTML。
Windows下你改名成 User.html 也能加载,Linux下直接报错 Template not found。
立即学习“PHP免费学习笔记(深入)”;
修正模板文件名与控制器方法名的映射关系
方法名 getUserInfo() 对应的模板文件名必须是 getuserinfo.html,不是 getUserInfo.html,也不是 getuserinfo.htm。
这一步操作起来很简单,直接把文件重命名就行:mv getUserInfo.html getuserinfo.html。
注意:如果控制器方法用了驼峰,ThinkPHP 8 在 fetch() 时会自动把方法名转为小写再拼路径,所以你不能靠手写大写文件名来“匹配”;【必须让文件名和框架生成的路径完全一致】,也就是全部小写+无扩展名拼接逻辑。
检查 {include} 和 {extend} 的路径写法
方法一:相对路径引用要以当前模板所在目录为起点
比如你在 app/index/view/user/profile.html 里写 {include file="header"},它会去找 app/index/view/user/header.html,不是 app/index/view/header.html。
方法二:跨模块引用必须带 @ 符号且大小写精准
{include file="admin@public/header"} 表示引用 app/admin/view/public/header.html;如果写成 {include file="Admin@Public/header"},Linux 下直接失败——【@ 前后模块名和目录名都必须与实际文件系统大小写完全一致】。
方法三:用绝对路径写法规避相对查找(仅调试用)
{include file="./../public/header.html"} 这种写法绕过模板引擎的路径解析,但破坏可移植性,上线前必须改回标准写法。
验证模板能否被正确加载
第一步:进入项目根目录,执行 php think route:list → 确认路由已注册且无语法错误。
第二步:临时在控制器中硬编码 fetch 路径:return $this->fetch('index/index'); → 如果仍报错,说明路径字符串和磁盘文件名不匹配。
第三步:在命令行手动测试文件是否存在:php -r "var_dump(file_exists('app/index/view/index/index.html'));" → 输出 bool(true) 才算过关。
只要 file_exists() 返回 false,就别查语法或配置,直接去改文件名和目录名。



















