What does the following (simple) .htaccess rule do? - apache

I'm learning a lot about .htaccess, I found the following line in a project, but i really can't make out what it does
RewriteRule ^$ index.php [L]
I know that ^ indicated the beginning of the url to match and
that $ indicated the end of the string. But there's nothing in between so maybe this one is redundant?

This one is not redundant rule it is matching ^$ (empty pattern which means home/landing URI /) and forwarding it to index.php thus when you open http://domain.com it is showing http://domain.com/index.php
Though same thing can be achieved using:
DirectoryIndex index.php

Related

I can't figure out why this RewriteCond isn't working

So I'm having trouble figuring out why my RewriteRules won't trigger. These rules are in an .htaccess file at the root directory of a subdomain of my website. I've turned on detailed logging for mod_rewrite in the VirtualHost but that isn't really helping me solve what's wrong, though the first three rules seem to be working simply by coincidence since their files exist at the requested location.
The goal of this set of rules is:
sub.domain.tld/ -> passthrough/serve actual file
sub.domain.tld/?q=test -> passthrough/serve actual file with query args intact
sub.domain.tld/.well-known/* -> passthrough/serve actual file (for letsencrypt)
sub.doamin.tld/* -> process.php?project=*
sub.domain.tld/*?q=test -> process.php?project=*&q=test while handling unlimited number of query args
And the current .htaccess is:
RewriteEngine on
#serve actual file if viewing main page or doing https renewal
RewriteCond %{REQUEST_URI} ^\?.+|\/$ [OR]
RewriteCond %{REQUEST_URI} ^\.well-known.*
RewriteRule (.*) - [L,QSA]
#redirect everything else to the processing script
RewriteCond %{REQUEST_URI} ^(\w+)
RewriteRule \/(\w+) process.php?project=$1 [NC,L,QSA]
Thank you for your help!
OK, This was actually a complex one and because most of the time, %{REQUEST_URI} tests are done using the RewriteRule itself, I got a bit confused and I'm sorry about that.
It turns out:
%{REQUEST_URI} contains the leading slash
the matching part of the RewriteRule doesn't
Also, keep in mind %{REQUEST_URI} doesn't contain the query string, as stated in the Apache manual:
REQUEST_URI
The path component of the requested URI, such as "/index.html". This notably excludes the query string which is available as its own variable named QUERY_STRING.
So, a rule like RewriteCond %{REQUEST_URI} ^\?.+ is pretty much useless as you'll never have a question mark in %{REQUEST_URI}
Also, and this probably is the most confusing part, when requesting /, %{REQUEST_URI} will contain the actual index file that has been served. So, if your DirectoryIndex is set to index.php index.html (in that order) and you have an index.html file in the root folder, {REQUEST_URI} will be index.html. If you have an index.php file, it will be index.php, but never /.
That being said, we can simply your rules to:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/(\.well-known|index\.php$)
RewriteRule (.+) process.php?project=%{REQUEST_URI} [QSA]
Note that I added the $ inside the brackets to only match the end of string character after index\.php but not after \.well-known, so anything after \.well-known will also match.
You will need to replace index\.php with index\.html if you have an html index.
Finally, you don't need 2 rules for that. It's always better to have only one and exclude some URLs from it.
PS: you'll also notice you don't need to escape / as this is not considered as a regexp delimiter.
You just need this single rule in your .htaccess:
RewriteEngine on
# skip files, directories and anything inside .well-known/ directory
RewriteRule ^(?!index\.|process\.php|\.well-known)(.+)$ process.php?project=$1 [L,QSA,NC]

mod_rewrite: hide real urls but keep available as different files

Possible this question has already been answered but I didn't find any answer after hours of searching.
I need to put the site under "maintenance mode" and redirect/rewrite all requests to site_down.html, but at the same time I need the site to be available if I enter the address like files are in a subfolder.
ex:
if I type http://example.com/login.php I need site_down.html to be displayed.
but if I specify http://example.com/test/login.php I need real login.php do be displayed.
I need this to be done with rewrite, so copying everything to another directory isn't a solution.
I tried a couple dozens of combinations, but I'm still unable to achieve what I need
This is one version of my .htaccess file ():
DirectoryIndex site_down.html
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^test\/(.*)$ $1 [S=1]
RewriteRule ^(.*\.php)$ site_down.html
RewriteRule .* - [L]
</IfModule>
This code should rewrite all requests with "test/*" to "parent folder" and skip next rewrite rule and then terminate rewriting at RewriteRule .* - [L]. If there is no "test/" in url - all request should be rewritten to site_down.html
What am I doing wrong?
Could you suggest any valid solutions, please?
Thank you.
Essentially, you are searching for 2 rules. One rule will translate a virtual subdirectory to the working files. The other rule will translate the url to the working files to a splash page. We just have to make sure that if the first rule matches, the second rule doesn't match. We can do this by making sure " /test/" (including that leading space) was not in THE_REQUEST (or the string that the client sent to the server to request a page; something in the form of GET /test/mypage.php?apes=bananas HTTP/1.1). THE_REQUEST doesn't change on a rewrite, which makes it perfect for that. Skipping a rule like you did usually doesn't have the effect you expect, because mod_rewrite makes multiple passes through .htaccess until the resulting url doesn't change anymore, or it hits a limit and throws an error. The first time it will skip the rule, but the second time it will not do that.
RewriteCond %{THE_REQUEST} !\ /test/
RewriteRule \.php site_down.html [L]
RewriteRule ^test/(.*)$ $1 [L]

Apache rewrite exception for / index but not second and deeper indexes?

I want to have an exception for...
http ://localhost/
...while rewriting the index of any directories underneath...
http ://localhost/directory1/
http ://localhost/directory2/
By having an empty item below (the first item which is between the characters (| on the third line) it creates an exception for ALL indexes so how can I make the exception NOT apply to the localhost/ itself using this copy of .htaccess?
http ://localhost/.htaccess
RewriteEngine on
RewriteRule ^(|directory2/|directory2/) - [L]
RewriteRule !\.(css|xhtml|xml|zip)$ rewrite.php
...and I can not mess with server configuration. Additionally this question is not redirect related.
Try using a RewriteCond to match your directory, and then apply the RewriteRule to anything that matches.
EDIT: Also, I think your ! line might be causing some problems. I tested with the rewrite rule tester and tweaked my suggested fix to look like this:
RewriteCond %{REQUEST_URI} ^/(directory1|directory2)/
RewriteRule .(css|xhtml|xml|zip)$ - [L]
RewriteRule .* rewrite.php
This is generally how I match things -- if you have some things you don't want to process, match them and stop processing rules with the [L] directive, then continue ahead for anything else.
This rule makes an exception for the root index. Since nothing is between ^ (^ = starts with) and $ ($ = ends with) the requested URI this matches http:// localhost/ exactly. Having [space] index.php (or change the extension to what you want) forces the file to rewrite to itself. It does not appear to loop.
RewriteRule ^$ index.php [QSA]

mod_rewrite - stop repeating for each directory

I have spent hours trying to get a simple rewrite working, there must be an error in my fundamental understanding of mod_rewrite:
I want a rule that does the following substitution:
www.example.com/fr/ -> www.example.com/?lang=fr
which I have working, but for subdirectories:
www.example.com/fr/other/directories/ -> www.example.com/other/directories/?lang=fr&lang=fr&lang=fr
It seems the rule is being applied once for every sub-directory (it should only be applied once).
Also, a request without a trailing slash causes another lang=fr to be appended to the query string
The rule is located in the < VirtualHost > and not within a < Directory > tag
RewriteRule ^/(en|fr|zh|gr|it)/(.*)$ /$2?lang=$1 [QSA]
I am also using the DocumentIndex /index.php index.php directive
Many thanks.
Could try adding a / in your second rewrite just after $s2 to experiment with the extra addition.
And try adding [L] to the conditions, might stop it repeating over every directory.
RewriteRule ^/(en|fr|zh|gr|it)/(.*)$ /$2/?lang=$1 [QSA,L]
However, I've heard [L] behaves differently when in htaccess opposed to being in the httpd.conf - I'm no expert on it I'm afraid.
To be certain a RewriteRule will only be applied once add this condition before:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^/(en|fr|zh|gr|it)/(.*)$ /$2?lang=$1 [QSA,L]
Because any internal redirection made by mod-rewrite (and you'll have a lot, even with the [L] tag) will have the REDIRECT_STATUS envirronement variable altered.
The [L] tag means stop the chain of rewriteRule in case you have some other rules there. But the result of the mod-rewrite rewrite in your directory will always be tested against his new destination (and here the new destination is the same directory), and rules will be applied for the rewritten content as if it was a new one (except this env variable is set).

Why would mod_rewrite rewrite twice?

I only recently found out about URL rewriting, so I've still got a lot to learn.
While following the Easy Mod Rewrite tutorial, the results of one of their examples is really confusing me.
RewriteBase /
RewriteRule (.*) index.php?page=$1 [QSA,L]
Rewrites /home as /index.php?page=index.php&page=home.
I thought the duplicates might have had been caused by something in my host's configs, but a clean install of XAMPP does the same.
So, does anyone know why this seems to parse twice?
And, to me this seems like, if it's going to do this, it would be an infinite loop -- why does it stop at 2 cycles?
From Example 1 on this page, which is part of the tutorial linked in your question:
Assume you are using a CMS system that rewrites requests for everything to a single index.php script.
RewriteRule ^(.*)$ index.php?PAGE=$1 [L,QSA]
Yet every time you run that, regardless of which file you request, the PAGE variable always contains "index.php".
Why? You will end up doing two rewrites. Firstly, you request test.php. This gets rewritten to index.php?PAGE=test.php. A second request is now made for index.php?PAGE=test.php. This still matches your rewrite pattern, and in turn gets rewritten to index.php?PAGE=index.php.
One solution would be to add a RewriteCond that checks if the file is already "index.php". A better solution that also allows you to keep images and CSS files in the same directory is to use a RewriteCond that checks if the file exists, using -f.
1the link is to the Internet Archive, since the tutorial website appears to be offline
From the Apache Module mod_rewrite documentation:
'last|L' (last rule)
[…] if the RewriteRule generates an internal redirect […] this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.
To prevent this you could either use an additional RewriteCond directive:
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule (.*) index.php?page=$1 [QSA,L]
Or you alter the pattern to not match index.php and use the REQUEST_URI variable, either in the redirect or later in PHP ($_SERVER['REQUEST_URI']).
RewriteRule !^index\.php$ index.php?page=%{REQUEST_URI} [QSA,L]