.htaccess Add Trailing Slash to URL
If you are rewriting your URLs using .htaccess and mod_rewrite, you might run into a problem where trailing slashes are ignored.
Here is an example scenario. Say you have PHP script that takes query arguments like this (replace example.org with your domain, of course):
http://example.org/index.php?page=content&title=welcome
You are rewriting it to look like this:
http://example.org/content/welcome/
For reference, here’s an example .htaccess script that would do that (there are plenty of other ways, this is one basic example):
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/$ /index.php?page=$1&title=$2 [QSA,L]
And here is the problem with that! If you try a URL like this (without the trailing slash):
http://example.org/content/welcome
404! OH NOES!!
So, one alternative is to change the .htaccess directive to look like this:
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?$ /index.php?page=$1&title=$2 [QSA,L]
So now both of these URLs work!
http://example.org/content/welcome/, AND
http://example.org/content/welcome
BUT WAIT! Trailing slashes are prettier, and we don’t want two separate URLs for the same content! Google doesn’t even like that! OOOH NOOOES!!
How to force a trailing slash in the URL:
- Make your rewrites require the trailing slash, as with the first example:
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/$ /index.php?page=$1&title=$2 [QSA,L] - Add this code below your regular rewrites:
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$ RewriteRule (.*)$ http://example.org/$1/ [R=301,L]
Note: This should work no matter how your application handles URLs. Some applications, however, such as WordPress, pull in the entire URL query regardless of slashes. If your application inherently does not care about trailing slashes in its RewriteRules, then you must put these directives before your other rewrites. The reason for that is because if it goes after them, then the application’s own RewriteRule will go into effect, accepting the URL without the trailing slash, and will likely ignore any subsequent rules (because of the [L] flag). The reason I suggest in this tutorial to put the script after your normal rewrites is for optimization and that can only apply when your normal rewrites require a trailing slash. If the URL has a trailing slash, as is the desired scenario, then it should go ahead and apply the rules and not even bother looking at the redirection directive.
Another point to keep in mind is that this script will redirect and add a trailing slash even for bogus URLs. E.g. - if you type this hypothetical non-existent URL into the address bar:
http://example.org/garhtrehstreetreetree
It is going to rewrite and forward it to the following URL with a trailing slash:
http://example.org/garhtrehstreetreetree/
Before displaying the expected 404 error. Note that this is not typical behaviour of Apache server. However; I do not consider this quirk to be a big deal at all, and I believe that it is unavoidable since we are handling this with .htaccess.
Explanation of the directives and regular expressions:
The two RewriteCond lines test to make sure the requested filename is not an actual file or directory, respectively. This makes sense because we’re rewriting URLs here; the requested URLs are not actual files, they are references to actual files and query arguments.
The regular expression in the third RewriteCond does two things. It checks to make sure the requested “filename” does not have an extension. If for whatever reason it has an extension, then we probably don’t want to add a trailing slash! Note: This expression considers an extension anything that has a period followed by between 1 and 5 letters and numbers. That covers your .js and your .phtml, at least. Feel free to change the 1 and 5 to suit your application. The other thing the third RewriteCond does is make sure that the URL doesn’t already have a trailing slash. If it didn’t do that check, the redirect could attempt to loop forever and that’s annoying!
The last line, the RewriteRule, will capture the entire URL path. It then does a 301 redirect to the same URL path with a trailing slash appended.
IMPORTANT UPDATE (IMPORTANT UPDATE TO IMPORTANT UPDATE: IMPORTANT UPDATE NOW IRRELEVANT — SEE EVEN MORE IMPORTANT UPDATE): It appears that some configurations do not support lookaheads in regular expressions! I have a strong suspicion but do not know for sure that the issue is the Apache version. This tutorial should work fine for Apache 2, and may not work for Apache 1.3. That, specifically, was the case with the configurations I tested. Here is an alternative route if you are getting internal server errors with the original method:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)([^/])$ http://example.org/$1$2/ [R=301,L]
I do not think it is as pretty, but ya gotta do what ya gotta do!
EVEN MORE IMPORTANT UPDATE: After browsing the web for a minute, I came across another site that has a similar (but different) tutorial. After looking at the example therein, I metaphorically smacked my forehead and realized that a very small part of the original example (specifically, the lookahead ((?!/)) part) was not necessary, and it now works on all tested servers. The tutorial has been updated to reflect this change and is now even prettier than it was before. Thank you other person, I feel dumb now and hats off to you.
May 1st, 2008 at 3:43 am
Hi,
I used your code to solve trailing slash problem but then my function to change http://www. to non-www didn’t work. Can you help, please? (switchstories.com).
Regards
May 1st, 2008 at 9:53 am
Paul, could you paste the applicable code in here and we could have a look at it? I’m curious as well about what’s going on there…
May 1st, 2008 at 5:42 pm
Sure, Dan. My site is http://switchstories.com and the code I use is:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www.switchstories.com [NC]
RewriteRule ^(.*)$ http://switchstories.com/$1 [L,R=301]
and let’s take news section: RewriteRule ^news\/$ ?action=news_List [L]
When I installed your function http://switchstories.com/news was 301 redirected to the version with slash. But then http://www. was not redirected to non-www as I have it now.
Thanks for support.
May 1st, 2008 at 6:40 pm
Not sure if this has been tried already, but the non-www rules might have to come before the trailing slash code here (seems like it ought to catch it either way though)… Maybe it will be as simple as that? If that doesn’t work we can try another route…
May 2nd, 2008 at 4:31 pm
Doesn’t work
May 2nd, 2008 at 5:47 pm
I’ll e-mail you directly about it and see if we can find a solution…
May 26th, 2008 at 9:27 am
Dan, your solution solved the problem:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www.switchstories.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ http://switchstories.com/1/ [R=301,L]
RewriteCond %{HTTP_HOST} ^www.switchstories.com [NC]
RewriteRule (.*)$ http://switchstories.com/1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ http://switchstories.com/1/ [R=301,L]
THANKS!
May 26th, 2008 at 11:08 am
Sweet! Good to know it worked!
July 10th, 2008 at 8:35 am
how do I redirect
http://www.somesite.com/elle to
http://www.somesite.com/example.php
July 10th, 2008 at 9:04 pm
Sraboni,
This post is just about adding a trailing slash to URLs, but to point you in the right direction, you might try here, here, or otherwise try Google…
July 17th, 2008 at 8:18 am
Thanks Dan. I have done this,
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(/[a-zA-Z0-9]{1,5})\.html$
RewriteRule ^(.*)$ http://www.somesite.com/landing_page.php [L]
Its showing http://www.somesite.com/landing_page.php. its fine. But I want to show the url as
http://www.somesite.com/abc
July 17th, 2008 at 10:26 am
You might try
RewriteEngine OnRewriteBase /
RewriteRule ^abc/?$ landing_page.php [QSA,L]