Mod_Rewrite unexpected behavior L flag
You are missing an important fact about the L
flag:
It is therefore important, if you are using
RewriteRule
directives in one of these [.htaccess
,<Directory>
] contexts, that you take explicit steps to avoid rules looping, and not count solely on the [L] flag to terminate execution of a series of rules
From: L|last (Flag); bold by me
That means, only by using the L
does not have your desired effect to prevent the interal redirect. The INTERNAL REDIRECT
happens here because it must happen, you have specified it with your .htaccess
configuration. The L
flag is not the right flag to prevent the INTERNAL REDIRECT
.
Let's look closer at your question and what actually happens:
I can't understand it because I've placed the [L] flag just to ensure that the mod_rewrite stops.
Is just that you have the wrong undestanding of the L
flag. It will only stop for the current rewriting, meaning, the RewriteRule
directives beneath it are not going to be processed in the current round (the inner loop).
If the URI changed L
will re-inject into the the next round (the outer loop) as the following technical details flowchart shows:
To highlight where the L
flag kicks in and where the INTERNAL REDIRECT
happens, this is the same graphic with some annotations for your specfic (first) URI rewrite:
It shows that the L
flag only exits the inner loop but if the URI has been rewritten (changed) - as in your case - the outer loop takes care that the changed URI will be passed again to all your rewrite rules.
Instead you might want to formulate a condition as the following example from that part of the manual shows:
RewriteBase /
RewriteCond %{REQUEST_URI} !=/index.php
RewriteRule ^(.*) /index.php?req=$1 [L,PT]
(PT
has it's own manual entry, is is more or less not part of the solution, just noting because I quoted the example as-is)
What you actually want to use is the END
flag:
RewriteRule css css.php [END,NC]
However contact your system administrator if you have the needed apache version for it (Available in 2.3.9 and later). If not, you need to operate with RewriteCond
.
hakre's answer illustrates well what is happening. Besides using the END
flag you have a few more options:
-
Use
%{ENV:REDIRECT_STATUS}
to prevent any further rewrites. This will change after an internal redirect. See this page for more information what is actually happening:RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule css css.php [L,NC]
-
Use
%{THE_REQUEST}
to match against the request that was made to the server. Since this does not change when you internally redirect, this can be used to prevent further redirectsRewriteCond %{THE_REQUEST} ^(GET|POST)\ /css\ HTTP RewriteRule ^ css.php [L,NC]
-
Use a dummy variable in the query string. This would allow to prevent redirecting by defining this variable in a link, but we will use it here to prevent multiple passes:
RewriteCond %{QUERY_STRING} !noredir=1 RewriteRule css css.php?noredir=1 [L,QSA,NC]
Please note that for each of these examples you need to use this construction for each individual rule.