views:

138

answers:

1

I want to rewrite all my URLs to hide the .php extension. A general rule that adds .php to all URLs obviously won't do, so I want this rule to be conditional on the fact that

  • There is no file nor directory that matches the URL
  • After adding the .php, there is a match

I've arrived at these rewriting rules:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [L]

The first two take care of checking whether the request can be satisfied without rewriting (so for images and other non-PHP content). With the third rule I'd like to check if adding .php would make the request valid (if not, we'll try something else further down the rewrite rules, or return 404).

The RewriteCond %{REQUEST_FILENAME}.php -f part never seems to match though. Any suggestions?

EDIT

The rewrite log is containing these entries:

(4) RewriteCond: input='/contact' pattern='!-f' => matched 
(4) RewriteCond: input='/contact' pattern='!-d' => matched 
(4) RewriteCond: input='/contact.php' pattern='-f' => not-matched

I find it strange that it's trying to match /contact, and not /var/www/mysite/htdocs/contact (At least that's what I'd expect when reading the docs on REQUEST_FILENAME). Apparently REQUEST_FILENAME is only what I expect when there is an actual match?

EDIT2

Thanks to Thomas for the answer: use %{DOCUMENT_ROOT} instead to manually compose the complete filename of the as yet unfound PHP file.

I've also thrown in an extra '/?' in the regexp to remove an optional / at the end of the URL, now all of /contact, /contact/ and /contact.php all refer to /contact.php:

RewriteCond %{DOCUMENT_ROOT}$1 !-f
RewriteCond %{DOCUMENT_ROOT}$1 !-d
RewriteCond %{DOCUMENT_ROOT}$1\.php -f
RewriteRule ^(.*?)/?$ $1.php [L]

UPDATE

After a lot of cursing I also found out that it depends on whether the RewriteRules are inside a <Directory> directive or .htaccess file on the one hand, or in your <VirtualHost> directive or just in the main body of an httpd.conf on the other hand. When inside a <Directory>/.htaccess, %{REQUEST_FILENAME} does contain the path so my initial solution should work there. Outside of <Directory>, you need to add the %{DOCUMENT_ROOT} yourself.

A: 

I'm not so sure about using REQUEST_FILENAME. REQUEST_FILENAME should point to the full path of the matched file, but you are actually checking it's existence.

I would try something like:

RewriteCond  %{DOCUMENT_ROOT}/$1         !-f
RewriteCond  %{DOCUMENT_ROOT}/$1\.php    -f
RewriteRule  ^(.*)$                      $1.php [L]
Tomas
Yes from the RewriteLog it seems that `REQUEST_FILENAME` only gets populated with the 'full local filesystem path' the docs promise you if it actually *exists*. Your solution seems to solve this problem, I'll try it out!
Wim
Maybe without the / between ${DOCUMENT_ROOT} and $1 ...
Tomas
That's it, thanks! I've also thrown in a '/?' in the regexp to remove an optional / at the end of the URL, now all of `/contact`, `/contact/` and `/contact.php` all refer to `/contact.php`:` RewriteCond %{DOCUMENT_ROOT}$1 !-f`` RewriteCond %{DOCUMENT_ROOT}$1 !-d`` RewriteCond %{DOCUMENT_ROOT}$1\.php -f`` RewriteRule ^(.*?)/?$ $1.php [L]`
Wim
Duh dumping code in comments really doesn't work... Anyone know a better way to do this?
Wim
No. You could add the final answer to the question for clarity... Thanks.
Tomas