Search code examples
phpnginxfastcgi

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


I'm trying to figure out why the prepending / is not allowing the \.php$ 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: //domian.com/v#.#/endpoint/uri

Our document_root is one directory below the version number; index.php exists within the version directory: path/to/sites/public/v1.0/index.php

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;

To:

    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 try_files because the pattern explicitly looked for starting with /.

I was reading: http://nginx.org/en/docs/http/request_processing.html

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.


Solution

  • 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.