1

I'm moving a legacy Zend Framework application over to Nginx + php-fpm. Here are my relevant configs:

server { listen 80; server_name *.sandbox.journalexperts.com; port_in_redirect off; server_tokens off; autoindex off; include /etc/nginx/conf.d/assets.conf; # this file contains some info about not access logging robots.txt, favicon.ico, etc. client_max_body_size 15m; client_body_buffer_size 128k; root /wwwroot/vhosts/$host; index index.html index.php; access_log off; # deliver a static 404 error_page 404 /404.html; location /404.html { internal; root html; allow all; } # Deliver 404 instead of 403 "Forbidden" error_page 403 = 404; # Deny access to hidden files location ~ /\. { deny all; access_log off; log_not_found off; } location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { include /etc/nginx/conf/fastcgi.conf; fastcgi_intercept_errors on; fastcgi_ignore_client_abort off; fastcgi_connect_timeout 60; fastcgi_send_timeout 180; fastcgi_read_timeout 180; fastcgi_buffer_size 128k; fastcgi_buffers 4 256k; fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; } } 

This is my fastcgi.conf file:

fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param REQUEST_URI $request_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 $host; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; # http://wiki.nginx.org/HttpFastcgiModule#fastcgi_split_path_info fastcgi_split_path_info ^((?U).+\.php)(/?.+)$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param SCRIPT_URL $script_url; # This is a mapped variable. fastcgi_param SCRIPT_URI $scheme://$http_host$script_url; # Uses above mapped variable. fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param PHP_SELF $uri; fastcgi_param HTTPS $https if_not_empty; 

I need to mimic the behavior of SCRIPT_URL and SCRIPT_URI as they are populated in Apache. I found this thread where the poster used map to fill these.

map $uri $script_url { ~^(?<script_filename>.+\.(php|html))(?<path_info>.+)$ $path_info; ~^(?<script_filename>.+\.(php|html))$ $script_filename; } 

This, unfortunately, does not work for me and shows /index.php as the SCRIPT_URI. I suspect that this is because of my try_files block where I send the request over to /index.php. This is supported by the Nginx documentation:

$uri This variable is the current request URI, without any arguments (see $args for those). This variable will reflect any modifications done so far by internal redirects or the index module. Note this may be different from $request_uri, as $request_uri is what was originally sent by the browser before any such modifications. Does not include the protocol or host name. Example: /foo/bar.html 

Okay, let's try rewriting the map using $request_uri.

map $request_uri $script_url { default $request_uri; ~^(?<script_filename>.+\.(php|html))(?<path_info>.+)$ $path_info; ~^(?<script_filename>.+\.(php|html))$ $script_filename; } 

This is slightly better but still does not achieve the desired result. Here's what I get in Apache:

$_SERVER['SCRIPT_URL']: /tos/show.php/article/0000 $_SERVER['SCRIPT_URI']: http://example.com/tos/show.php/article/0000 

This is what I get in Nginx:

$_SERVER['SCRIPT_URL']: /tos/show.php/article/0000?hello=world $_SERVER['SCRIPT_URI']: http://example.com/tos/show.php/article/0000?hello=world 

I don't know how to go about this.

2
  • Fixing the PHP code wasn't an option? Commented Mar 14, 2013 at 22:44
  • Sadly, no. That was my preferred solution, but it turns out that a few different legacy applications use these two variables, as do some third party libraries we use, and who knows what else. Commented Mar 15, 2013 at 1:17

2 Answers 2

3

This is what I ended up doing, which works.

nginx.conf, in the http{} block:

map $request_uri $my_script_url { default $request_uri; ~^(?<script_filename>.+\.(php))(.*)?$ $script_filename; #/test.php or /test.php?hello=world ~^(?<script_filename>.*)(\?.*)$ $script_filename; #/tos?hello=world ~^(?<script_filename>.*)(\?.*)?$ $script_filename; #/tos or /tos/hello/world or /tos/hello/world?omg=what } 

Things I learned:

  • the regular expressions are matched top down and processing stops when the first match is found.
  • the nginx documentation could have done a lot more for me than it actually did.

Inside the server{} block:

location / { try_files $uri $uri/ /index.php$is_args$args; } location ~* \.php(.*)?$ { include /etc/nginx/conf/fastcgi.conf; [...] } 

fastcgi.conf:

fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param REQUEST_URI $request_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 $host; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; # http://wiki.nginx.org/HttpFastcgiModule#fastcgi_split_path_info fastcgi_split_path_info ^((?U).+\.php)(/?.+)$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param SCRIPT_URL $my_script_url; fastcgi_param SCRIPT_URI $scheme://$http_host$my_script_url; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param PHP_SELF $uri; fastcgi_param HTTPS $https if_not_empty; try_files $uri =404; 

php.ini:

; cgi.fix_pathinfo = 1 
1

Looks like you just need to strip the query parameters off:

map $request_uri $script_url { default $request_uri; ~^(?<script_filename>.+\.(php|html))(?<path_info>.+)(\?.*)?$ $path_info; ~^(?<script_filename>.+\.(php|html))(\?.*)?$ $script_filename; } 
1
  • Thanks for the suggestion. Unfortunately, that didn't change anything for me. To verify that the new pattern was matched, I changed the default to '/whatever' and that's what ended up getting returned. Commented Mar 14, 2013 at 18:03

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.