I configured nginx stable (1.4.4) + PHP (using FastCGI, php-fpm) on Debian. That works fine:
location ~* ^/~(.+?)(/.*\.php)$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
alias /home/$1/public_html$2;
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_index index.php;
autoindex on;
}
I use the PATH_INFO variable, therefore I added the following line to fastcgi_params:
fastcgi_param PATH_INFO $fastcgi_path_info;
And in /etc/php5/fpm/php.ini:
cgi.fix_pathinfo = 0
I think that should work, but when I print out all server variables, PATH_INFO is always empty:
array (
'USER' => 'www-data',
'HOME' => '/var/www',
'FCGI_ROLE' => 'RESPONDER',
'QUERY_STRING' => '',
'REQUEST_METHOD' => 'GET',
'CONTENT_TYPE' => '',
'CONTENT_LENGTH' => '',
'SCRIPT_FILENAME' => '/usr/share/nginx/html/srv_var.php',
'SCRIPT_NAME' => '/srv_var.php',
'PATH_INFO' => '',
'REQUEST_URI' => '/srv_var.php',
'DOCUMENT_URI' => '/srv_var.php',
'DOCUMENT_ROOT' => '/usr/share/nginx/html',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'GATEWAY_INTERFACE' => 'CGI/1.1',
'SERVER_SOFTWARE' => 'nginx/1.4.4',
.....
)
I can not figure where the problem is. Any ideas?
First of all, in modern PHP, the PATH_INFO
is stored in the $_SERVER
array. Try:
echo "called SCRIPT_NAME: {$_SERVER['SCRIPT_NAME']} with PATH_INFO: {$_SERVER['PATH_INFO']}";
In any case phpinfo()
comes to the rescue to help find a lot of the internal php information, like variables and configurations.
As for the NginX config most of it is already explained in the other posts. So this here is a summary and a closer look at the details and the why of the following sample location block:
location /main.php {
# regex to split $uri to $fastcgi_script_name and $fastcgi_path_info
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
# set the standard fcgi paramters
include fastcgi.conf;
# pass the request to the socket
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}
The fastcgi_split_path_info
splits your location between SCRIPT_NAME
and PATH_INFO
.
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
The expression in the first parentheses of the regular-expression extracts the SCRIPT_NAME
, while the second extracts the PATH_INFO
.
The first regex group, (.+?\.php)
, expects any character (the dot .
), at least once or more than once (the plus +
). with a trailing .php
. The dot in .php
is escaped to \.php
so it's taken literally not as "any character".
The questionmark ?
makes the plus lazy (+?
) so the evaluation stops at the first .php
suffix.
/some.php/next.php/path-info
is evaluated to a SCRIPT_NAME
of /some.php
with a PATH_INFO
of /next.php/path-info
; beware, not to a SCRIPT_NAME
of /some.php/next.php
with a PATH_INFO
of /path-info
.The second regexp group, (/.*)
, basically takes everything that start with a slash as PATH_INFO
.
The leading ^
and trailing $
bind the expressions to the start and end of the line.
The next line checks that the extracted script really does exist as a file:
try_files $fastcgi_script_name =404;
Otherwise it returns a 404
error. This prevents giving non-existing files to the PHP processor, however has the bad habit of resetting the $fastcgi_path_info
variable (see: http://trac.nginx.org/nginx/ticket/321).
One workaround is to store $fastcgi_path_info
in $path_info
and set the FCGI param to the stored $path_info
. This is done by the next two lines:
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
The other FCGI parameters are then set within the include of fastcgi.conf
. This file, that's sometimes also named fastcgi_params
should be provided by your distribution.
include fastcgi.conf;
Then finally pass the request to your current PHP instance socket (here PHP 7.4):
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
Now remember that all of this happens only, if the surrounding location block is hit. The above example is a prefix location, meaning that every location is matched, that starts with the prefix /main.php
. This would be a typical configuration for a routed PHP application that has only one central file named main.php
. To catch all .php
files a regex has to be used, which could be as simple as ^.+?\.php(/|$)
. The (/|$)
after the .php
means that there's either a backslash (and more characters) or nothing after the .php
part of the location. Subdirectories are also allowed, so the expression matches basically every location that somewhere contains the string .php
, as long as it's either at the end or followed by a slash.
location ~ ^.+?\.php(/|$) {
#...
}
As the location is only the guard that allows entering the following block, the final PHP filename and path-info are still split as described above. If the resulting filename does not exist a 404 is returned.
This is just a simple configuration. Of course there's a myriad of possibilities to configure the location regex, to suit the needs of your specific application. To go into all that details would be a small book.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With