不能把 config 目录留在 public 下,否则配置文件可能被直接下载导致数据库密码泄露;必须将其移至 web 根目录外,并通过 define('config_path', ...) 和 app()->config->setpath() 指定新路径。

为什么不能把 config 目录留在 public 下
ThinkPHP 默认的 config 目录在 app/config,但很多新手会误把整个 app 放进 public,或直接把 config 暴露在 Web 可访问路径下。一旦发生,.php 文件没被正确解析(比如服务器配置异常),攻击者就能直接下载 database.php、cache.php,数据库账号密码全泄露。
核心问题不是“能不能移”,而是“不移就等于裸奔”。Web 服务器只该暴露 public 下的入口文件,其余所有源码、配置、运行时目录必须在 Web 根目录之外。
怎么改 App::getInstance() 的配置加载路径
ThinkPHP 6+ 使用 think\App 类启动,配置由 think\Config 加载,默认从 app/config 读取。要移出 Web 目录,关键不是改文件位置,而是改加载逻辑——让框架知道新路径在哪。
- 把原
app/config整个移到 Web 根目录外,比如和public同级的config目录 - 在
public/index.php中,在App::getInstance()调用前插入一行:define('CONFIG_PATH', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR); - 然后在
App::getInstance()初始化后,手动重置配置路径:app()->config->setPath(CONFIG_PATH);
- 确保
CONFIG_PATH最终指向的是绝对路径,且 PHP 进程有读取权限;相对路径容易因 CLI/Web 工作目录不同而失效
遇到 Config not found 或空数组怎么办
常见错误现象:页面报错 Config not found: app,或者 Config::get('database') 返回空。本质是路径没生效,或文件权限/命名不匹配。
- 检查
CONFIG_PATH是否真实存在且可读:var_dump(is_readable(CONFIG_PATH)); - 确认新
config目录下仍有app.php、database.php等标准文件,ThinkPHP 不会自动扫描子目录,只认根下的 PHP 配置文件 - 如果用了多环境(如
config/dev),需手动指定:app()->config->setPath(CONFIG_PATH . 'dev' . DIRECTORY_SEPARATOR);
- CLI 命令(如
php think optimize:config)可能仍读旧路径,需同步修改think命令入口脚本中的加载逻辑
移出后要注意 runtime 和 vendor 的连带影响
只动 config 是不够的。runtime 目录也必须移出 Web 目录,否则缓存、日志文件可能被直接访问;vendor 虽然不敏感,但若放在 public 下,Composer 自动加载可能出错。
- 统一规划目录结构,推荐:
/project-root/ ├── config/ ├── runtime/ ├── vendor/ ├── app/ ├── public/ ← Web 根目录,仅放 index.php + static └── think
- 在
public/index.php中同步设置RUNTIME_PATH:define('RUNTIME_PATH', dirname(__DIR__) . '/runtime/'); - 别忘了更新
.env中的APP_DEBUG和LOG_LEVEL,它们会影响 runtime 下的日志行为,但本身不决定路径
路径挪得再干净,只要 public/index.php 里漏掉一个 define,或服务器 open_basedir 限制没同步调整,就白忙一场。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










