NGINX rewrite rules for PATH_INFO and SCRIPT_NAME

We use nginx as our web server on all our servers here at Em Space as it does a great job of serving web sites with very little overhead, essential on low memory virtual servers.

We have a stock virtual host file which serves Drupal sites very nicely (I'll post that sometime) but Josh needed to install a PHP Harvester PHP based OAI2 harvester application which uses the server variable PATH_INFO for its query handling. Our default Drupal based rewrite and fastcgi rules didn't work, so we set about figuring out how to fix them for this site.

This is what we came up with:


server {
listen 80;
server_name doaih.urbits.com;

access_log /home/swin/oaih/dev/logs/access.log;
error_log /home/swin/oaih/dev/logs/error.log;

root /home/swin/oaih/dev/public;
index index.php index.html index.htm;

location / {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
}
}

location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

include /etc/nginx/fastcgi_params;
}

location ~ .php($|/) {

set $script $uri;
set $path_info "";

if ($uri ~ "^(.+.php)(/.+)") {
set $script $1;
set $path_info $2;
}

fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$script;
fastcgi_param SCRIPT_NAME $script;
fastcgi_param PATH_INFO $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 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_param REDIRECT_STATUS 200;

}

}

The first location directive sets up the base options while the second location directive matches a request to index.php on its own and passes it to fastcgi to handle. This was needed as requests for the domain without index.php were not being handled correctly by the next block.

The key section in the whole config file for dealing with our problem is this:


location ~ .php($|/) {

set $script $uri;
set $path_info "";

if ($uri ~ "^(.+.php)(/.+)") {
set $script $1;
set $path_info $2;
}

fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$script;
fastcgi_param SCRIPT_NAME $script;
fastcgi_param PATH_INFO $path_info;
}

This location directive matches any PHP requests not previously matched and sets the $script variable to the full uri. It also empties the $path_info variable. The if statement matches any requests like the following: http://mysite/index.php/foo and puts index.php into the $script variable and /foo into the $path_info variable.

$script and $path_info are inserted into the server variables by the fastcgi parameters SCRIPT_NAME and PATH_INFO and allow PHP to properly process the requests.