guice666 guice666 - 1 year ago 68
PHP Question

Why does `/` in try_files break `~ \.php$`

I'm trying to figure out why the prepending

is not allowing the
locations directive from picking up the script.

Below is a sample .conf I'm using for nginx. We're running API code, versioned out in path:

Our document_root is one directory below the version number;
exists within the version directory:

index index.php # <-- this is in here globally
location ~ ^/(?<version>v[\d\.]+) {
try_files $uri $version/index.php?$args;
# Why does this NOT work? The / stopping \.php$ from matching
# try_files $uri /$version/index.php?$args;

location ~ \.php$ {

fastcgi_pass php56;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;

I've tried all sorts of things, but can't seem to get this working. Once I remove the
it works as expected, but then my SCRIPT_FILENAME line changes from:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;


fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;

And this breaks direct PHP file calls -- something I don't want.

Edit: Solution: Answered below: The issue had to do with order of matching. Pattern matching is first found, not last discovered.

Switching their order worked. It failed the first
because the pattern explicitly looked for starting with

I was reading:

A request “/index.php” is also matched by the prefix location “/”
first and then by the regular expression “.(php)$”. Therefore, it is handled by the latter location and the request is passed to a FastCGI server listening on localhost:9000.

Answer Source

The first thing to note is that regex locations are evaluated in file order, so if /v1.1 matches the first location block, then /v1.1/index.php will also match the first location block. You seem to fix the problem in the wrong way by creating bad URIs with a missing leading /.

See this document for details.

You need to place your location ~ \.php$ block before your location ~ ^/(?<version>v[\d\.]+) block in order to allow .php files with the version prefix to be processed by the PHP block.