.htaccessmod-rewritetrailing-slash

htaccess - Add trailing slash at the end of URL


Currently, file extension .php is removed correctly from my URL. But the URLs are available without trailing slash under www.example.com/thema and with trailing slash under www.example.com/thema/.

Content of my .htaccess file:

DirectoryIndex index.php

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    RewriteCond %{HTTP_HOST} !^www\.example\.com$
    RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]

    # redirect file.php to /file/
    RewriteCond %{THE_REQUEST} \s/+(.+?)\.php\s [NC]
    RewriteRule ^ /%1/ [R=302,NE,L]

    # added .php extension to /file by checking presence of file.php
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{DOCUMENT_ROOT}/$1.php -f
    RewriteRule ^(.+?)/?$ $1.php [L]
</IfModule>

Can You please give me some advice what needs to be changed that following points match:


Solution

  • RewriteCond %{HTTP_HOST} !^www\.example\.com$
    RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
    

    You should be redirecting to https in this rule, not http. (The presence of http in this rule will result in an additional redirect, since the first rule will then redirect you back to https.)

    You can then add another rule following this that appends the trailing slash:

    # Append trailing slash
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^.+[^/]$ /$0/ [R=301,L]
    

    The $0 backreference contains the entire match from the RewriteRule pattern (ie. the entire URL-path, less the slash prefix).

    Homepage should be available only under www.example.com (w/o trailing slash)

    There is always a slash at the start of the URL-path (ie. immediately after the hostname). You have no control over this (it is required to make a valid HTTP request). However, whether that is displayed in the browser's address bar is another matter - most browsers omit it, but that's just aesthetics (the same way browsers tend to omit the www. subdomain and the request scheme, ie. http and https, and even the query string in some cases, from the visible URL).

    See this question on the Webmasters SE site for more information: https://webmasters.stackexchange.com/questions/35643/is-trailing-slash-automagically-added-on-click-of-home-page-url-in-browser


    Aside:

    # redirect file.php to /file/
    RewriteCond %{THE_REQUEST} \s/+(.+?)\.php\s [NC]
    RewriteRule ^ /%1/ [R=302,NE,L]
    

    This may or may not be an issue, but this rule will fail if the request, that contains a .php extension, also includes a query string. To resolve that and remove the .php extension regardless of whether a query string is present or not then you could do the following instead:

    # redirect file.php to /file/
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule (.+)\.php$ /$1/ [NC,R=302,L]
    

    Any query string on the initial request is preserved.

    (NB: This should ultimately be a 301, once you have confirmed it works as intended.)

    # added .php extension to /file by checking presence of file.php
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{DOCUMENT_ROOT}/$1.php -f
    RewriteRule ^(.+?)/?$ $1.php [L]
    

    The first condition (RewriteCond directive) is superfluous and should be removed, unless you also happen to have directories of the same name as the .php file basename and accessing the directory should take priority? (This seems very unlikely, since it would also make the .php file inaccessible from HTTP requests.)


    However, in order to minimise the number of redirects (not that that should necessarily be an issue here) you would need to reorder the directives and use absolute URLs in the redirects discussed above. I'm also assuming you are not implementing HSTS.

    For example:

    DirectoryIndex index.php
    
    RewriteEngine On
    
    # redirect file.php to /file/ (www + HTTPS)
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule (.+)\.php$ https://www.example.com/$1/ [NC,R=301,L]
    
    # Append trailing slash to non-files (www + HTTPS)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^.+[^/]$ https://www.example.com/$0/ [R=301,L]
    
    # Non-www to www (and HTTPS)
    RewriteCond %{HTTP_HOST} !^www\.example\.com$
    RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
    
    # HTTP to HTTPS remaining URLs
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    
    # added .php extension to /file by checking presence of file.php
    RewriteCond %{DOCUMENT_ROOT}/$1.php -f
    RewriteRule ^(.+?)/?$ $1.php [L]
    

    I removed the the <IfModule> wrapper, since that is not required here (it would only serve to mask any errors if mod_rewrite is not installed).