Reputation: 4708
I am migrating from an old framework to a new framework in php. The old framework had a landing page for every URL, such as:
test.com/page1
would be routed to public_directory/page1.php
test.com/another_page
would be routed to public_directory/another_page.php
etc.
The following block was used for these requests:
location / {
limit_req zone=globallimit burst=20 nodelay;
try_files $uri $uri/ @php;
}
location @php {
rewrite ^(/[^/]+)$ $1.php last;
rewrite ^(/[^/]+)/(.*)$ $1.php?q=$2 last;
}
The new framework uses a front controller, and every request needs to be directed to public_directory/front_controller.php
. As we migrate we are removing the old landing files, which is how we can identify which pages use the new framework.
What I thought would work is the following, after the @php
block, adding a default argument to front_controller.php
:
location / {
limit_req zone=globallimit burst=20 nodelay;
try_files $uri $uri/ @php /front_controller.php?$arg;
}
location @php {
rewrite ^(/[^/]+)$ $1.php last;
rewrite ^(/[^/]+)/(.*)$ $1.php?q=$2 last;
}
If the @php rewrite block doesn't match a file, then it should default to /front_controller.php?arg
; however, what I am finding is that now @php is ignored and nginx
is instead going directly to front_controller.php. Where am I going wrong, why is the @php rewrite now being ignored?
Upvotes: 0
Views: 2724
Reputation: 15537
The try_files
directive expect a list of files followed by the URI / named location / HTTP error code that will be used if none of the files in a list exists. Assuming your site root directory is /home/user/www
and your request is http://example.com/some/path
this configuration check the existence of following files/directories:
/home/user/www/some/path
file, if the file is found it's contents will be returned in response body./home/user/www/some/path/
directory, if this directory exists, it will be checked for all possible index files defined with the index
directive, first found file will be used. If no index files found in this directory, nginx returns directory contents if you have autoindex on;
or HTTP 403 Forbidden otherwise./home/user/www@php
file. Obviously, this file would not be found.If none of these checks succeed, nginx will follow an URI (or named location) defined as the last argument (/front_controller.php?$arg
in this case).
What you can do is to try something like
location ~ ^(/[^/]+)$ {
try_files $1.php /front_controller.php?$arg;
}
location ~ ^(?<script>/[^/]+)/(?<param>.*)$ {
rewrite ^ $script?q=$param last;
}
However I do not understand where $arg
variable should come from. Maybe you mean $is_args$args
?
I was wrong, you can check the existence of php script with try_files
directive, but this script would not be passed to your php handler location block. Your task intrigued me, and finally I got something working:
# backup original args
set $original_args $args;
if ($uri ~ "^(/[^/]+)(?:/(.*))?$") {
set $script $1.php;
set $param $2;
}
if ($param) {
set $args "q=$param";
}
location / {
limit_req zone=globallimit burst=20 nodelay;
try_files $uri $uri/ @php;
}
location @php {
if ( !-f $document_root$script ) {
# old landing php file is absent, restore original args and rewrite URI to /front_controller.php
set $args $original_args;
set $script /front_controller.php;
}
rewrite ^ $script last;
}
When I occasionally come upon some of my old answers, they are really makes me cry sometimes. Here is how I'd solve this now, after a few years of nginx experience:
set $original_args $is_args$args;
location / {
limit_req zone=globallimit burst=20 nodelay;
try_files $uri $uri/ @php;
}
location @php {
rewrite ^(/[^/]+)$ $1.php last;
rewrite ^(/[^/]+)/(.*)$ $1.php?q=$2 last;
}
location ~ \.php$ {
try_files $uri /front_controller.php$original_args;
... rest of the original PHP handler here
}
Upvotes: 1