PATH_INFO 失效主因是服务器配置问题:Apache 未启用 mod_rewrite、nginx fastcgi_split_path_info 正则错误、PHP-FPM security.limit_extensions 限制或框架兼容模式冲突;应逐层排查并优先采用 QUERY_STRING 模式。

Apache 虚拟主机没开 mod_rewrite,PATH_INFO 直接失效
很多虚拟主机(尤其共享型)默认禁用 mod_rewrite,或只允许基础重写规则。这时候框架(比如 ThinkPHP、Laravel 的兼容模式)依赖的 PATH_INFO 会彻底拿不到值——$_SERVER['PATH_INFO'] 为空,$_SERVER['ORIG_PATH_INFO'] 也常为空,不是代码写错了,是服务器压根没传。
实操建议:
- 先确认是否真被禁用:在站点根目录放一个
info.php,内容为<?php phpinfo(); ?>,搜索mod_rewrite看是否显示“enabled” - 如果禁用且无法开启,别硬改框架的
URL_MODEL或APP_URL_MODE,那只会让路由全挂 - 改用
QUERY_STRING模式:把/index.php/user/profile?id=123这种显式参数 URL 作为唯一入口,后端统一解析$_GET和路径片段 - ThinkPHP 5.1+ 可设
'url_route_must' => false避免强制匹配,再配合parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY)手动拆参
nginx 虚拟主机伪静态规则写错,PATH_INFO 变成空字符串
不少用户照搬 Apache 的 .htaccess 规则到 nginx,结果 $_SERVER['PATH_INFO'] 是空,但请求能进脚本——其实是 fastcgi 参数没传对,fastcgi_split_path_info 正则没匹配上,导致 PATH_INFO 没被提取出来。
实操建议:
- 检查 nginx 配置里是否有
fastcgi_param PATH_INFO $fastcgi_path_info;这行,缺了就补上 -
fastcgi_split_path_info的正则必须和你的入口文件名一致,比如入口是index.php,就得写^((?U).+\.php)(/?.+)$,不能写成^((?U).+\.php/)(/?.+)$(多了一个斜杠) - 测试方法:在
index.php开头加var_dump($_SERVER['PATH_INFO'], $_SERVER['ORIG_PATH_INFO']);,访问/index.php/user/list看输出 - 部分主机商屏蔽了
fastcgi_split_path_info,此时只能退到QUERY_STRING模式,或改用REQUEST_URI自己 parse
PHP-FPM 配置限制导致 PATH_INFO 被截断或污染
有些虚拟主机用老旧 PHP 版本(如 5.4),或 FPM pool 配置里设了 security.limit_extensions = .php,会导致带点号的路径(如 /user/1.2.3)被直接拒绝,或者 PATH_INFO 在中间被截断成 /user/1。
实操建议:
- 检查
phpinfo()里Loaded Configuration File对应的php.ini,搜security.limit_extensions,确保包含常见扩展如.php .php3 .php4 .php5 .phtml - 若无法修改,避免在 URL 路径中使用点号分隔版本号或浮点 ID,改用连字符(
/user/1-2-3)或 base64 编码 - 遇到
Access denied.错误且 URL 含点号,基本就是这个配置在拦截,不是权限问题 - PHP 7.4+ 默认更宽松,但虚拟主机未必升级,别假设版本新就安全
框架启用兼容模式后,$_GET 和 PATH_INFO 冲突
比如 ThinkPHP 设 'url_model' => 3(兼容模式),它会尝试从 REQUEST_URI 或 PATH_INFO 提取路由,再 fallback 到 QUERY_STRING。但如果用户手动拼了 ?s=/user/index 又带其他 GET 参数,两个来源混在一起,s 参数可能被覆盖或解析错位。
实操建议:
- 兼容模式下,统一用
s参数承载路径,其他业务参数走独立键名,比如?s=/user/profile&id=123&tab=info,别把id塞进路径段 - 检查框架是否开启了
url_convert,某些版本会自动把/转成%2F导致解析失败,关掉更稳 - 调试时打印
$_SERVER['REQUEST_URI']和$_GET对比,看框架到底从哪读的原始路径 - 别依赖
$_SERVER['PATH_INFO']和$_GET同时有效——虚拟主机环境下,它们经常只有一边靠谱
真正麻烦的不是怎么配,而是你得先分清:当前空白的 PATH_INFO,到底是 Apache 没传、nginx 没拆、PHP 拦了,还是框架自己解析错了。少猜,多打日志,每个环节都 var_dump 一下,比查十篇教程快。


















