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.
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 gyn0.com www.gyn0.com; root html/default; # 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 / { # Below are some wordpress-friendly rewrite rules if (-f $request_filename) { expires 30d; break; } if (!-e $request_filename) { rewrite ^/.+/?(/wp-.*) $1 last; rewrite ^/.+/?(/.*\.php)$ $1 last; rewrite ^/(.+)$ /index.php?q=$1 last; } } 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) include php; # 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 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/ include fastcgi_params; # Includes the modified fastcgi parameter file (see below) fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; }
The new modified fastcgi_params:
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; #SCRIPT_NAME needs to remain without the document_root on front #Otherwise PHP_SELF breaks, the interpreter will still find the file #because of the added SCRIPT_FILENAME parameter below fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #This one was added right into the file, since with root moved, and path_info split #It should no longer need to be set manually for each virtual host fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; #the two lines below are possible now because of the fastcgi_split_path_info function fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; # I removed the version, as not to give away too much information 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;
There you have it, PHP should now have correct environment variables. For example http://www.kbeezie.com/php.php/a/path/string/?var=foo would render the following results (the url above doesn’t actually work, sorry
):
$_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.


You will also need to add the following line to the advanced option. The url will be the destination notified in the event of a payment or related transaction. Normally you don’t want to call it something as obvious as ipn.php in the root of your site, rather bury the script in a folder and give it some other name such as txn1.php.
If you have multiple options that you will want to verify in your IPN script you can get PayPal to send you the specific Item ID by turning on the tracking option for the button: