open_basedir 通过路径白名单限制PHP脚本只能读写指定目录内的文件,必须包含上传目标目录和系统临时目录(如 /tmp/),配置时路径末尾需加斜杠并用英文冒号分隔。

PHP 8.0 配置 open_basedir 来限制上传文件访问,核心不是“专门防上传”,而是通过路径白名单,让脚本**只能读写指定目录内的文件**——包括上传后存到哪里、后续又从哪读取,都必须落在这个范围内。上传功能本身(如 $_FILES)不直接受限,但后续的移动(move_uploaded_file)、读取(file_get_contents)、包含(include)等操作,一旦路径越界就会被拦截。
必须包含上传目标目录和临时目录
PHP 上传流程分两步:先存到系统临时目录(如 /tmp),再由脚本用 move_uploaded_file() 移到业务目录。这两处都得放进 open_basedir,否则会报错:
-
系统临时目录:通常是
/tmp/,部分环境也可能是/var/tmp/或/run/php/php8.0-tmp/,需确认upload_tmp_dir的实际值(查phpinfo()或ini_get('upload_tmp_dir')) -
业务上传目录:比如
/www/wwwroot/example.com/uploads/,要确保该路径存在、可写,且末尾带斜杠 - 若用框架(如 Laravel),上传目录可能在
storage/app/,那就要把整个storage/或storage/app/加进去
配置方式推荐:.user.ini + Nginx 双加固
单站点场景下,不建议改全局 php.ini,优先用 .user.ini 精准控制:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 进入网站根目录(如
/www/wwwroot/example.com/),编辑或新建.user.ini - 写入类似内容:
open_basedir=/www/wwwroot/example.com/:/www/wwwroot/example.com/uploads/:/tmp/:/proc/ - 注意:每段路径末尾必须有
/,多路径用英文冒号:分隔,不能有空格或中文 - 若提示只读,先执行
chattr -i .user.ini解锁,保存后再chattr +i .user.ini锁定 - 在宝塔中点击“重载配置”或重启 PHP 8.0,使设置生效
验证上传相关操作是否真受控
光看配置文件不够,必须实测关键路径是否被拦住:
- 新建一个
test_upload.php,尝试读取/etc/passwd:var_dump(file_get_contents('/etc/passwd'));→ 应报open_basedir restriction错误 - 测试上传后读取自己目录的文件:
var_dump(file_get_contents('/www/wwwroot/example.com/uploads/test.jpg'));→ 应成功 - 调用
ini_get('open_basedir'),输出应为非空字符串,且与你配置一致 - 上传一个文件,检查
move_uploaded_file()是否能成功移到/uploads/下;再尝试移到/var/backups/→ 应失败
常见上传绕过陷阱与规避
有些看似“正常”的路径其实会绕过限制,必须提前识别:
-
软链接陷阱:如果
/www/wwwroot/example.com/uploads是指向/data/uploads的软链,而/data不在open_basedir列表里,PHP 会检查真实路径,操作仍会被拒绝 -
路径末尾缺斜杠:写成
/www/wwwroot/example.com/uploads(无尾部/)是危险的,可能导致/www/wwwroot/example.com/uploadssomething被误放行 -
session 和缓存目录遗漏:如果上传逻辑依赖 session 或文件缓存(如
opcache.file_cache),对应目录(如/var/lib/php/sessions/)也建议加入,避免功能异常
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










