Nginx 与 PHP 的正确使用姿势 ( 以及 PATH_INFO )

通常来说, PHPnginx 一块用的时候, PHP 通过 php-fpm 启动处理进程, nginx 通过 fastcgi 协议和 fpm 进行通信.

也就是当客户端请求 .php 的时候, nginx 通过正则匹配文件, 然后设置一些重要的变量, 比如 SCRIPT_FILENAME 这些变量, 然后反向代理给监听的 fpm 处理, 当 fpm 处理完 php 脚本之后将结果返回给 nginx.

因此对于一般的 php 程序来说, nginx 配置文件只需要简单的加如下内容

location ~* \.php$ {
    fastcgi_index   index.php;
    fastcgi_pass    127.0.0.1:9000;
    include         fastcgi_params;
    fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
}

在这里通过 fastcgi_pass 指定 fpm 监听的地址, 而 include fastcgi_params 来包含一个预先定义好的文件, 此文件中通过一系列的 fastcgi_param 指令设置了一大堆 CGI 1.1 协议当中的变量, 这些变量将会在 $_SERVER 魔术变量当中可以获取到.

虽然此方法可以让一般的 php 程序正常运行, 但这会让一些基于 PATH_INFO 来运行的程序产生404, 例如 wordpress 等

要想解决这个问题, 首先得明白什么是 PATH_INFO, 你去百度搜索一下, 几乎所有人都会跟你说:

PATH_INFO 不是 nginx 的功能, 是 PHP 的功能

对此我只能说, fnndp, PATH_INFO 的确不是 nginx 的功能, 但它也不是 PHP 的功能, 相反, PATH_INFOCGI 1.1 协议当中定义的 Request Meta-Variables, 具体可以查阅RFC 38754.1.5 小节.

而一些 PHP 框架大量运用这一特性进行 URL 美化, 例如 /index.php/this/is/path/info
这间接导致了几乎让一大堆人认为 PATH_INFO 就是 PHP 的功能.

知道了什么是 PATH_INFO 之后, 该怎么解决呢? 通常有两种办法.

使用 php 的 cgi.fix_pathinfo 功能 [deprecated]

强烈不推荐此种方式

此方式通过将 php.ini 当中的 cgi.fix_pathinfo 设置为1, 并且在 nginx 中加入一条 fastcgi_param PATH_INFO $fastcgi_script_name;

当开启 fix_pathinfo 之后, php 会根据 CGI 1.1 的规范来分析 SCRIPT_FILENAME, 从中截取什么是真正的执行脚本, 什么是 PATH_INFO, 并且修正对应的变量

但这种方法有严重的安全隐患, 会引起脚本注入. 因此强烈不推荐用这种方式, 如果有人教你说用这种方式, 请赶快修正你的配置.

使用 nginx 的 fastcgi_split_path_info 功能

此种方式依赖 nginxfastcgi_split_path_info 指令, 该指令通过正则表达式来对 uri 进行处理, 从中分理出真实脚本文件和 PATH_INFO, 并根据正则捕获组来设置两个重要变量
1. $fastcgi_script_name
2. $fastcgi_path_info

当使用这种方式的时候, nginx 的配置看起来如下

location ~ ^(.+\.php)(.*)$ {
    fastcgi_index index.php;
    fastcgi_pass 127.0.0.1:9000;

    include fastcgi_params;

    fastcgi_split_path_info       ^(.+\.php)(.*)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
}

需要注意的是第一行修改了原来的正则, 同时第七行增加了 fastcgi_split_path_info 指令, 而第九行的值改为了正确的 $fastcgi_path_info.

同时需要注意将 cgi.fix_pathinfo 设置为0.

通过对 nginx 进行调整之后就可以正确的使用 PHP 功能了.

发表评论

电子邮件地址不会被公开。 必填项已用*标注