How to stop .htaccess loop

10,552

The rule-set ends up in a loop. Let's see:

The request is http://localhost/Test/TestScript.php is redirected to http://localhost/Test/TestScript/, for the browser to show it, and finally is trying to be mapped back to the original resource.

The [L] flag in the rule doesn't stop the process, as many people think. The rewriting engine loops through the complete rule-set, rule by rule, and when a particular rule matches, it loops through the corresponding conditions, if any. As this process is repeated for each request and rules generate new requests, it is easy to enter an infinite loop.

That's what the message "The page isn't redirecting properly" means in this case.

Here are The Technical Details of this process

Some solutions:

I) The best and more practical one is to use directly the "pretty" URL in the initial request, mapping it silently to the resource. This is a one step process where the "pretty" URL is always displayed in the browser's address bar. One of the advantages of this option, is that nothing in the URI-path of the incoming URL has to exist.

  1. Request: http://localhost/Test/TestScript/
  2. Mapped internally to resource: http://localhost/Test/TestScript.php
Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /
# Prevent loops
RewriteCond %{REQUEST_URI} !\.php  [NC]
# Map internally to the resource, showing the "pretty" URL in the address bar
RewriteRule  ^([^/]+)/([^/]+)/?   /$1/$2.php  [L,NC]

II) If that's not possible because there are already links pointing directly to the resource, one way to show the "pretty" URL but still get the data from the original request, is to make a visible and permanent redirect first, stripping the extension to display the "pretty" URL, and then an internal rewrite back to the original resource.

  1. Request: http://localhost/Test/TestScript.php,
  2. Permanent and visible redirect to: http://localhost/Test/TestScript/ the "pretty" URL,
  3. Internal and silent mapping back to: http://localhost/Test/TestScript.php, the original request.
Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /

# Get the URI-path directly from THE_REQUEST variable
RewriteCond %{THE_REQUEST} ^(GET|HEAD)\s/([^/]+)/([^.]+)\.php [NC]
# Strip the extension and redirect permanently
RewriteRule  .*   /%2/%3/   [R=301,L,NC]

# Now the browser bar shows `http://localhost/Test/TestScript/`

# Prevent loops
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !\.php  [NC]
# Map internally to the original resource
RewriteRule  ^([^/]+)/([^/]+)/?   /$1/$2.php  [L,NC]

NOTES:

  1. The above options are to be placed in one .htaccess file at root directory, making sure mod_rewrite is enabled.
  2. Strings Test and TestScript are assumed to be dynamic and can be replaced with any name.
  3. Host name localhost is an example and can also be replaced with any other name.
Share:
10,552
Felipe Alameda A
Author by

Felipe Alameda A

Senior hardware designer. Firmware, software and web developer at ZSControl

Updated on June 28, 2022

Comments

  • Felipe Alameda A
    Felipe Alameda A almost 2 years

    I am not expert in htaccess files and I am trying something that seems very simple but I have not been able to do it.

    I searched and finally find something here could work for my use but it didn't. The code is below.

    Here is an example of what i need:

    http://localhost/Test/TestScript.php to show this: http://localhost/Test/TestScript/ with script in original place.

    These are my rules (Copied):

    Options +FollowSymLinks -MultiViews
    # Turn mod_rewrite on
    RewriteEngine On
    RewriteBase /Test
    
    ## hide .php extension
    # To externally redirect /dir/foo.php to /dir/foo
    RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
    RewriteRule ^ %1 [R,L,NC]
    
    ## To internally forward /dir/foo to /dir/foo.php
    RewriteCond %{REQUEST_FILENAME}.php -f
    RewriteRule ^ %{REQUEST_FILENAME}.php [L]
    

    This rule give:

    Forbidden You don't have permission to access ".../Test/TestScript.php on this server."

    So changed last line to:

    RewriteRule ^.*  http://localhost/Test/TestScript.php  [L]
    

    But now get this error:

    The page isn't redirecting properly

    Hope brilliant people in this place can help me. Thank you.

  • Admin
    Admin over 11 years
    It is redirecting. Too much I guess. Thanks.
  • Admin
    Admin over 11 years
    Excellent Felipe. Now understand, took me some minutes but I see the problem. Your 2 suggestions are good, do not know which I pick but tested this and works perfect. No problem. Thank you, thank you many times. Lia