Skip to content

KBeezie

There's no place like ::1

Menu
  • Home
Menu

Path_Info & PHP_SELF woes [NginX]

Posted on 2009/12/122025/05/10

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:

Nginx
	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:

Nginx
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

Nginx
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)

Nginx
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:

Nginx
$_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.

5 thoughts on “Path_Info & PHP_SELF woes [NginX]”

  1. frostschutz says:
    2010/05/27 at 05:19

    First of all, thanks for sharing this! I’ve successfully replicated your setup, and for /php.php/a/path/string/?var=foo I get the same results as you. I do have a question however:

    What should the expected result be if php.php is in a subfolder, i.e. /folder/php.php/a/path/string/?var=foo?

    Currently, PATH_TRANSLATED for /php.php/ and /folder/php.php/ is exactly the same, I wonder if this is indeed correct or if /folder/ should go in there too.

  2. kbeezie says:
    2010/05/31 at 12:04

    When using paths after the php file name, PATH_INFO should show up as the path trailing the script, I would assume this should be the same for PATH_TRANSLATED as well when using a path trailing the file name. I do however advise that people concentrate on parsing the REQUEST_URI as opposed to relying on PATH_INFO and PATH_TRANSLATED. Most systems now days use mod_rewrite or similar and use the request_uri instead of the older path_info.

  3. frostschutz says:
    2010/06/01 at 05:36

    Also ran into a PHP security issue after following this guide (mainly because my php.conf did not include the folder restrictions anymore I had in place before).

    http://cnedelcu.blogspot.com/2010/05/nginx-php-via-fastcgi-important.html

    Yes, I’d prefer mod_rewrite over file.php/something too but unfortunately there are still a lot of scripts around that do this, both in Open Source and Proprietary scripts. 🙁

  4. Matthew says:
    2010/11/15 at 13:41

    I replicated your config but my scripts were returning a 404 in the error log. I had to have a SCRIPT_FILENAME manually configured for each vhost which solved the problem.

  5. kbeezie says:
    2010/11/15 at 13:49

    Well that’s not really *solving* it but rather taking a long work around. If you have the root defined in the server { } block and not location { } block then script filename would be automatic in the fastcgi params.

Comments are closed.

Bloggers

  • Clement Nedelcu
  • Martin Fjordvald
  • Michael Shadle
  • Profarius

Sites I Use

  • Karl Blessing
  • Nginx Wiki

administration Apache blog certificate circuits.web class-c configuration cpanel directadmin django examples freebsd friendly url front page google help httpd IP ipn migration Nginx nibbleblog openssl package passenger payment paypal performance PHP ports proxy proxying Python results scrape security seo sni ssl tips tls sni uwsgi wordpress wsgi

© 2025 KBeezie