Nginx location match all file extensions except ph

2019-02-18 08:16发布

问题:

I have the following in my nginx config file, it works, but I don't want to have to list every file extension.

location ~ \.(gif|jpg|png|css|js|ttf|woff|html|htm|unity3d) {
    try_files $uri /images/default.gif;
}

Is there a way to apply this to everything except php files?

Edit: Updated Config

The main file:

server{
    listen 80 default_server;

    server_name    _;
    root           /usr/share/nginx/html/$http_host;
    index          index.php index.html index.htm;

#    location ~ \.(gif|jpg|png|css|js|ttf|woff|html|htm|unity3d|tpl) {
#        try_files $uri /images/default.gif =404;
#    }

    location ~ .+(?<!\.php)$ {
        location ~ ^[^.]+\.[^.]+$ {
            try_files $uri /images/default.gif =404;
        }

        location ~ / {
            try_files $uri $uri/ /index.html;
            include /usr/share/nginx/conf/mission13.io.conf;
        }

    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Then in the included file:

if ($http_host = groups.mission13.io) {
    rewrite ^(.+)$ /index.php?path=$1;
}

回答1:

The PCRE Library

Nginx uses the PCRE library written in C. There's a huge man page, a bit hard to understand sometimes but quite detailed. Among it, you will find the look ahead / look behind functionnalities as you would find them in Perl.

Postive/negative look ahead/behind

Positive/negative look ahead/behind allow to match a string if one part of it is/isn't followed/preceded by an expression. Look behind expressions are restricted to a fixed string because it's not possible for most implementations to apply a regular expression backwards as you need to know how many steps you go back for this. Look ahead doesn't obviously suffer from this limitations, so you can use a regular expression like you usually do.

Here's the relevant section of the man page :

LOOKAHEAD AND LOOKBEHIND ASSERTIONS

     (?=...)         positive look ahead
     (?!...)         negative look ahead
     (?<=...)        positive look behind
     (?<!...)        negative look behind

 Each top-level branch of a look behind must be of a fixed length.

Unfortunately you can't capture the end of the string with look ahead.

Look behind in action

So, our first attempt will be using negative look behind from the end of the string :

location ~ .+(?<!\.php)$ {
    ...
}

Which means "Only capture strings that don't end with .php". That's quite close from what we need already. But there's something more to add to make it work like expected.

Nested locations

Indeed, nothing guarantees that you will have a string containing a file extension at this point. It could rather be anything except ^.+\.php$. To make sure this is a real file suffix, the natural way to overhaul this limit is by using nested location blocks where the most restrictive part is the apex. So our configuration will now look like below.

location ~ .+(?<!\.php)$ {
    location ~ ^[^.]+\.[^.]+$ {
        try_files $uri /images/default.gif;
    }
}

And that's it !

Your second issue

Here are my remarks after your post update for the second issue you are facing (404 errors on other URLs).

As ~ .+(?<!\.php)$ matches everything except \.php$ and locations are nested, you need to nest the location block / and transform it to a regex match :

location ~ .+(?<!\.php)$ {

    location ~ ^[^.]+\.[^.]+$ {
        try_files $uri /images/default.gif;
    }

    location ~ / {
        # your stuff
    }

} 

Also note that you can end up with an infinite loop with the try_files $uri /images/default.gif; part because the last paremeter of the try_files directive is an internal redirect or an HTTP code. So if /images/default.gif doesn't resolve to a file, the request will go trough this location block 10 more times until nginx stops the processing and return HTTP 500. So change it to try_files $uri /images/default.gif =404;.



标签: nginx