NGINX send path as variable to PHP except if path

2019-05-26 22:23发布

I want to pass all my path to index.php?page=path. For example:

domain.com/a/b/c -> index.php?page=a/b/c

Therefore this is my NGINX conf file:

location ~ /(?P<arg1>.*)$ {
    fastcgi_pass php:9000;
    fastcgi_param  QUERY_STRING       /index.php?page=$arg1;
}

As far as I know, query string should be everything after .com, right? I'm passing arg1 to it. However, I wanted to ignore truly file paths like /file.jpg or /images/favicon.ico. I could simply negate them in regex but then they'd have no path at all.

So how to match /anything to index.php?page=anything except for files and actually deliver those files?

标签: php regex nginx
4条回答
\"骚年 ilove
2楼-- · 2019-05-26 22:34

The use case you mention is very common, and it's detailed in the common Nginx pitfalls page under the section Front Controller Pattern Web Apps

As per the aforementioned page, for Drupal, Joomla, etc., just use this inside your location block:

try_files $uri $uri/ /index.php?q=$uri&$args;

Since you want to use the "page" variable name, your code will look as follows:

location / {
    try_files $uri $uri/ /index.php?page=$uri&args;
}

The part $uri/ is relevant only if you want to serve content from directories, for example if you want to serve a Wordpress blog from yourdomain.com/blog/. If that's not the case, you can remove the $uri/ part.

My advice is to not use page as the variable to pass the section/route to PHP, because you might end up having a confusion between which section of the website to show vs. which page number. Page is misleading, I'd use route instead.

Of course, your mileage may vary and you may require something more complex based on your needs, but for basic sites, these will work perfectly. You should always start simple and build from there.

Additionally, to make debugging easier, consider using a verbose error log setting, I'd use info or notice to debug routing:

error_log logs/error.log info;

Good luck and keep us posted on how you solved the issue.

查看更多
我命由我不由天
3楼-- · 2019-05-26 22:43

I don't know nginx, but assuming truly/real path is something that ends with some kind of extension, and that you can write several rules with top rules having higher priority, you could write 2 rules like these:

First rule matches an url that ends with an extension: ( dot + word ) and does nothing:

/^.*[.]\w+$/

second rule matches anything and captures:

/(.*)/

If that is not possible, you could try to use a rule that matches urls like these: foo/bar/foo/bar/...

(\w+(?:\/\w+)*\/?)

If you don't want to allow last / bar, just use

(\w+(?:\/\w+)*)
查看更多
4楼-- · 2019-05-26 22:49

You need to use below

location ~ /(.*)$ {
  try_files $uri $uri/ /index.php?page=$1;
}

This will first check if file or directory exists if not then pass it to the index.php file

查看更多
Juvenile、少年°
5楼-- · 2019-05-26 22:49

Based on your Apache's .htaccess, the equivalent setting under Nginx would be:

    location / {
        # First attempt to serve request as file, then
        # as directory, then index.php?page=$args.
        try_files $uri $uri/ /index.php?page=$args;
    }
查看更多
登录 后发表回答