I've been learning mod_rewrite today. I'm thinking of writing a CMS, and I need to be able to translate "fake" URLs (requests for files that don't actually exist) into objects in my database. Importantly, however, I want to make sure that if an actual file exists, that file gets served instead of looking in my CMS. So, here are my rules:
RewriteEngine On
RewriteBase /testing/rewritetest/
RewriteRule ^([^.]+[^/])$ $1/ [R=permanent,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ bar.php?$1
Basically, this says "start the rewriting engine" (start processing rules) and set the base directory. If the thing you requested looks like a directory (if it doesn't have an extension), then add a trailing slash and make it look like a directory. This sends an actual redirect (code 301, "moved permanently") to the browser, and stops processing other rules (L means "last").
Otherwise, if it's either a "real looking" directory with a slash on the end, or it looks like a file (has an extension), then if what you requested isn't a real directory and isn't a real file, fulfill the request with bar.php and pass it the actual requested URL through the querystring.
This is, of course, just a test, and filenames, etc. will be changed for my actual CMS.
There was a bug in Apache for Windows that caused this to break when I put it on my system. I found this in the release announcement for Apache 1.3.26, which happens to be the version I'm using:
Fix for a problem in mod_rewrite which would lead to 400 Bad Request responses for rewriting rules which resulted in a local path.
Even though they said the bug was fixed, this seemed to be the same behavior I was getting. In fact, the engine was erroneously injecting the local path into the filename twice when it resolved the URL into a filename. As you can see in the log I generated (some info deleted):
(3) [per-dir c:/prog/work/localweb/testing/rewritetest/] add per-dir prefix: bar.php -> c:/prog/work/localweb/testing/rewritetest/bar.php
(3) [per-dir c:/prog/work/localweb/testing/rewritetest/] add per-dir prefix: c:/prog/work/localweb/testing/rewritetest/bar.php -> c:/prog/work/localweb/testing/rewritetest/c:/prog/work/localweb/testing/rewritetest/bar.php
So, that's definitely wrong. But I noticed they said the bug was for when you resolved to a local path, so I cheated and changed it to an absolute path:
RewriteRule ^(.+)$ http://localhost/testing/rewritetest/bar.php?$1
And that fixed it.
You are a star! This has been bugging me for days!!