Search code examples
apache.htaccesshttp-redirectmod-rewrite

Apache htaccess force lowercase and remove trailing slash


I am trying to redirect all URLs to lowercase and remove trailing slashes.

My htaccess file currently looks like this:

<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteCond expr "tolower(%{REQUEST_URI}) =~ /(.*)/"
    RewriteRule [A-Z] %1 [R=308,L]

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [R=308,L]
</IfModule>

This does work, however it does two redirects one after another. First redirect forces lowercase and the second redirect removes the trailing slash.

How can I merge these two rules into one redirect?


Solution

  • You don't need to actually merge the two rules in order to reduce the number of redirects. You can reverse the order of the two rules and always convert the URL to lowercase in the rule that removes the trailing slash.

    For example:

    # Remove trailing slash AND convert to lowercase
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond expr "tolower(%{REQUEST_URI}) =~ m#(.+)/$#"
    RewriteRule /$ %1 [R=308,L]
    
    # Convert remaining URLs to lowercase
    RewriteCond expr "tolower(%{REQUEST_URI}) =~ /(.*)/"
    RewriteRule [A-Z] %1 [R=308,L]
    

    A potential problem with combining the two rules (without adding additional complexity) is that you avoid converting URLs to lowercase that map to directories (which may or may not be an issue), since you can only remove the trailing slash on non-directories.

    Note that I used the alternative regex-syntax in the first rule (formerly the second rule) in order to avoid having to escape literal slashes in the regex. The RewriteRule pattern can also be simplified now, since we only need to assert that the URL ends in a trailing slash.

    Note that you should remove the <IfModule> wrapper if these directives are mandatory.