What’s up with REQUEST_FILENAME in mod_rewrite?

I was trying to setup mod_rewrite rules for a CakePHP app running under Apache.

According to the mod_rewrite docs, REQUEST_FILENAME is “The full local filesystem path to the file or script matching the request.”

If that were true, this idiom, which I’ve seen in a number of places,
should work to prevent the RewriteRule underneath it from firing when a request is made for a file which exists in the filesystem:

RewriteCond %{REQUEST_FILENAME} !-f

But it doesn’t. Looking at the rewrite log reveals that REQUEST_FILENAME, on my system at least, is not the full filesystem path; it is actually relative to the document root. Which means that the condition is never true and the rewrite will always happen.

So in order to get it to work, I have to do this ugly hack:

RewriteCond /home/y/share/htdocs%{REQUEST_FILENAME} !-f

Why?

12 thoughts on “What’s up with REQUEST_FILENAME in mod_rewrite?

  1. Did you ever find the solution to this? I’m having the same problem with a rewrite thing I’m doing at the moment..

    cheers,
    Jonathan.

  2. Looks like -f is context sensitive, I just ran into this problem, when used in .htaccess or inside a tag, it works correctly, outside it has the same behaviour as %{REQUEST_URI}, so:

    DocumentRoot “C:Site”
    ServerName http://www.mysite.com

    <Directory "C:\Site">
        Order allow,deny
        Allow from all
    </Directory>
    
    RewriteEngine On
    RewriteCond $1 (^/images/)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ /admin$1 [QSA,L]
    

    Will behave badly, however:

    DocumentRoot “C:Site”
    ServerName http://www.mysite.com

    RewriteEngine On
    <Directory "C:\Site">
        Order allow,deny
        Allow from all
    
        RewriteCond $1 (^/images/)
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ /admin$1 [QSA,L]
    </Directory>
    

    Will work as it’s supposed to.

    Thanks


    Craig “FrostyCoolSlug” McLure

  3. Disregard my previous comment, seems that some cached stuff was causing confusion on the page..

    A more simple solution, when looking at your example, change:
    RewriteCond %{REQUEST_FILENAME} !-f

    To read:
    RewriteCond %{DOCUMENTROOT}%{REQUESTFILENAME} !-f

    Thus getting a Document Root prefix. It is still context specific, so if you use .htaccess you don’t need %{DOCUMENT_ROOT} but from what i’ve seen, it shouldn’t go in , my apologies for any confusion.

  4. Your rule works fine, Frosty. However, if you are using Alias’ed resources and wish to do the “-f” test, you’re back in the same boat. :(

    It seems Apache doesn’t know how to check to see if a file exists when it’s being referenced via an alias.

  5. When detecting if a file actually exists, you must use REQUEST_FILENAME, which corresponds to the file on your system. For most other things, use REQUEST_URI which corresponds to the directory and file name portion (URI) of the requested web address (URL).

  6. Hi folks,

    FrostySlug, your first answer (putting the directory tag around the rewrite) worked great for me!

    Thanks!

  7. Just to follow up on this that the reply by FrostySlug is correct (for FreeBSD anyway that had this problem) however his DOCUMENT_ROOT and REQUEST_FILENAME need the underscores in the middle to work – so DOCUMENT ‘underscore’ ROOT and REQUEST ‘underscore’ FILENAME

  8. The alias occurs after the rewritecond checks for files and directories, so rewritecond -f doesn’t know about your aliased directory. I’ve looked for a way around this, but all solutions involve some convoluted regex for an apache file-system path + file. Ideally there would be some flag asking Apache to process the alias before the rewrite rules (this might cause problems with putting rewrite inside constructs though).

  9. For me this didn’t help like sayd before:

    DocumentRoot “C:Site”
    ServerName http://www.mysite.com

    RewriteEngine On

    Order allow,deny
    Allow from all

    RewriteCond $1 (^/images/)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ /admin$1 [QSA,L]

    But this did:
    DocumentRoot “C:Site”
    ServerName http://www.mysite.com

    Order allow,deny
    Allow from all

    RewriteEngine On
    RewriteCond $1 (^/images/)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ /admin$1 [QSA,L]

    … putting everything concerning rewrite inside Directory.

  10. Use `RewriteBase /` otherwise relative paths will be used.

  11. It depends on what APACHE u are using.

    Please see a difference between these two docs:

    http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
    “REQUEST_FILENAME
    The full local filesystem path to the file or script matching the request.”

    http://httpd.apache.org/docs/current/mod/mod_rewrite.html
    “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.”

    I think you are using a virtual host, like almost everyone. So like another person said, you have to use %{DOCUMENT_ROOT}%{REQUEST_FILENAME} instead of just %{REQUEST_FILENAME}

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>