Skip to content
Advertisement

How redirect from /file.php to /file on nginx?

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 with webroot/index.php file;
  • request to http://example.com/somename would be served with webroot/somename.php file;
  • request to http://example.com/somename.php would be redirected to http://example.com/somename and served with webroot/somename.php file;
  • request to http://example.com/somename/ would be served with webroot/somename/index.php file;
  • request to http://example.com/someothername would be redirected to http://example.com/someothername/ (since no webroot/someothername.php file exists) and served with webroot/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;
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement