PHP 8.2 无法限制目录执行 PHP 脚本,须由 Nginx/Apache 在 Web 服务器层拦截:Nginx 用 location ^~ /path/ { location ~ \.php$ { return 403; } },Apache 用 .htaccess 中 SetHandler none 配合 Require all denied,并确保上传目录移出 Web 根目录。

PHP 8.2 本身不能限制某个目录执行 PHP 脚本——这是 Web 服务器(Nginx 或 Apache)的职责,不是 PHP 解释器的功能。你改 php.ini 中的 open_basedir 或禁用函数,都拦不住用户上传一个 shell.php 后直接通过 URL 访问并执行。真正起效的方式,是让 Nginx/Apache 根本不把那个目录下的 .php 当作脚本解析。
Nginx 下禁止上传目录执行 PHP(宝塔/通用)
进入站点配置文件(宝塔:网站 → 点击域名 → 配置文件),在 server { ... } 块内、location ~ \.php$ 规则之前插入:
- 用
^~前缀确保优先匹配,例如禁止/runtime/uploads/和子目录下所有 PHP 文件:
location ^~ /runtime/uploads/ {
location ~ \.php$ { return 403; }
}
- 别写
deny all,它对路径无效;也别漏掉结尾斜杠,否则/runtime/uploadshack.php可能绕过 - 改完必须重启 Nginx(宝塔点“重载配置”或终端执行
nginx -s reload) - 验证方式:
curl -I https://yoursite.com/runtime/uploads/test.php,返回HTTP/1.1 403 Forbidden才算成功
Apache 下禁止上传目录执行 PHP(含宝塔 Apache 模式)
在要限制的目录(如 public/uploads/)下放一个 .htaccess 文件,内容为:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
SetHandler none
Require all denied
-
SetHandler none是关键:强制解除 PHP 处理器绑定,比RemoveHandler更可靠 - 确保站点根目录的
AllowOverride设为All(宝塔默认开启) - 不要只依赖
Deny from all,该语法在 Apache 2.4+ 已废弃,会导致 500 错误
目录位置比权限设置更重要
即使你把 uploads/ 权限设成 644,只要它还在 public/ 或 Web 根目录下,攻击者就能通过 URL 直接请求 /public/uploads/malware.php。正确做法是:
- 把上传根目录移到 Web 不可访问路径,如
runtime/uploads/或storage/uploads/ - 确认该路径不在
root或alias指向的公开目录内(用ls -l /var/www/yourapp/查看实际结构) - Linux 权限设为
755即可(Web 进程需写入,但无需给组/他人执行权)
PHP 层面配合加固(非替代,是补充)
虽然不能靠 PHP 拦执行,但可以加几道保险:
- 上传后立即用
finfo_file()校验真实 MIME 类型,拒绝application/x-php等类型 - 禁止保存
.php、.phtml、.phps、.phar等扩展名(白名单优先) - 重命名上传文件,去掉原始扩展名,服务端根据内容决定后缀(如图片统一存为
xxx.jpg) - 下载文件必须走控制器,用
readfile()输出,并加头:header('X-Content-Type-Options: nosniff');
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










