What's the difference between REQUEST_FILENAME and REQUEST_URI in apache configuration?

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.

REQUEST_FILENAME is a beast.

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.