Apache RewriteRule [L] flag ignored - apache

I'm trying to configure Apache rewrite rules. My website directory contains three files
index.html
index2.html
index3.html
I'm using these Apache rewrite rules:
RewriteRule index.html /index2.html [R=301,L]
RewriteRule index2.html /index3.html [R=301,L]
According to Apache's documentation about the [L] option:
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed.
So when I request index.html I would expect index2.html to be served. However the request for index.html ends up in index3.html. Shouldn't the [L] option stop the processing of the second RewriteRule?
I'm using Apache version is 2.4.39 (Fedora). A similar question was asked here.

I realized that the rules in .htaccess are processed on every request. A number actions take place when I access http://www.example.com/index.html :
.index.html is requested
The first rule in .htaccess is processed. It matches index.html and redirects to index2.html. [L] stops processing subsequent rules
index2.html is requested
The first rule in .htaccess is processed. It fails to match index.html so the flags [R=301,L] are not applied
The second rule in .htaccess is processed. It matches index2.html and redirects to index3.html. [L] stops processing subsequent rules
I found two possible solutions:
Move the rewrite rules from /var/www/html/.htaccess to /etc/httpd/sites-available/example.com.conf. Unlike .htaccess which is processed on every request, example.com.conf is processed only once -- when the server is started.
Leave the rules in .htaccess but use [END] flag instead of [L].
The advantage of the first solution is that the rules are processed only one time.

Related

mod_rewrite rule matched, but chain is not left

please help me to find a solution for this behavior which is very strange to me.
Here is my htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^emltr\.gif$ aaa.html [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>
Note the L flag, so I would say that when "gif" rule is matched the chain is left.
But it is not.
The requested URL is "emltr.gif"
If the "catch-all" rule and conditions are commented, then the "gif" rule is correctly taken. ("aaa.html" does not exists, this is a test to prevent unwanted circular behavior.)
If the "catch-all" rule is uncommented, then IT is taken, rather than the first rule. Why is the second one taken rather than the first? Or else: why isn't the chain left even though the L flag, and then second rule is evaluated?
Thank you
This is documented in the manual L|last
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed.
If you are using RewriteRule in either .htaccess files or in <Directory> sections, ... The simplified form of this is that once the rules have been processed, the rewritten request is handed back to the URL parsing engine to do what it may with it. It is possible that as the rewritten request is handled, the .htaccess file or section may be encountered again, and thus the ruleset may be run again from the start. Most commonly this will happen if one of the rules causes a redirect - either internal or external - causing the request process to start over.
An alternative flag, [END], can be used to terminate not only the current round of rewrite processing but prevent any subsequent rewrite processing from occurring in per-directory (htaccess) context. This does not apply to new requests resulting from external redirects.
In short, when you have rewrite rules in an .htaccess file or inside a Directory directive, the request will be processed again, if it was rewritten by this round. Only when there is no more rewrite, it will stop.

mod_rewrite rule is ignored with Wordpress

I am trying to use mod_rewrite to redirect all requests to a certain directory to a specific page:
RewriteEngine On # Turn on rewriting
RewriteRule /about/(.*) /wp-content/themes/twentyfiteen/test.php
From here I plan to get the requested URI and serve up the appropriate page.
But it seems that this rule does not even get triggered.
Thanks
URI's that are sent through rewrite rules in an htaccess file have the leading slash removed, so you can't match /about/, you need to remove the leading slash:
RewriteEngine On
RewriteRle ^about/(.*)$ /wp-content/themes/twentyfiteen/test.php [L]

Why does mod_rewrite ignore my [L] flag?

This is my .htaccess file. It should deliver static files from assets folder if the url matches them. Otherwise, everything should be redirected to index.php.
Note that the url doesn't contain assets as segemnt here. So example.com/css/style.css directs to assets/css/style.css.
RewriteEngine on
# disable directory browsing
Options -Indexes
# static assets
RewriteCond %{DOCUMENT_ROOT}/assets/$1 -f
RewriteRule ^(.*)$ assets/$1 [L]
# other requests to index.php
RewriteRule !^asset/ index.php [L]
Unfortunately, urls like example.com/assets/css/style.css also deliver the file, since for that url none of my rules applies and Apache's default behavior is applied which delivers the file.
So I tried changing the last line to this. I thought that this would work since the [L] flag in the rule above should stop execution for asset urls and deliver them.
RewriteRule ^(.*)$ index.php [L]
Instead, not all requests are redirected to index.php, even static assets like example.com/css/style.css. Why does the flag not stop execution of rewrite rules and who to fix my problem then?
I found the solution on the pages of the official documentation.
If you are using RewriteRule in either .htaccess files or in
sections, it is important to have some understanding of
how the rules are processed. The simplified form of this is that once
the rules have been processed, the rewritten request is handed back to
the URL parsing engine to do what it may with it. It is possible that
as the rewritten request is handled, the .htaccess file or
section may be encountered again, and thus the ruleset may be run
again from the start. Most commonly this will happen if one of the
rules causes a redirect - either internal or external - causing the
request process to start over.
It is therefore important, if you are using RewriteRule directives in
one of these 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, as shown below.
An alternative flag, [END], can be used to terminate not only the
current round of rewrite processing but prevent any subsequent rewrite
processing from occurring in per-directory (htaccess) context. This
does not apply to new requests resulting from external redirects.
To fix my problem, I changed to [L] flags to [END].
RewriteEngine on
# disable directory browsing
Options -Indexes
# static assets
RewriteCond %{DOCUMENT_ROOT}/assets/$1 -f
RewriteRule ^(.*)$ assets/$1 [END]
# other requests to index.php
RewriteRule !^asset/ index.php [END]

How to prevent mod_rewrite from rewriting URLs more than once?

I want to use mod_rewrite to rewrite a few human-friendly URLs to arbitrary files in a folder called php (which is inside the web root, since mod_rewrite apparently won't let you rewrite to files outside the web root).
/ --> /php/home.php
/about --> /php/about_page.php
/contact --> /php/contact.php
Here are my rewrite rules:
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^$ php/home.php [L]
RewriteRule ^about$ php/about_page.php [L]
RewriteRule ^contact$ php/contact.php [L]
However, I also want to prevent users from accessing files in this php directory directly. If a user enters any URL beginning with /php, I want them to get a 404 page.
I tried adding this extra rule at the end:
RewriteRule ^php php/404.php [L]
...(where 404.php is a file that outputs 404 headers and a "Not found" message.)
But when I access / or /about or /contact, I always get redirected to the 404. It seems the final RewriteRule is applied even to the internally rewritten URLs (as they now all start with /php).
I thought the [L] flag (on the first three RewriteRules) was supposed to prevent further rules from being applied? Am I doing something wrong? (Or is there a smarter way to do what I'm trying to do?)
[L] flag should be used only in the last rule,
L - Last Rule - Stops the rewriting process here and don’t apply any more rewriting rules & because of that you are facing issues.
I had similar problem. I have a content management system written in PHP and based on Model-View-Control paradigm. The most base part is the mod_rewrite. I've successfully prevent access to PHP files globally. The trick has name THE_REQUEST.
What's the problem?
Rewriting modul rewrites the URI. If the URI matches a rule, it is rewritten and other rules are applied on the new, rewritted URI. But! If the matched rule ends with [L], the engine doesn't terminate in fact, but starts again. Then the new URI doesn't more match the rule ending with [L], continues and matches the last one. Result? The programmer stars saying bad words at the unexpected 404 error page. However computer does, what you say and doesn't do, what you want. I had this in my .htaccess file:
RewriteEngine On
RewriteBase /
RewriteRule ^plugins/.* pluginLoader.php [L]
RewriteCond %{REQUEST_URI} \.php$
RewriteRule .* index.php [L]
That's wrong. Even the URIs beginning with plugins/ are rewritten to index.php.
Solution
You need to apply the rule if and only if the original - not rewritten - URI matches the rule. Regrettably the mod_rewrite does not provide any variable containing the original URI, but it provides some THE_REQUEST variable, which contains the first line of HTTP request header. This variable is invariant. It doesn't change while rewrite engine is working.
...
RewriteCond %{THE_REQUEST} \s.*\.php\s
RewriteRule \.php$ index.php [L]
The regular expression is different. It is not applied on the URI only, but on entire first line of the header, that means on something like GET /script.php HTTP/1.1. But the critical rule is this time applied only if the user is explicitly requesting some PHP-script directly. The rewritten URI is not used.

Problem with multiple rewrite rules

I have this rule which redirects all requests without a . in them to index.php, and it works fine:
# Redirect all page requests to content handler
RewriteRule ^([^.]*)$ index.php [L]
Now I'd also like to disallow any requests where the original URL contains .php in it. When I add another rule like this (after the first one), the first rule breaks:
# Disallow access to PHP files
RewriteRule \.php 404.php [L]
I thought that adding [L] to the first rule would stop the second rule from being executed, but it seems to have no effect: the output from the first rule (i.e. index.php) matches the second rule and all requests end up in 404.php. What am I doing wrong here?
The [L] means no more rules are processed for this request, but the entire path is triggered again when index.php is being processed. Try adding a new rule making the 404 rule fire only if the requested page isn't index.php, something like this:
# Disallow access to PHP files
RewriteCond %{REQUEST_FILENAME} !=index.php
RewriteRule \.php 404.php [L]