How to set up a basic mod_rewrite?

I've heard that you can use mod_rewrite to clean up your URLs, and basically I'd like to make it so the .php file extension isn't shown in the URL.

For example, let's say I have the following file structure on a site:

/index.php
/about.php
/contact.php
/css/main.css
/img/animage.jpg
/admin/index.php
/admin/login.php
/admin/admin.php

I would like to make the following basic changes with mod_rewrite:

  • When a request is made to the root i.e. /about, if a directory is found called about, then it should behave as a directory nomrally does (i.e. load the index.php from the direcotry).
  • If a directory is not found, it should point to about.php
  • If a request for a .php file is made, it should 301 redirect to the filename without the .php extension.
  • Only the directories which would actually be viewed directly in the browser should have these URL changes (i.e. the root and the admin directory), therefore css and img should have their URLs unchanged.

How can I make those changes using mod_rewrite?


In .htaccess file:

RewriteEngine On
RewriteBase /

# Abort on directories, skip sub-requests
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .? - [L,NS]

# Check if there is php file (add extension)
RewriteCond %{REQUEST_URI}\.php -f
RewriteRule (^.*) $1\.php [L]

#Redirect explicit php requests (if file exist)
RewriteCond %{REQUEST_FILENAME} -f
# strange - REQUEST_URI always contains .php
# have to parse whole request line
# look for .php in URI (fields are space separated) but before '?' (query string)
RewriteCond %{THE_REQUEST} ^[^\ ]+\ /[^\ \?]*\.php
RewriteRule (.*)\.php$ $1 [NS,R=301]

mod_rewrite is extremely powerful :)