Nginx, PHP FPM, try_files and path_info
In the post, http://wiki.nginx.org/PHPFcgiExample, the author gives an URL example for testing various parameters, especially PATH_INFO and $fastcgi_path_info.
This URL is, http://lemp.test/test.php/foo/bar.php?v=1 (this URL is not a hyperlink and does not work, of course)
I was interested to find what Location clause would be necessary to test this on my own server.
In my case, I wanted to test in a separate sub-directory, so the test string becomes:-
http://mydomain.co.uk/mytest/test.php/foo/bar.php?v=1 (this URL does not work either. It’s intended you construct a test on your own server)
As the article says, the test.php file is:-
<pre>
<?php
var_export($_SERVER)
?>
</pre>
I’m the type of person that fears Regex. I don’t know why, but with a lot of patience and a late night, I’ve got this:-
location ~* ^/mytest/(.+\.php)(/.*)?$
and the steps are:-
“~*” the nginx command for case insensitive matching.
”^/mytest/” the sub-directory off the site’s root where the test.php file is present.
”(.+\.php)” the regex specification that will match one or more characters before the .php extension of the filename, where \. escapes the dot. This protects against a file, “.php” being processed.
“(/.*)?” the regex specification that will match zero or more characters after a slash, where the ? makes this optional.
”$” and finally the $ marks the end of the string. Note that the “?v=1” is never considered by the location matching.
If you think that two php filenames in the URL is a bit odd, various authors suggest it’s a possible construct and give OwnCloud as an example (I’ve not investigated this).
Now we have got the Location sorted, we need to consider whether try_files being included in the location block where fastcgi_split_path_info is also used.
It would appear there is a bug/feature, that PATH_INFO will not be correct if both are present.
And it’s true – I’m using version 1.8.0 when writing this.
Seems it won’t be fixed – see http://trac.nginx.org/nginx/ticket/321
My complete but minimalistic Location block I’ve used to test and correct the issue is as follows:-
#At least one char before the .php, then an optional / with 0 or more chars after
location ~* ^/mytest/(.+\.php)(/.*)?$
{
index index.php;
try_files $uri $uri/ /mytest/index.php$args; #You can comment this out, and PATH_INFO will be same
include fastcgi_params; #Put here first so we can override
fastcgi_split_path_info ^(.+\.php)(/.*)$; #Slightly different from others, and matches my Location regex command
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
set $real_script_name $fastcgi_script_name;
if ($document_uri ~* “^(.+?\.php)(/.*)$”) #Note using $document_uri as this avoids including the query string in the test
{
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
#Check to see if the file does really exist
if (!-f $document_root$real_script_name)
{
return 404;
}
}