- URL: https://www.laruence.com/en/2009/11/13/1138.html
- Please include attribution when republishing.
PATH_INFO is a CGI 1.1 standard, and it is often used as a carrier for passing parameters.
For example, we can use PATH_INFO instead of Rewrite to build pseudo-static pages, and quite a few PHP frameworks use PATH_INFO as the routing carrier.
In Apache, with no configuration at all, AcceptPathInfo is accepted by default for PHP scripts, which means:
If the server has a /laruence/index.php
then for the following requests,
/laruence/index.php/dummy /laruence/dummy
Apache accepts both, treats them as accesses to info.php, and sets PATH_INFO to dummy
Under Nginx, PATH INFO is not supported, meaning it will not set PATH_INFO by default.
And since the default config file only gives very basic PHP support, those requests will also 404 under the default setup, with a file-not-found error.
For PHP frameworks that use PATH_INFO to pass critical information (Kohana, ThinkPHP, for example), that is practically fatal.
There are generally two ways to solve this. The first is to use rewrite, but its downside is obvious: you have to convert PATH_INFO into a Query String. I will not go into that one here.
The second is what I want to talk about today: emulating PATH_INFO:
First, in Nginx the decision whether to hand a request to the PHP CGI server is made by matching the file extension. nginx.conf generally has a default block like this:
location ~ .php$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
}
So for a path like /laruence/info.php/pathinfo, Nginx will not route it to the PHP CGI server correctly. We need to rewrite that config as:
location ~ .php {//fragment match
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
}
Now the script path is left for PHP to handle itself. So how do we add PATH_INFO?
First, we need to turn on the cgi.fix_pathinfo directive in PHP. Once it is on, PHP follows the CGI spec to work out which part of SCRIPT_FILENAME is the script and which is PATH_INFO (ini directive explanation), and uses SCRIPT_NAME to correct PATH_INFO (and PATH_TRANSLATED) to the right values (which also says a lot about how incomplete PHP's original CGI 1.1 support was)
Then all you need to do is add one FASTCGI_PARAM entry:
location ~ .php {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_script_name;
}
Now give it a try...
btw: Of course, the fix above hands path analysis over to PHP. Some friends online have posted another configuration where Nginx does the path analysis instead (so fix_pathinfo is not needed):
location ~ \.php
{
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
set $path_info "";
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME /var/html/$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
}
Postscript: a security hole discovered recently (A Possible Security Vulnerability in Nginx + PHP CGI) is related to this configuration. If you use the second configuration, please be sure to turn off cgi.fix_pathinfo. As for that vulnerability, I personally think it has little to do with Nginx and is not an Nginx vulnerability. It is a configuration problem, yet everywhere people are calling it an Nginx Bug. Not right, not right.
Be First to Comment