How to Remove Extensions From, and Force the Trailing Slash at the End of URLs?
So I wrote a set of Rewrite rules that did what you wanted, but it completely broke my website. I realized that what you want is probably not what you need. Adding trailing slashes to the end of all URLs really messes with the semantics of the URL in that you're no longer accessing the file /foo
but the content listing of the directory /foo/
.
For example:
changing /mypage
to /mypage/
will probably break any relative links. If you reference a Javascript file <script src="myscript.js">
, instead of looking for /myscript.js
, the browser will look for /mypage/myscript.js
. You would need to change your source to read <script src="../myscript.js">
which 1) doesn't make sense to the author, and 2) looks uglier than not having trailing slashes.
For reference:
RewriteCond %{REQUEST_FILE}\.html -f
RewriteRule (.*)$ $1.html [L]
RewriteCond %{REQUEST_FILE}\.php -f
RewriteRule (.*)$ $1.php [L]
RewriteCond %{REQUEST_FILE}\.cgi -f
RewriteRule (.*)$ $1.cgi [L]
would change only php, cgi, and html extensions, but a better idea would be to use Apache2 content negotiation (with MultiViews).
Edit:
The original code. Or at least part of it. I broke it, and then cut it down to the above, and now I can't quite remember what I did. But it does everything except remove trailing extensions.
# This block adds the trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond /your/web/directory%{REQUEST_URI}\.html -f [OR]
RewriteCond /your/web/directory%{REQUEST_URI}\.php -f [OR]
RewriteCond /your/web/directory%{REQUEST_URI}\.cgi -f
RewriteRule .* %{REQUEST_URI}/ [R=301,L]
# These blocks redirect /foo/ to /foo.html and so on
RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond /your/web/directory%1\.html -f
RewriteRule (.*)/$ $1.html [L]
RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond /your/web/directory%1\.php -f
RewriteRule (.*)/$ $1.php [L]
RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond /your/web/directory%1\.cgi -f
RewriteRule (.*)/$ $1.cgi [L]
You can email me at mazin (at) aztekera.com if you'd like.
Admin
Updated on September 17, 2022Comments
-
Admin over 1 year
Example of current file structure:
example.com/foo.php example.com/bar.html example.com/directory/ example.com/directory/foo.php example.com/directory/bar.html example.com/cgi-bin/directory/foo.cgi*
I would like to remove HTML, PHP, and CGI extensions from, and then force the trailing slash at the end of URLs. So, it could look like this:
example.com/foo/ example.com/bar/ example.com/directory/ example.com/directory/foo/ example.com/directory/bar/ example.com/cgi-bin/directory/foo/
I am very frustrated because I've searched for 17 hours straight for solution and visited more than a few hundred pages on various blogs and forums. I'm not joking. So I think I've done my research.
Here is the code that sits in my .htaccess file right now:
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}\.html -f RewriteRule ^(([^/]+/)*[^./]+)/$ $1.html RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]|/)$ RewriteRule (.*)$ /$1/ [R=301,L]
As you can see, this code only removes .html (and I'm not very happy with it because I think it could be done a lot simpler). I can remove the extension from PHP files when I rename them to .html through .htaccess, but that's not what I want. I want to remove it straight. This is the first thing I don't know how to do.
The second thing is actually very annoying. My .htaccess file with code above, adds
.html/
to every string entered afterexample.com/directory/foo/
. So if I enterexample.com/directory/foo/bar
(obviously/bar
doesn't exist sincefoo
is a file), instead of just displaying message that page is not found, it converts it toexample.com/directory/foo/bar.html/
, then searches for a file for a few seconds and then displays the not found message. This, of course, is bad behavior.So, once again, I need the code in .htaccess to do the following things:
- Remove .html extension
- Remove .php extension
- Remove .cgi extension
- Force the trailing slash at the end of URLs
- Requests should behave correctly (no adding trailing slashes or extensions to strings if file or directory doesn't exist on server)
- Code should be as simple as possible
@Kronbernkzion excellent. The only issue I'm having now is 404's don't seem to work right and leads me to a real funky place, I can't even use an absolute 404 redirect.
ErrorDocument 404 http://www.google.com
Did you come across this? How did you get past it?
Aside from the 404 rewrite, the full code I've used was:
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_URI} (.*)/$ RewriteCond %{REQUEST_FILENAME}\.html -f RewriteRule (.*)/$ $1.html [L] RewriteCond %{REQUEST_URI} (.*)/$ RewriteCond %{REQUEST_FILENAME}\.php -f RewriteRule (.*)/$ $1.php [L] RewriteCond %{REQUEST_URI} (.*)/$ RewriteCond %{REQUEST_FILENAME}\.cgi -f RewriteRule (.*)/$ $1.cgi [L] RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}\.html -f [OR] RewriteCond %{REQUEST_FILENAME}\.php -f [OR] RewriteCond %{REQUEST_FILENAME}\.cgi -f RewriteRule .* %{REQUEST_FILENAME}/ [R=301,L] </IfModule>
-
Admin about 14 yearsI feel your pain
-
Admin about 14 yearsQuestion: Does these rewrite rules need to match ALL Extensions? For example, if you have
/foo.html
and/bar.php
, are you going to have a rule that explicitly matches/foo/
to/foo.html
and/bar/
to/bar.php
? Or do you need a single generic entry that will match/foo/
to both/foo.html
OR/foo.php
(depending on which one exists)? -
Admin about 14 yearsI need a single generic entry. Nothing file specific, I just want to remove extensions from those three file types.
-
Admin about 14 years@Kronbernkzion, I've updated my answer. I don't think you'll like what it says though.
-
Admin about 12 yearsThere's not real reason to use a trailing slash. Look at zendesk.com who uses wordpress, they have configured their permaliks to not use a trailing slash. I've also used the same setup on a few domains and Google crawls them just fine, and they look better IMHO than with a trailing slash. I'd upgrade to WP if you can and just setup 301's from your old static or dynamic pages to the new WP pages.
-
Sean about 14 yearsI will not have duplicate filenames, so there will never be foo.html and foo.php, so Apache won't need to decide which file should be served.
-
Sean about 14 yearsResponse to your edit: Again, all I need it to do is remove every .html, .php and .cgi extension and then add a trailing slash afterwords. I have no doubt that this can be done. I know it can easily be done through PHP file, and I know a lot of people prefer this method, but I want to do it through .htaccess.
-
Mark Henderson about 14 yearsWhether or not there are duplicate filenames or not is irrelevant. Apache will not know which one you even MEAN, let alone serve it. You will need a system with some intelligence that you can program your rules into, so that it knows which content to serve. That option is PHP or ASP. This is what we did when we were in a similar situation. We funneled EVERY request into a single .php file, which then acted as our proxy. The PHP file would then query each version of the URL until it found one that did not return a status 404, and it then served that content out to the browser.
-
Mark Henderson about 14 yearsSorry, just saw your comment - must have been written whilst I was writing mine. This cannot be done by .htaccess - it's simply a too complex task for its simple rewriting engine to do.
-
Sean about 14 yearsSo you're saying that it can only process one file type extension. It can only be .html or only .php, it can't do both? Are you sure about that?
-
Mark Henderson about 14 yearsAhhh, you know what? I think maybe Mazin's answer might be on track. Let me know how you go with his, he may have taken an angle that I hadn't thought of.
-
styks about 14 yearsI know exactly what I need. Esthetics and functionality of trailing slashes in URLs is topic for itself, so we won't go into that. No worry about breaking links because I am in process of building website from scratch.
-
styks about 14 yearsWhat would you add to the code above to force trailing slashes at the end of URLs?
-
styks about 14 yearsOK, I added most of what I had. I still think you're going down the wrong path by forcing trailing slashes given that it breaks the path semantics, but you seem pretty determined.
-
Admin about 14 yearsAs I already said above, I am not interested in doing it with PHP.