ThinkPHP应用目录不能全设755,因需写入的仅cache/、log/、runtime/子目录,其余应只读;runtime移至public外更安全,需绝对路径配置并设好属组与权限。

ThinkPHP 应用目录为什么不能全给 755?
生产环境里把 application/ 目录设成 755,等于默认允许 Web 服务器进程(如 www-data、nginx)读+执行——但 ThinkPHP 运行时会往 application/cache/、application/log/ 写文件,如果目录不可写,缓存失效、日志丢弃,错误却静默;可如果整个 application/ 都可写,攻击者上传恶意配置或覆盖路由定义就只差一个未过滤的文件参数。
真正要放开写的,只有明确需要运行时写入的子目录:
-
application/cache/:必须可写(755或775,取决于组权限) -
application/log/:必须可写 -
application/runtime/:ThinkPHP 6+ 默认 runtime 目录独立于 application,但若自定义到 application 下,也得可写 - 其余目录(
application/common/、application/controller/等)应设为755且属主为部署用户,Web 进程仅读取,不拥有写权限
runtime 目录放在 public 外面更安全吗?
是的,而且这是 ThinkPHP 官方推荐做法。默认 runtime/ 在 public/ 同级,但只要没做 Web 路径隔离,直接访问 https://yoursite.com/runtime/ 就可能列出缓存文件甚至泄露调试信息。更稳妥的是把它移到项目根目录外(比如和 think 命令同级),然后在 config/app.php 里显式指定:
'runtime_path' => dirname(__DIR__) . '/storage/runtime/',
注意两点:
立即学习“PHP免费学习笔记(深入)”;
- 路径必须是绝对路径,相对路径在 CLI 和 Web 环境下行为不一致
-
storage/目录需手动创建,并确保 Web 进程对其有写权限(chown -R www-data:www-data storage/) - 别忘了把
storage/加进.gitignore,否则缓存文件会被误提交
Linux 下 chmod + chown 组合操作容易漏哪步?
常见错误是只改权限,不改归属。比如执行 chmod -R 755 application/ 后,Web 进程仍可能因属主不是自己而无法写入 cache 目录——尤其当部署用 git 拉取代码,属主是 deploy 用户,而 nginx 运行在 www-data 组里。
正确流程是分两步走:
- 先统一属组:
chgrp -R www-data application/cache application/log application/runtime - 再开组写权限:
chmod -R g+w application/cache application/log application/runtime - 确认父目录有执行权限(否则无法进入):
chmod 755 application/,不要775—— 组可写意味着所有同组用户都能改代码
顺带一提:setgid 位可以避免新创建文件继承错组,对 cache/ 这类目录加一下:chmod g+s application/cache
Windows IIS 或宝塔面板上怎么对应处理?
Windows 没有 chmod,靠“属性 → 安全 → 编辑”配 ACL;宝塔则藏在网站根目录的“权限设置”页。但核心逻辑不变:Web 服务账户(IIS_IUSRS 或宝塔里的 www 用户)只需要对特定子目录有“修改”权限,其它目录给“读取与执行”足矣。
特别注意宝塔的坑:
- 它默认勾选“递归设置子目录”,一旦对
application/设了“可写”,所有子目录全被放开,包括controller/ - 务必取消勾选,手动逐个点开
cache/、log/单独设权限 - IIS 下若启用“静态内容压缩”,还要确认
runtime/不在被压缩路径里,否则可能暴露.php缓存文件头
权限这事没有银弹,每次上线前用 ls -l application/ 快扫一眼,比等报错再查快得多。



















