I don't see any posts discuss the differences between REQUEST_URI and REQUEST_FILENAME, while I see many posts use them interchangeably.

I turned on the mod_rewrite log (LogLevel alert rewrite:trace8), replaced REQUEST_FILENAME with REQUEST_FILENAME, looked up the rewrite log in each configuration, and the rewriting process are exactly the same.

So my question is:

Are they the same under 99% circumstances?

I didn't say 100% because I see from doc(https://httpd.apache.org/docs/current/mod/mod_rewrite.html) mentioning an exception for REQUEST_URI related to something called AcceptPathInfo.


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. Depending on the value of AcceptPathInfo, the server may have only used some leading components of the REQUEST_URI to map the request to a file.

Actually I find it difficult to understand the whole definition, not only the last sentence.

I use REQUEST_FILENAME and REQUEST_URI mainly between <VirtualHost *:443>.

My <VirtualHost *:443> settings:

<VirtualHost *:443>
        ServerAdmin admin@exmaple.com
        DocumentRoot /var/www/example.com/public_html
        ServerName example.com
        ServerAlias www.example.com

        LogLevel alert rewrite:trace8
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

RewriteEngine On
#RewriteCond %{REQUEST_URI} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule (.*) /tq_info.php?p=%{REQUSET_URI}

RewriteCond %{REQUEST_FILENAME} !/.*\.php$
RewriteCond %{REQUEST_FILENAME} !/admin/.*
RewriteRule (.*) /index.php/$1 [L]
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

These are very different and serve different purposes.

REQUEST_URI is the path component of the URI in the request. For example, /tq_info.php.

REQUEST_FILENAME is the result of trying to find the file in the local filesystem by applying the URI path to the document root or any alias that might have been defined. Thus, if the file exists, this will be set to /var/www/example.com/public_html/tq_info.php. It is used to locate a file in the filesystem. It is only set to match REQUEST_URI if there is no file in the filesystem. In that case the request will be passed to the 404 handler, or to an upstream web application if you have defined one in your web server configuration that matches the URI path.

When you are choosing which one to use, you need to think about whether you are trying to work with the URI path component, or the path of the corresponding file in your filesystem.

  • But REQUEST_FILENAME doesn't automaticallly add document root at all. For example, if I write RewriteCond %{REQUEST_FILENAME} !-f, and the url I type is www.example.com/hello.txt. %{REQUEST_FILENAME} would be /hello.txt, a file under root directory and apache would check whether it exists. It is not going to check var/www.example.com/public_html/hello.txt. It won't add the document root. So I think what you said isn't correct. Maybe I misunderstood your word? – Rick Jul 12 '20 at 9:56
  • @Rick Did you actually check the value of REQUEST_FILENAME? You could write a trivial PHP script to print both values, and then you would see the difference. – Michael Hampton Jul 12 '20 at 12:28
  • I did check the both value in a PHP script separately. Hmm. I will check both again later. – Rick Jul 12 '20 at 13:21

I'm late to the party, but to clear a few things up:

REQUEST_URI, as Michael Hampton wrote, always contains the path component of the requested URI. This, crucially, means that query parameters (things like ?a=b) are stripped off the request URI.


In the best case, it will contain a local file system path mapping to what was requested and it will be exactly %{DOCUMENT_ROOT}%{REQUEST_URI}. This needs not be the case, though. If %{REQUEST_URI} maps to an alias, it will be transparently redirected, so %{REQUEST_FILENAME} will be different, too. This also holds for a chain of redirections, for example //tricked/you with the latter path actually existing (relative to the document root). One could argue that this is an intermediate step that we can ignore, but chaining is possible.

Then, the AcceptPathInfo configuration option modifies the way request URIs are mapped to files. If set to on, the server scans for files for sub-paths as well and exposes trailing data in %{PATH_INFO}. In such a case, only part of %{REQUEST_URI} may be used to map a path to a file system location. Extending the example from above, if /tricked/you refers to a proper file, a %{REQUEST_URI} of /tricked/you/and/then/some/more will let httpd map the request to what /tricked/you would have mapped to and expose /and/then/some/more as %{PATH_INFO}, which means that %{REQUEST_FILENAME} would eventually be something along the lines of %{DOCUMENT_ROOT}/tricked/you.

Lastly, whether %{REQUEST_FILENAME} is already expanded to an actual file system path or still set to %{REQUEST_URI} depends upon the context of its usage. In a VirtualHost context, like you are using, it will never be a mapped file system path - mainly because this code point lies before the actual mapping point in the code path. Sadly, there is no easy way to find out whether httpd might have already mapped (part of) %{REQUEST_URI} to a file system location or not - other than looking through the source code and hoping that the execution path will not change unexpectedly.

There are, however, a few assumptions you can safely make:

  • VirtualHost contexts will only ever see unmapped values
  • querying that variable in a script that is part of the document root will always return a mapped path (since, how else would httpd be able to execute the script if its location wasn't mapped beforehand?)

Everything else is trial and error. Especially, %{REQUEST_FILENAME} needs not to be mapped in any random executed script. Think of wrappers that actually determine what file to serve or execute when set as handlers.

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.