I’m currently hiding the .php extension from the urls on my nginx server with this configuration:
location / { try_files $uri $uri/ @extensionless-php; index index.html index.htm index.php; } location ~ .php$ { try_files $uri =404; include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; } location @extensionless-php { rewrite ^(.*)$ $1.php last; }
This is working perfectly, but how can I make nginx not allow adding the .php extension?. In my example if you manually delete the .php it works but if you add it it remains permanent in the url.
Advertisement
Answer
To redirect those requests permanently with HTTP 301 code try
rewrite ^(.*).php$ $1 permanent;
Put this directive before your location
blocks.
Update
After this being answered, OP asked another question (now being deleted) – what if you have the following webroot structure:
webroot | +-- index.php (PHP file) | +-- somename.php (PHP file) | +-- somename (folder) | | | +-- index.php (PHP file) | +-- someothername (folder) | +-- index.php (PHP file)
Previous solution makes it impossible to serve somename.php
file, because the request to http://example.com/somename
would be redirected by try_files
directive to http://example.com/somename/
and in next turn would be served with somename/index.php
file.
This can be solved, but you’ll have to stop using index
and try_files
directives and emulate their behavior with your own request processing logic. This is what I’ve ended up with:
map $original_uri $maybe_slash { ~/$ ''; default '/'; } server { ... if ($original_uri = '') { set $original_uri $uri; } # redirect requests of '/somepath/somefile.php' to '/somepath/somefile' rewrite ^(.*).php$ $1 pemanent; location / { # this emulates 'try_files $uri $uri/ ...' directive behavior and redirects '/some/path' # to '/some/path/' if 'some/path.php' file does not exists, but 'some/path' folder exists # and there are 'some/path/index.html' file in that folder set $check_redirect $rewrited$maybe_slash; if ( $check_redirect = '1/' ) { return 301 $original_uri/$is_args$args; } if ( -f $document_root$uri.php ) { rewrite ^ $uri.php last; } # this emulates 'index index.php index.html' directive behavior if ( -f $document_root$uri${maybe_slash}index.php ) { set $rewrited 1; rewrite ^ $uri${maybe_slash}index.php last; } if ( -f $document_root$uri${maybe_slash}index.html ) { set $rewrited 1; rewrite ^ $uri${maybe_slash}index.html last; } # if a request for an absent resource should be served with some backend # controller, it is ok to use some 'try_files' directive here like # try_files $uri /index.php?path=$original_uri; } location ~ .php$ { # this emulates 'try_files $uri $uri/ ...' directive behavior and redirects '/some/path' # to '/some/path/' if 'some/path.php' file does not exists, but 'some/path' folder exists # and there are 'some/path/index.php' file in that folder set $check_redirect $rewrited$maybe_slash; if ( $check_redirect = '1/' ) { return 301 $original_uri/$is_args$args; } # no 'try_files $uri =404' or 'include snippets/fastcgi-php.conf' here, this location # can be reached only if requested PHP file is really exists in webroot folder include fastcgi.conf; fastcgi_param SCRIPT_FILENAME $document_root$uri; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; } }
With this configuration and webroot structure given above
- request to
http://example.com/
would be served withwebroot/index.php
file; - request to
http://example.com/somename
would be served withwebroot/somename.php
file; - request to
http://example.com/somename.php
would be redirected tohttp://example.com/somename
and served withwebroot/somename.php
file; - request to
http://example.com/somename/
would be served withwebroot/somename/index.php
file; - request to
http://example.com/someothername
would be redirected tohttp://example.com/someothername/
(since nowebroot/someothername.php
file exists) and served withwebroot/someothername/index.php
file.
Important note about custom HTTP error pages
If you have some custom error page, for example webroot/error/404.php
for HTTP 404 error, instead of usual way to define it like
error_page 404 /error/404.php;
you’d need to skip .php
extension of that file:
error_page 404 /error/404;