Markus Kottländer
Markus Kottländer

Reputation: 8268

mod_rewrite omit html extension loop

I have the following scenario:

Two frontcontrollers in a web directory (document root):

web/frontend.php # handles all *.html requests
web/backend.php # direct calls only

Rewriting is easy so far:

RewriteCond %{REQUEST_URI} !^/backend.php
RewriteRule (.+)\.html$ /frontend.php [L]

So now when I call example.org/backend.php I'm in the backend, nothing special happens. And when I call something like example.org/ or example.org/team/john.html it is handled by frontend.php.

Works so far!

Now I want the possibility to omit the *.html extension so that example.org/team/john is internally handled as example.org/team/john.html.

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_URI}.html [L]

Last but not least I want to redirect requests to john.html to john to avoid duplicate content.

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} ^(.+)\.html$
RewriteRule (.*)\.html$ /$1 [R=301,L]

Every part works on it's own but put together I get a loop, which doesn't surprise me but I don't know how to avoid this. I searched the docs, tried several flags and conditions but I'm totally stuck and I need help.

Here is the whole .htaccess file:

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteBase /

    # extend html extension internally
    RewriteCond %{REQUEST_FILENAME}.html -f
    RewriteRule !.*\.html$ %{REQUEST_URI}.html [L]

    # redirect example.html to example
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteCond %{REQUEST_URI} ^(.+)\.html$
    RewriteRule (.*)\.html$ /$1 [R=301,L]

    # frontcontroller
    RewriteCond %{REQUEST_URI} !^/backend.php
    RewriteRule (.+)\.html$ /frontend.php [L]
</IfModule>

Any help would be great.

Upvotes: 0

Views: 60

Answers (2)

Amit Verma
Amit Verma

Reputation: 41229

The loop is because of the multiple internal redirections, You can use END flag to prevent the rewrite loop

RewriteRule ^(.+)\.html$ /$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_URI}.html [END]

Upvotes: 1

Olaf Dietsche
Olaf Dietsche

Reputation: 74078

To avoid a loop, you can use THE_REQUEST

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteCond %{THE_REQUEST} "\.html "
    RewriteRule ^(.*)\.html$ /$1 [R,L]

Unrelated, but you can simplify your rules. First one

RewriteCond %{REQUEST_URI} !^/backend.php
RewriteRule (.+)\.html$ /frontend.php [L]

You already check for (.+)\.html, so you can omit the RewriteCond. Next, you don't use the captured part (.+). Replace it with . to ensure it's not empty. This gives then

RewriteRule .\.html$ /frontend.php [L]

Second one, unless you have *.html.html files in your site, you don't need to check for !html and can just use ^ for the RewriteRule pattern

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [L]

Upvotes: 1

Related Questions