Static content and Front Controller pattern under same base URI

J. Lewis Muir jlmuir at imca-cat.org
Fri Oct 18 02:07:38 UTC 2019


Hello, nginxers!

What's the best way to server static content as well as dynamic content
that uses the Front Controller pattern under the same base URI?

I'm dealing with a web app partially written in PHP that expects to
serve static content as well as dynamic PHP content, using the Front
Controller pattern, both under the same base URI.  It expects to serve
static content if the file or directory exists.  But if the file or
directory does not exist, it expects request rewriting according to the
Front Controller pattern like this:

----
Request       Rewritten Request

/foo/         /foo/index.php
/foo/bar      /foo/index.php/bar
/foo/bar/baz  /foo/index.php/bar/baz
----

The following config works correctly:

----
location = /foo { return 301 $uri/$is_args$args; }

location /foo/ {
  alias /srv/www/localhost/app/foo/1.0.0/;
  index index.php;
  try_files $uri $uri/ @foo_front_controller;
}

location ~ ^/foo/.*?[^/]\.php(?:/|$) {
  error_page 418 = @foo_front_controller;
  return 418;
}

location @foo_front_controller {
  rewrite ^/foo(?!/index\.php)(/.+)$ /foo/index.php$1 last;
  root /srv/www/localhost/app/foo/1.0.0;
  fastcgi_split_path_info ^/foo(/.+?\.php)(/.*)?$;
  include php-fpm.conf;
  fastcgi_param REQUEST_URI $fastcgi_script_name$fastcgi_path_info$is_args$args;
}
----

I'm not a big fan of the location that sets the 418 error_page to the
@foo_front_controller named location, but I don't know of any other way
to essentially do a "return @foo_front_controller".  Is there a better
way?

The whole point of the @foo_front_controller named location is so that
I can have one block that defines the Front Controller logic, and then
use it in both the "/foo/" location block in the try_files directive as
the fallback for when the file or directory does not exist and in the
location block right below it for requests that are for .php files.

Is this a good approach, or is there a better way?

Example content and requests are shown below.

Thank you!

Lewis

----
$ ls -al /srv/www/localhost/app/foo/1.0.0
total 8
drwxr-xr-x 2 root root  38 Oct 17 17:04 .
drwxr-xr-x 3 root root  19 Oct 17 16:37 ..
-rw-r--r-- 1 root root 209 Oct 17 17:04 index.php
-rw-r--r-- 1 root root  21 Oct 17 16:44 msg.txt
$ cat /srv/www/localhost/app/foo/1.0.0/index.php
<!doctype html>
<html lang=en>
<head>
<title>hello, world</title>
</head>
<body>
<?php echo '<p>hello, world</p>' . "\n"; ?>
<?php echo '<p>REQUEST_URI: ' . $_SERVER['REQUEST_URI'] . '</p>' . "\n"; ?>
</body>
</html>
$ cat /srv/www/localhost/app/foo/1.0.0/msg.txt
Use the Force, Luke.
$ curl http://localhost/foo/
<!doctype html>
<html lang=en>
<head>
<title>hello, world</title>
</head>
<body>
<p>hello, world</p>
<p>REQUEST_URI: /index.php</p>
</body>
</html>
$ curl http://localhost/foo/index.php
<!doctype html>
<html lang=en>
<head>
<title>hello, world</title>
</head>
<body>
<p>hello, world</p>
<p>REQUEST_URI: /index.php</p>
</body>
</html>
$ curl http://localhost/foo/bar
<!doctype html>
<html lang=en>
<head>
<title>hello, world</title>
</head>
<body>
<p>hello, world</p>
<p>REQUEST_URI: /index.php/bar</p>
</body>
</html>
$ curl http://localhost/foo/bar/baz
<!doctype html>
<html lang=en>
<head>
<title>hello, world</title>
</head>
<body>
<p>hello, world</p>
<p>REQUEST_URI: /index.php/bar/baz</p>
</body>
</html>
$ curl http://localhost/foo/msg.txt
Use the Force, Luke.
$ curl http://localhost/foo/msg-quux.txt
<!doctype html>
<html lang=en>
<head>
<title>hello, world</title>
</head>
<body>
<p>hello, world</p>
<p>REQUEST_URI: /index.php/msg-quux.txt</p>
</body>
</html>
----


More information about the nginx mailing list