5

i know this is a very common topic but none of the solutions works for me. i have tried several answers:

answer 1

answer 2

answer 3

and the referal links.

The htaccess code that i am using:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)\.html$ /$1 [L,R=301] 

then i changed my links from services.html to services i.e. i removed the extension and also removed the extension from the file name using ftp.

what i get is the page code displayed in my browser not the actual page.

I have checked mod_rewrite on my server and it works correctly using this code

RewriteEngine On
Options +FollowSymLinks
RewriteRule ^joomla\.html http://www.joomla.org/? [R=301,L]
Community
  • 1
  • 1
xbass540
  • 319
  • 1
  • 3
  • 14
  • how is your original link looks like? – Abhishek Gurjar Aug 22 '16 at 11:35
  • I think what you want is enter `domain.tld/test` in your browser, but this should rewrite to `domain.tld/test.html` internally (without showing it to the user, i.e. without changing it in the browser's address bar)? And I guess you also want to redirect `domain.tld/test.html` to `domain.tld/test`? I'll write an answer on how to do that. – Simon Hänisch Aug 22 '16 at 13:21

2 Answers2

14

Your file should still have the .html extension on the server, otherwise the server/browser won't interpret it as html but text instead (which is the reason you see the code in your browser). So rename the files on your server using ftp again.

In order to let your server serve the file /test.html when the url /test is accessed, you want to rewrite that internally, i.e.:

RewriteRule ^test[^/]$ test.html

The ^ is to match the start of the string, the $ matches the end, so this will only rewrite if the url exactly matches test. It will rewrite that request to test.html. The rewrite is internal, this means it won't redirect the browser (the url in the address bar doesn't change). There is also the external rewrite ([R] appended to the rule), which redirects the browser.

This rule also only matches urls that don't end with a trailing slash ([^/] means "not slash"). We will handle urls with a trailing slash later.

You could create a custom RewriteRule for each page that you want to rewrite:

RewriteRule ^foo[^/]$ foo.html
RewriteRule ^bar[^/]$ bar.html

This is a lot of work if you have many pages, so you may want to rewrite all urls, e.g. foo or bar should be rewritten to foo.html / bar.html, and foo/bar should be rewritten to foo/bar.html.

You can also use a regular expression to match all requests. But you should first check if foo isn't actually a directory (which could contain a index.html and be a sub-directory you want to serve). Also you want to check if foo isn't really a file on your server's file system. There are two rewrite conditions to check that (see the RewriteCond directive):

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

Now you can add a rewrite rule for all requests:

RewriteRule ^(.+[^/])$ $1.html

$1 is the content of the first capture group, a capture group in a regex is an expression placed in () brackets. . matches any character, the + modifier means "one or more".

Note that this would cause a rewrite loop resulting in a 500 error (see this answer), so you need to also add a rewrite condition to check if the <request>.html file actually exists on the file system:

RewriteCond %{REQUEST_FILENAME}.html -f

Also you might not want to rewrite urls that already have a .html extension. I don't think it's necessary, as you already have the rule above which would in that case check for <file>.html.html which probably shouldn't exist. But if you have to deal with that, you could add another condition:

RewriteCond %{REQUEST_FILENAME} !^.+\.html$

So putting it altogether your rewrite rule looks like this:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !^.+\.html$ # not really necessary
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+[^/])$ $1.html

The only thing that you need to handle now are urls that have a trailing slash. For that we just add a simple external rewrite rule that removes the trailing slash if the url doesn't actually match a directory:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]

This rule matches only urls that end with / (regex /$) and captures everything before the trailing slash as a group (regex (.+)), then redirects to the group (which doesn't contain the slash). Notice the R and L flags behind the rule. R is for redirect, which redirects the browser (url in address bar changes). L is for last, meaning no other rules will be applied after this one, though rules will be applied again after the rewrite, and this is where the other rule gets applied.


TL;DR

RewriteBase /

# handle trailing slashes (if not a directory)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]

# rewrite rule that internally adds the .html extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+[^/])$ $1.html
Simon Hänisch
  • 4,740
  • 2
  • 30
  • 42
0

like @simon suggested the correct file is:

# handle trailing slashes (if not a directory)
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.+)/$ $1 [R,L]

# rewrite rule that internally adds the .html extension

RewriteCond %{REQUEST_FILENAME} !-d

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME}.html -f

RewriteCond %{REQUEST_FILENAME} !^.+\.html$

RewriteRule ^(.+[^/])$ $1.html

also i had to delete all text files with the same name from the server through ftp.

xbass540
  • 319
  • 1
  • 3
  • 14
  • @simonHanisch i discovered a falback of the above file regarding the fix about slashes (if not a directory). When i hit example.com/services/ it redirects me to example.com/home/myftpuser/public_html/services and i get 404 error – xbass540 Aug 23 '16 at 16:08
  • can you try `RewriteBase /`? If you work with symbolic links you may also need `Options +FollowSymLinks`... also have a look at the difference between `REQUEST_FILENAME` and `REQUEST_URI`. – Simon Hänisch Aug 24 '16 at 07:08
  • @simon Hanisch : RewriteBase / worked like a charm. thanks Simon – xbass540 Aug 24 '16 at 08:40
  • alright. keep in mind that if you move your page to a subfolder like `domain.tld/my-site/`, you need to set `RewriteBase /my-site/`. glad I could help – Simon Hänisch Aug 24 '16 at 08:55