Welcome to WebmasterWorld Guest from

Forum Moderators: Ocean10000 & incrediBILL & phranque

Message Too Old, No Replies

[L] only working for non-rewrites?



5:20 pm on Apr 16, 2011 (gmt 0)

5+ Year Member

I've been messing around with what I thought would be a very simple htaccess file (given that I have a decent knowledge of regex) for a long time, and I finally got it working by doing something I expected to be pointless. The recurring problem was that the [L] flag was not stopping the rewriting process. ie, one rule with the last flag would match a url and rewrite it, and then the next rule would match the url that request was rewritten to and rewrite it again.

The only solution I've found is to add in another rule which matches the url the first rule rewrites to, does not modify it, and also has the [L] flag. Here is the complete file - the "INTERNAL REDIRECTS" section should be the only one you need to look at, but since I'm no apache guru I'm not sure that the rest of the code isn't having effects I don't know about.

ErrorDocument 403 /error/403.html
ErrorDocument 404 /error/404.html
ErrorDocument 500 /error/500.html

RewriteEngine on

RewriteRule \.ini$ - [F]
RewriteRule (/|^)\.ht(access|passwd|group)$ - [F]

RewriteCond %{HTTP_HOST} !^(example\.com)?$
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

RewriteCond %{QUERY_STRING} ^$
RewriteRule ^(s/|(index\.php)?$) - [L]
RewriteRule ^.+?/.+ details.php [L]
RewriteRule details.php - [L]
RewriteRule ^[^/]+$ list.php [L]

The intent (and effect) is to pass through requests for the index page or anything in the /s directory, rewrite everything 2 levels deep (example.com/category/item) to details.php, and rewrite everything 1 level deep (example.com/category) or 0 but with a query string (example.com/?price=10-30) to list.php.

The line matching /s and the index effectively stops execution yet the next line does not (the file fails if the line after that is removed). Why? Does [L] only work for rules that don't do anything (rewrite to "-")?


8:25 pm on Apr 25, 2011 (gmt 0)

WebmasterWorld Senior Member jdmorgan is a WebmasterWorld Top Contributor of All Time 10+ Year Member

Due to being executed in the Apache API "fix-up" phaae, mod_rewrite processing is recursive, so [L] only stops processing for this pass through the code.

Using [L] is still worthwhile, since only the last pass through the code will need to process all of the rules (The [L] flag is only applied if the entire rule matches, and so is never applied on the last pass, when no rule matches).

Therefore, all .htaccess mod-rewrite recursion must be explicitly prevented, either by excluding rewrite target paths, or by using %{REDIRECT_STATUS} or %{REQUEST_URI} in rewritconds to see if this request has already been rewritten.

It still appears that "list.php" rewriting will recurse.

Consider using a "wider" exclusion pattern and scope, such as excluding all .php requests (and the others) from being rewritten right a the top. Consider moving the single-rule-specific exclusions into rewriteconds, rather than using a preceding "quit if" rule. Remember that rewriteconds are not processed unless the rewriterule pattern matches. This can be used to eliminate unnecessary processing.



7:06 pm on Apr 27, 2011 (gmt 0)

5+ Year Member

Hi Jim, thanks for your response, it's just what I was missing. I rewrote the "internal redirects" section according to your help and guidelines and it works flawlessly. And I know it's an improvement since it reads like the description of my first attempt. Here's my new code:
RewriteCond %{REQUEST_URI} ^/.+/
RewriteRule !^s/ details.php [L]
RewriteCond %{QUERY_STRING} . [OR]
RewriteCond %{REQUEST_URI} ^/[^/]+$
RewriteRule !\.php$ list.php

My only concern is that requests for example.com/s/resource.jpg?params will be rewritten to list.php. What I need is the equivalent of if((A and B) or C), but I don't know how to do that in apache.

Also, I looked at my previous code again and it looks to me like you're right, list.php recurses indefinitely. However, I tested it and for some reason it works fine. And speaking of things I don't understand, why does a request for a directory appear as both a null string and the default string (index.*)? It behaves as if it runs the file twice, once with the directory request (example.com/category/) and once with an index request (example.com/category/index.html).


7:20 pm on Apr 27, 2011 (gmt 0)

WebmasterWorld Senior Member g1smd is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

I guess that happens because folder requests are internally rewritten to add the index filename to the internal pointer (from the DirectoryIndex index.php directive or from an internal rewrite) and the rules are then tested again to see if any further actions are required.


7:27 pm on Apr 27, 2011 (gmt 0)

5+ Year Member

That makes sense, and it's not too hard to account for. It just seems to me like there should be a set execution order, not just keep going until there's nothing left to do.


7:29 pm on Apr 27, 2011 (gmt 0)

WebmasterWorld Senior Member g1smd is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

Yes, it keeps going until there are no rules left to match.

That's why the [L] flag is so important, in order to stop processing if THIS rule was matched.


7:40 pm on Apr 27, 2011 (gmt 0)

5+ Year Member

Well, of this pass anyway, as jdMorgan just informed me. But I was thinking (hoping) the index rewrite would be on some other level of processing and therefore not subject to this somewhat inefficient process. I don't really have a question (about this part) any more, I'm just complaining :p

Featured Threads

Hot Threads This Week

Hot Threads This Month