I have a problem with a file test operation in a mod_rewrite RewriteCond entry which is testing whether %{REQUEST_FILENAME} exists. It seems that rather than %{REQUEST_FILENAME} being an absolute path, I'm getting a path which is rooted at the DocumentRoot instead.


I have this inside a <VirtualHost> block in my apache 2.2.9 configuration:

RewriteEngine on
RewriteLog /tmp/rewrite.log
RewriteLogLevel 5

#push virtually everything through our dispatcher script
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([^/]*)/?([^/]*) /dispatch.php?_c=$1&_m=$2 [qsa,L]

Diagnostics attempted

That rule is a common enough idiom for routing requests for non-existent files or directories through a script. Trouble is, it's firing even if a file does exist.

If I remove the rule, I can request normal files just fine. But with the rule in place, these requests get directed to dispatch.php

Rewrite log trace

Here's what I see in the rewrite.log

init rewrite engine with requested uri /test.txt
applying pattern '^/([^/]*)/?([^/]*)' to uri '/test.txt'
RewriteCond: input='/test.txt' pattern='!-f' => matched
RewriteCond: input='/test.txt' pattern='!-d' => matched
rewrite '/test.txt' -> '/dispatch.php?_c=test.txt&_m='
split uri=/dispatch.php?_c=test.txt&_m= -> uri=/dispatch.php, args=_c=test.txt&_m=
local path result: /dispatch.php
prefixed with document_root to /path/to/my/public_html/dispatch.php
go-ahead with /path/to/my/public_html/dispatch.php [OK]

So, it looks to me like the REQUEST_FILENAME is being presented as a path from the document root, rather than the file system root, which is presumably why the file test operator fails.

Any pointers for resolving this gratefully received...


Took me a while to find out as well, but the reason is mentioned in the mod_rewrite documentation:

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.

That's why it works in .htaccess but not in the conf file of the vhost. (And that's also why adding the DOCUMENT_ROOT works around the problem).


I resolved this by explicitly writing the document root into the condition

RewriteCond /path/to/my/public_html%{REQUEST_FILENAME} !-f
RewriteCond /path/to/my/public_html%{REQUEST_FILENAME} !-d
  • 3
    This is strange considering the documentation says REQUEST_FILENAME contains "the full local filesystem path". Did you try with %{SCRIPT_FILENAME}?. Anyways... consider using %{DOCUMENT_ROOT} rather than a literal path for a more general solution. – GetFree Oct 25 '09 at 19:25
  • I know, hence my confusion. I think it might because I've done this before via .htaccess, but this time put the rules into the vhost config - perhaps it operates differently at that level. Thanks for the DOCUMENT_ROOT tip though. – Paul Dixon Oct 26 '09 at 8:27
  • it's an old question, but being the selected answer, can you edit it so as to use %{DOCUMENT_ROOT}? – tokland Feb 17 '11 at 12:15
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

This won't work as intended in a virtualhost (or server) context because the directives are processed before the request has been mapped to the filesystem, unlike when used in a directory (or .htaccess) context. Before the request has been mapped to the filesystem, REQUEST_FILENAME is the same as REQUEST_URI, ie. the root-relative URL-path.

However, you can use a lookahead instead to get the absolute filename that the request will eventually map to. For example:

RewriteCond %{LA-U:REQUEST_FILENAME} !-f
RewriteCond %{LA-U:REQUEST_FILENAME} !-d
RewriteCond     %{REQUEST_URI}     ^(/pathinfo/|/pathinfo)(.*)$
RewriteRule     .*          %{DOCUMENT_ROOT}%{REQUEST_URI} [L]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.