mod_rewrite: what does this RewriteRule do? - mod-rewrite

Given these conditions (I know what they mean/do):
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
What does the first rule do? What is that lonely dash for?
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]
I've been using this for quite some time now in combination with the Zend Framework, but I never really got what the first rule does exactly.

The RewriteCond directive just describes an additional condition for a RewriteRule directive. So RewriteCond must always be associated with a RewriteRule.
In your case the three RewriteCond probably belong to the first RewriteRule like this:
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
Now this rule is applied if the pattern of the RewriteRule matches the current request URL (per-directory path stripped before) and if the condition is fulfilled.
In this case the condition is only true if when mapping the request URL to the filesystem it matches either an existing file with the file size greater than 0 (-s), or a symbolic link (-l) or a directory (-d). So your rule will be applied for any URL (^.*$ matches anything) that can be mapped to something existing in your filesystem. The substitution - just means to not change anything. And the NC (no case, case insensitive, useless in this context) and L (last rule if applied) are flags that modify either the pattern, replacement or the execution of the rule.

Related

.htaccess - Check .jpg size and replace if match

I need to control all remotes .jpg matching sizes: 4456 and 4824. If match these bytes I need to replace with a default image. The below code is to replace a .jpg if doesn't exist.
RewriteCond %{REQUEST_URI} \.(jpeg|JPEG|jpg|JPG)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*$ /default-image.jpg [L]
I need that if a example.com/*.jpg have size (4456 | 4824) then replace with the default-image.jpg.
In PHP this is working like a charm for my needs but I would prefer to set in .htaccess.
$link = 'https://example.com/test.jpg';
$check_image = get_headers($link, 1);
$bytes = $check_image["Content-Length"];
if ($bytes < 5000) { ...
You can do the following on Apache 2.4 using an Apache expression with mod_rewrite:
RewriteCond %{REQUEST_URI} !^/default-image\.jpg$
RewriteCond expr "filesize(%{REQUEST_FILENAME}) =~ /4456|4824/"
RewriteRule \.jpe?g$ /default-image.jpg [NC,L]
If the requested image does not exist then the filesize() function simply returns 0 (no error). So, to handle non-existent images as well, then you could just change the regex to include 0, ie. /0|4456|4824/.
Aside:
RewriteCond %{REQUEST_URI} \.(jpeg|JPEG|jpg|JPG)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*$ /default-image.jpg [L]
In the first condition, there is no need to check jpeg|JPEG since you are using the NC (case-insensitive) flag on the directive. However, it is more optimal to perform this check in the RewriteRule pattern instead, rather than creating an additional condition.
There's no need to check that the request does not map to a directory (3rd condition), unless you also have directory names that end in .jpg etc. (unlikely). Filesystem checks are relatively expensive, so it is best to avoid them if possible.

Rewriterule for two index.php files - pls help me

I want to use RewriteRule for two index.php files which contain explode function.
www.domain.com/1/index.php and
www.domain.com/2/index.php
I want to build multilevel directories for both ie:
www.domain.com/1/europe/germany
www.domain.com/2/africa/maroco
I have first condition
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^?]*)$ /1/index.php?path=$1 [NC,L,QSA]
but i don't know where/how put second condition for directory /2/
Please help
Your RewriteRule pattern is too broad, you need to use the leading /1/ or /2/ :
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([0-9]+)/([^?]*)$ /$1/index.php?path=$2 [NC,L,QSA]
This rule use the leading number to dispatch the query to the right script.

how to create an empty rewrite rule, that will not modify the url

I have static files in several directories on my website.
I was trying to create a rule that will instruct the rewrite engine to disregard all of those static files.
something like this:
#RewriteCond %{REQUEST_URI} !\.*(jpg|css|js|gif|png|swf)$ [NC]
this seems to work only in some of the cases, but not all of them.
As a solution I decided to match the entire request URI of any requested file with one of the following extensions, and create an 'empty' rewrite rule for them, that will redirect the user to the precise request URL, basically.
To achieve that I did the following:
RewriteCond $1 \*.(js|ico|gif|jpg|png|css|swf|mp3|wav|txt)$ [NC]
RewriteRule ^(.*) \$1 [R=301,L]
This won't work for some reason, no useful information at the access.log and error.log either.
Thanks in advance for any assistance!
Full code:
#Catch static content and don't modify it
RewriteCond $1 \*.(js|ico|gif|jpg|png|css|swf|mp3|wav|txt)$ [NC]
RewriteRule ^(.*) \$1 [R=301,L]
#prevent looping
RewriteCond %{QUERY_STRING} !clientId=
#redirect sub domain to the client page cutl.mysite.com = mysite.com/in/index/php?clientId=curl
RewriteRule ^(.*)$ /in/index.php?uclinetId=$1 [L]
Rather than maintaining a long list of file extensions for exclusion you can simply use:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
Which means apply next RewriteRule if request is NOT for a real file or a symbolic link.
Probably your backslash should be between the asterix and the dot?
RewriteCond $1 *\.(js|ico|gif|jpg|png|css|swf|mp3|wav|txt)$ [NC]
RewriteRule ^(.*) \$1 [R=301,L]

Rewrite rules confused

I am struggling to achieve this simple thing...
I have some static pages which should be like
www.domain.com/profile etc..
The problem is how to write the rewrite rules in order to ..
There would be some fixed rewrites
like /home
I want every file that exists not to be rewritten
www.domain.com/test.php should go to
test.php
Lastly if it is not found i want it to be redirected to static.php?_.....
RewriteRule ^/home/?$ /index.php?__i18n_language=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([^/]+)/?$ /static.php?__i18n_language=$1
This works ok but if i type index.php or test.php or even the mach from other redirection it gets me in static.php...
Please help!
According to your description you can use these rules:
# stop rewriting process if request can be mapped onto existing file
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteRule ^ - [L]
# rewrite known paths /home, /foo, /bar, etc.
RewriteRule ^/(home|foo|bar|…)$ /index.php [L]
# rewrite any other path
RewriteRule ^ /static.php [L]
I haven't used this in a long time, but it's something I found, that should help. It is part of an old script that generates .httaccess files for redirecting from /usr/share/doc only when the doc isn't found:
The rule is "Check, and if the target url exists, then leave":
RewriteEngine On
RewriteBase /doc/User_Documents
### If the directory already exists, then leave
### We're just redirecting request when the directory exists but has been renamed.
RewriteCond %{REQUEST_FILENAME} User_Documents/([^/]+-[0-9][^/]*)
RewriteCond $PWD/%1 -d
RewriteRule .* - [L]
It's the [L] that means leave if one of the conditions is matched. In the old script, there are hundreds of generated rules (after [L]) that are skipped, because one of the conditions matched. In your case you would skip the rest of the rules when the target %{REQUEST_FILENAME} is found.
So, I suggest, before the redirection rule:
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]

Rewrite rule fails to match single quote chars

I asked this question earlier:
mod_rewrite: match only if no previous rules have matched?
And have been using the suggested solution with success for a while now:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^.+\ (/[^?\s]*)\??([^\s]*)
RewriteCond %{REQUEST_URI}?%{QUERY_STRING}<%1?%2 ^([^<]*)<\1$
RewriteRule .* /pub/dispatch.php [L]
However, we've since discovered that this rule fails for URLs containing single quote chars, e.g. http://example.com/don't_do_it (which is actually requested as http://example.com/don%27t_do_it)
Specifically, this is the line that's failing to match:
RewriteCond %{REQUEST_URI}?%{QUERY_STRING}<%1?%2 ^([^<]*)<\1$
commenting it out causes the rule to match as expected, but breaks the "match only if no previous rules have matched" behavior. This is presumably related to the fact that ' is urlencoded to %27.
Here's the relevant RewriteLog entry (for the url /asdf'asdf aka /asdf%27asdf):
RewriteCond: input='/asdf'asdf?</asdf%27asdf?' pattern='^([^<]*)<\1$' => not-matched
What I'm seeing here is that %{REQUEST_URI} is unescaped while %{QUERY_STRING} is escaped, hence the mismatch. Is there an alternative to either one of those I should be using?
Any ideas how to rewrite the above line so that it will also match lines that contain ' chars?
Try the C flag and chain the sequence of rules of which you just want one to be applied. So actually chain all of your rules.
You can test the [NE] flag at the end of the RewriteRule.
After beating on it for quite some time, things are looking good with:
RewriteMap unescape int:unescape
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^.+\ (/[^?\s]*)\??([^\s]*)
RewriteCond %{REQUEST_URI}?%{QUERY_STRING}<${unescape:%1}?%2 ^([^<]*)<\1$
RewriteRule .* /pub/dispatch.php [L]

Resources