3/31/2011 This has been updated to reflect a better configuration to be used with Nginx 0.8/0.9.
Over the last couple of years I’ve been constantly researching for a way to get the PHP environment variables to show up correctly. My latest pains were with PATH_INFO and PHP_SELF, which are now finally solved.
My current configuration are PHP-FPM (5.2.10) and NginX (0.8.29) on a CentOS 5.4 x64 VPS. (As of 2011, I’m now using PHP 5.3.6, Nginx 0.9.6 and FreeBSD 8.2)
Traditionally you would use a PHP configuration such as this:
server { server_name your-domain.com www.your-domain.com; location / { root html/default; } location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html/default$fastcgi_script_name; fastcgi_pass 127.0.0.1:9000; } }
Within fastcgi_params would be something like this:
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
While the above method may seem to work at first, you’ll quickly notice problems when it comes to using $_SERVER[‘PATH_INFO’] and $_PATH[‘PATH_TRANSLATED’], and often enough $_SERVER[‘PHP_SELF’] ends up being set incorrectly when you try to adjust for the two environment variables.
Here is a setup I’ve come to prefer, especially when it comes to having multiple virtual hosts that use PHP. Notable tips are commented below the line.
Simple Nginx configuration file with a single virtual host
worker_processes 1; pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; index index.html index.htm index.php; # Identical to Apache's DirectoryIndex, setting it in # the http block set it as a default for all server blocks within server { listen 80; # since port 80 is set by default, you do not actually need # to set this, unless of course you are binding to a specific # address such as listen server-ip-address:80 or alternate port; server_name example.com www.example.com; root html/example.com/; # You will want to set your root here, since otherwise # $document_root within the php block will not work # if you set it in the location block you would also have # to set the php block within that location as well location / { # This would replace the typical mod_rewrite rules for wordpress # it can also be try_files $uri $uri/ @rewrites; where it goes to a # location @rewrites { ... } where you can place rewrite rules if a file # or folder is not found. try_files $uri $uri/ /index.php; } location = /favicon.ico { access_log off; log_not_found off; } # If you haven't created a favicon for your site, you can keep # your access and error logs clean by turning off the logs # when a browser requests the fav icon (its also a good way # to keep your logs from filling with useless information) location ~ /\. { access_log off; log_not_found off; deny all; } # You want to make sure that Nginx does not serve any .hidden files include php.conf; # I prefer to keep my php settings in one file, so I can simply # paste this single line for each of my virtual hosts } }
Now the php.conf file (which I’ve created in the /conf folder with nginx.conf)
fastcgi_intercept_errors on; # this will allow Nginx to intercept 4xx/5xx error codes # Nginx will only intercept if there are error page rules defined # -- This is better placed in the http {} block as a default # -- so that in the case of wordpress, you can turn it off specifically # -- in that virtual host's server block location ~ \.php { fastcgi_split_path_info ^(.+\.php)(/.+)$; # A handy function that became available in 0.7.31 that breaks down # The path information based on the provided regex expression # This is handy for requests such as file.php/some/paths/here/ fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; }
There you have it, PHP should now have correct environment variables. For example http://www.example.com/php.php/a/path/string/?var=foo would render the following results:
$_SERVER["QUERY_STRING"] -> var=foo $_SERVER["SCRIPT_NAME"] -> /php.php $_SERVER["SCRIPT_FILENAME"] -> /usr/local/nginx/html/default/php.php $_SERVER["REQUEST_URI"] -> /php.php/a/path/string/?var=foo $_SERVER["DOCUMENT_URI"] -> /php.php/a/path/string/ $_SERVER["DOCUMENT_ROOT"] -> /usr/local/nginx/html/default $_SERVER["PATH_INFO"] -> /a/path/string/ $_SERVER["PATH_TRANSLATED"] -> /usr/local/nginx/html/default/a/path/string $_SERVER["PHP_SELF"] -> /php.php/a/path/string/
So there you have it. A simple php block that will correctly assign the path environment variables, without having to use multiple blocks and patterns. And quite easy to simply assign to a new virtual host by simply pasting the include php; line.