Clean urls with isapi rewrite on iis
Forced to deal with a windows based server, without apache and effectively also mod_rewrite? But, after much complaining and begging your sysadmin has been kind enough to install isapi_rewrite on that (already bloated) iis box... then this is for you!
This article (can this be called an article) is about clean and pretty uri's for cakephp, or anything else with an url dispatcher thingy.
Why, because im not a iis guru (I usually stay as much away from iis as humanly possible), and because of this I had some trouble giving my cake based webapps a nice and elegant url scheme. Allthough there where some skinny isapi_rewrite examples floating around here somewhere, they provided inadequate and not very friendly. The most usefull snippet i found, was directing any requests with a trailing slash to the index.php in the webroot, and the rest was treated as a normal ugly url to make sure your css, img and js dirs where still possible to get to.
So i figured, i do know mod_rewrite pretty ok, and because regexp can get a bit intimidating i decided to publish what i think is a nice way to do things, so here is the httpd.ini / htaccess.ini rewrite rules i've been using for a while now:
Download code
Ofcourse, all files in the webroot are on the same level as the webservers document root. The actual libs and code are outside of the servers docroot, as it should be.
Why, because im not a iis guru (I usually stay as much away from iis as humanly possible), and because of this I had some trouble giving my cake based webapps a nice and elegant url scheme. Allthough there where some skinny isapi_rewrite examples floating around here somewhere, they provided inadequate and not very friendly. The most usefull snippet i found, was directing any requests with a trailing slash to the index.php in the webroot, and the rest was treated as a normal ugly url to make sure your css, img and js dirs where still possible to get to.
So i figured, i do know mod_rewrite pretty ok, and because regexp can get a bit intimidating i decided to publish what i think is a nice way to do things, so here is the httpd.ini / htaccess.ini rewrite rules i've been using for a while now:
Download code
[ISAPI_Rewrite]
RewriteCond URL (?!/js/|/img/|/files/|/css/).*
RewriteRule (.*?\.php)(\?[^/]*)?/([^/]*)/(.*) $1(?2$2&:\?url=/$3/$4)
RewriteCond URL (?!/js/|/img/|/files/|/css/).*
RewriteRule ^/(.*) /index.php?url=/$1 [L]
RewriteCond URL (?!/js/|/img/|/files/|/css/).*
RewriteRule /(.*) /$1
Ofcourse, all files in the webroot are on the same level as the webservers document root. The actual libs and code are outside of the servers docroot, as it should be.
Comments
Question
1 which file gets replaced
A standard Cake install has:
/httpdocs/.htaccess
/httpdocs/app/.htaccess
/httpdocs/app/webroot/.htaccess
which file(s) does this httpd.ini replace for?
Comment
2 for v3
# Version 3.0.0.28
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]
Comment
3 slight problem with 3rd rule
Test url:
/controller/function/?key1=val1&key2=val2
Original 3rd rule:
RewriteRule ^/(.*) /index.php?url=/$1 [L]
Original Result:
/index.php?url=/controller/function/?key1=val1&key2=val2
The Fix...
New 3rd Rule:
RewriteRule ^/(.*)(\?.*) /index.php$2&url=/$1 [L]
New output:
/index.php?key1=val1&key2=val2&url=/controller/function/
P.S. I am no regular expression expert, so I sure there could be a better solution, and I have not catered for a clean url if url being tested was /controller/function/?, not that this should be problem though. Also, at the moment, the eventual rules would be:
RewriteCond URL (?!/assets/|/js/|/img/|/files/|/css/).*
RewriteRule (.*?\.php)(\?[^/]*)?/([^/]*)/(.*) $1(?2$2&:\?url=/$3/$4)
RewriteCond URL (?!/assets/|/js/|/img/|/files/|/css/).*
RewriteRule ^/(.*)(\?.*) /index.php$2&url=/$1 [L]
RewriteCond URL (?!/assets/|/js/|/img/|/files/|/css/).*
RewriteRule ^/(.*) /index.php?url=/$1 [L]
RewriteCond URL (?!/assets/|/js/|/img/|/files/|/css/).*
RewriteRule /(.*) /$1
I've kept the original 3rd rule, as we need to cater for both plain urls and those with querystrings already in them.