Apache2 - It seems that rewrite condition is not always applied - mod-rewrite

I would like to redirect to /lost/index.php only when the image file does not exists.
When I try it - it seems that it does not work on browser refresh
If I invoke it with a file which exists on the server
/images/image1.jpg
it shows me a file (GOOD - the file exists )
but if I refresh the browser it redirects me to /lost/index.php (WHICH IS BAD)
Below my rules
RewriteEngine On
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 3
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/images/(.*)$ /lost/index.php?image=$1 [L,R]
Any ideas ?

So I solved it.
If you define your rewrite rules inside element they should look like
<Directory /var/www/local.example.com>
...
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^images/(.*)$ /lost/index.html?image=$1 [R]
</Directory>
If you define them "globally" outside the (per-server context) they should look like
RewriteEngine On
RewriteCond %{LA-U:REQUEST_FILENAME} !-l
RewriteCond %{LA-U:REQUEST_FILENAME} !-d
RewriteCond %{LA-U:REQUEST_FILENAME} !-f
RewriteRule ^/images/(.*)$ /lost/index.html?image=$1 [R]
This is due the fact that if used in per-server context (i.e., before the request is mapped to the filesystem) SCRIPT_FILENAME and REQUEST_FILENAME cannot contain the full local filesystem path since the path is unknown at this stage of processing. Both variables will initially contain the value of REQUEST_URI in that case. In order to obtain the full local filesystem path of the request in per-server context, use an URL-based look-ahead %{LA-U:REQUEST_FILENAME} to determine the final value of REQUEST_FILENAME.
What is also important - the pattern has to be different in both cases. In second case it has to starts with '/' while in the first one not. This is due the fact that REQUEST_FILENAME contains the '/' at the beginning for the second case but it does NOT for the first one

Related

Why isn't this mod_rewrite re-directing?

I'm sending every request through an index.php except for pages in my blog subdirectory. I've been able to do this using mod_rewrite in my parent folder and;
RewriteCond %{REQUEST_URI} !^/blog
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
]
However, I'd also like to send requests to my blog folder if they have the form:
documentation/some-file.
I've tried:
RewriteRule ^/documentation/(.+)$ https://www.some_domain.com/blog/documentation/$1
but it looks like my request isn't getting sent to the blog folder in this case. My full code is below:
RewriteEngine On
#redirect to index.php as appropriate
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^/documentation/(.+)$ https://www.some_domain.com/blog/documentation/$1
RewriteCond %{REQUEST_URI} !^/blog
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
Edit:
I've used a slightly modified version of #Rijul's suggestion below and after moving the RewriteRule to before the RewriteCond, it works as I had hoped. In other words, the re-write for documentation performs the re-write to the blog subfolder. And, all other requests go through my index.php file. At this point, I would like to understand why.
RewriteEngine On
RewriteRule ^documentation/?(.*)$ /blog/documentation/$1 [R=301,L]
#redirect to index.php as appropriate
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
From what i know
RewriteEngine On
Without this all the rewrite rules and condition will be ignore
RewriteRule ^documentation/?(.*)$ /blog/documentation/$1 [R=301,L]
Rewrites documentation to blog/documentation
RewriteCond %{REQUEST_FILENAME} !-d
This rewrite condition checks whether the requested directory name doesn't exits. If it doesn't exits. Then proceeds to the next condition
RewriteCond %{REQUEST_FILENAME} !-f
This rewrite condition checks whether the requested file name doesn't exits. If it doesn't exits. Then proceeds to the next condition
RewriteCond %{REQUEST_FILENAME} !-l
This rewrite condition checks whether the requested symbolic link doesn't exits. If it doesn't exits. Then proceeds to rewrite rule
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
Rewrite to index.php?url=
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
writing rewrite condition like this produces an and operation.
(no file exits in that name) and (no directory exits in that name) and
(no symbolic link exits in that name)
If this is true then rewrite to php file. (no directory exits in that name) will go false in the case for /blog (since such a directory exits)

Moving symfony2 htaccess file into vhost

I wanted to move .htaccess content into vhost for performance, and am trying to solve an issue.
This is in .htaccess:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
I tried this in Vhost:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /app.php [QSA,L]
The problem is that second one redirects /app_dev.php/ controller to app.php and it shoud not, like in first example.
Any tips are greatly appreciated.
From RewriteCond Directive Apache Docs:
REQUEST_FILENAME:
The full local filesystem path to the file or script matching the request, if this has already been determined by the server at the time REQUEST_FILENAME is referenced. Otherwise, such as when used in virtual host context, the same value as REQUEST_URI.
So what you are actually testing for is not a file has the path /app_dev.php which is not the absolute path i.e. without the DocumentRoot path prepended. So, you have to do this:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^ /app.php [L]
^(.*)$ there is no need for this as you are just rewriting without consideration for URI.
Flag QSA also not required as you are not manipulating any query string.

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 logic breaking?

I have the following rewrite logic in my vHost and everything seems to be working in regards to redirecting subdomains, but as soon as I add a path to the URI I'm getting an error in my apache_error.log.
Here is the rewrite logic:
RewriteEngine On
# Remove the www alias
RewriteCond %{HTTP_HOST} ^www\.13labs\.net$ [NC]
RewriteRule ^(.+)$ http://13labs.net$1 [R=301,L]
RewriteCond %{REQUEST_URI} ^.+$
RewriteCond %{REQUEST_FILENAME} !\.(gif|jpe?g|png|js|css|swf|php|ico|txt|pdf)$ [OR]
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} !-d [OR]
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^ - [L]
RewriteCond %{HTTP_HOST} !^www\.13labs\.net$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.13labs\.net$ [NC]
RewriteRule ^(.+)$ /index.php?subdomain=%2&kohana_uri=$1 [PT,L,QSA]
RewriteRule ^(.+)$ /index.php?kohana_uri=$1 [PT,L,QSA]
I am trying to hit admin.13labs.net/login, which should be rewriting to 13labs.net/index.php?subdomain=admin&kohana_uri=/login. However, in my apache_error.log I am receiving the following:
[Mon Aug 30 23:56:06 2010] [error] [client 74.63.151.37] File does not exist: /var/www/13labs.net/html/login
Any clues? I've been playing around with this for about an hour now and I'm stumped...
Regards,
Andrew
Your second rewrite rule (with its corresponding conditions) looks like it'll stop rewrites for any URL. It matches if the file doesn't have the right extension, OR isn't a file, OR isn't a directory, OR isn't a link. No resource can be a file and a dir and a link at the same time, so all URLs will match -- and they'll all get passed as is, since your [L] flag prevents any subsequent rewrites.
If your intention is to prevent rewrites for URLs that correspond to existing files, links, or directories, remove the !'s from your conditions and remove the [OR] from the condition that checks the file extension.

mod_rewrite: what does this RewriteRule do?

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.

Resources