apache和nginx下$_server关键字段差异显著:request_uri最一致;script_name在nginx常为空;php_self行为也不同;重写规则、open_basedir路径、文件权限及upload_tmp_dir配置均需针对性适配。

Apache 和 Nginx 对 $_SERVER 的关键字段差异
PHP 脚本在 Apache 和 Nginx 下运行时,$_SERVER 数组里几个常用键的值可能完全不同,最典型的是 $_SERVER['REQUEST_URI']、$_SERVER['SCRIPT_NAME'] 和 $_SERVER['PHP_SELF']。Nginx 默认不设置 SCRIPT_NAME,而 Apache 会;Nginx 的 REQUEST_URI 包含查询参数,Apache 在某些 mod_rewrite 配置下可能被重写掉。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 永远用
$_SERVER['REQUEST_URI']获取完整请求路径(含 query),它在两者中行为最一致 - 避免依赖
$_SERVER['SCRIPT_NAME']做路由判断——Nginx 下常为空,改用basename($_SERVER['PHP_SELF'])或直接读取__FILE__ - 如果必须拼接 URL,优先用
$_SERVER['HTTP_HOST']+$_SERVER['REQUEST_URI'],别拼SCRIPT_NAME和PATH_INFO
rewrite 规则写法导致的 404 或 500 错误
Nginx 没有 .htaccess,所有重写逻辑必须写进 server 块;而 Apache 的 mod_rewrite 是逐级生效的(.htaccess → vhost → httpd.conf)。常见问题是把 Apache 的 RewriteRule ^(.*)$ index.php [L] 直接照搬到 Nginx,却忘了 Nginx 的 try_files 才是等效机制。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- Apache 的伪静态规则,对应 Nginx 应统一转为
try_files $uri $uri/ /index.php?$query_string; - Nginx 中不要用
if (!-f $request_filename)做判断——性能差且易出错,try_files更可靠 - 如果用了 Laravel/ThinkPHP 等框架,确认其官方文档给的 Nginx 配置片段是否包含
fastcgi_split_path_info,漏掉会导致PATH_INFO为空,路由失效
php.ini 和 open_basedir 在不同服务器上的路径兼容问题
Apache 下常通过 php_admin_value open_basedir 在 vhost 中限制目录,Nginx 则需在 fastcgi_param 中传入,或靠 PHP-FPM 的 php_admin_value[open_basedir] 配置。更麻烦的是:Apache 可能允许相对路径(如 ./uploads),但 Nginx + PHP-FPM 下必须写绝对路径,否则直接报 Warning: Unknown: open_basedir restriction in effect。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 所有
open_basedir值统一用realpath(__DIR__ . '/..')动态生成绝对路径,别硬编码 - 检查
phpinfo()输出里的Loaded Configuration File,确认实际生效的是哪个php.ini—— Nginx 下容易误改了 CLI 的配置而非 FPM 的 - 若用 Docker 或共享主机,注意
disable_functions在不同环境可能不同,比如shell_exec在 Nginx 环境常被禁,但 Apache 下开着,代码里调用前先function_exists('shell_exec')
文件权限与 upload_tmp_dir 导致上传失败
Apache 通常以 www-data 用户运行,Nginx 默认也是,但很多运维会把 Nginx worker 进程改成 nginx 用户,而 PHP-FPM pool 却配成 www-data,结果上传临时文件时因用户不一致被拒绝写入,报错 Unable to create temporary file 或 move_uploaded_file(): Unable to move。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 统一 PHP-FPM pool 的
user和group与 Nginx worker 用户一致(查ps aux | grep nginx看实际用户) - 显式设置
upload_tmp_dir = /var/tmp/php并确保该目录存在、可写、属主匹配,别依赖系统默认(/tmp 权限可能太松或太紧) - 上传后立即用
is_uploaded_file()校验,别直接信任$_FILES['xxx']['tmp_name']—— Nginx 下偶尔会返回空字符串
跨服务器兼容真正的难点不在语法,而在环境变量、进程用户、临时目录这些“看不见”的链路。哪怕一行代码没改,$_SERVER 少一个键、upload_tmp_dir 权限错一位、Nginx 的 fastcgi_param 漏传一个,都够卡半天。











