Ryan Kanno: The diary of an Enginerd in Hawaii

Everything you’ve ever thought, but never had the balls to say.

Tag Archive » ‘PHP’

CakePHP and IIS and ISAPI Rewrite - Demystified!

Update: 11/16/2007

One of my commenters, James has provided a working production solution versus my “hacked” solution. See the comments and be sure to visit his site. :) Thank you James!


@ work, Stephen and I were tasked with fulfilling a requirement for the big boss, so we selected an up and coming Rails-like framework called CakePHP. Cake’s really fun and easy to use and like Ubuntu, “everything just works“… until you try hooking it up into IIS with ‘pretty URLs’. It took us a day of testing, hair pulling, more testing, more hair pulling, but finally - we’ve debunked the mystery.

First, let me start off by saying that we read all the wiki documentation, searched google groups, and though we found people doing similar things, we didn’t find any solution that satisifed our needs. We found partial solutions with poorly written wiki tutorials, so that’s why you’re reading a brand-new one.

The setup

Our setup consisted of the Cake framework (cake_1.1.6.3264.zip) running on Win2K w/ IIS5 and PHP5 running as an ISAPI Dll. We created a virtual directory named “tp” that’s currently mapped to the app/webroot directory in our Cake installation directory. From reading all the available tutorials, Cake’s functionality all boils down to passing index.php in the app/webroot directory the following:


?url=/controllerName/action/params

This, my friend, is how all the magic begins. So, from the web, I should always be able to reach the following URL:


http://domain.com/tp/index.php?url=/controllerName/action/params

The get-go

Here are the following results from our tests:

Test 1: Do nothing

Stephen and I both hypothesized that by doing nothing, we’d just manually echo out all linking URL’s, i.e. we wouldn’t use the $html->link helper function. This works, period. However, if we do nothing to the configuration, and we do employ the $html->link helper, $html->link(”/controllerName/action”) writes out the following URL:


http://domain.com/controllerName/action

First off, since we have a virtual directory named “tp”, this obviously won’t work. Second, if I define (’WEBROOT_DIR’, ‘tp’) within app/webroot/index.php and then use $html->link(’/controllerName/action’), I get the following URL instead:


http://domain.com/tp/controllerName/action

Closer, but this still doesn’t work because ISAPI Rewrite isn’t enabled. So… that leaves us wondering, how do we use $html->link without modifying the configuration? In any case, we revert the variable WEBROOT_DIR back to its original setting for our next test.

Test 2: Enable Cake Short URLs

With Cake Short URLs enabled, a user will be able to access particular actions via the following URL:


http://domain.com/tp/index.php/controllerName/action

To enable the short URLs, I followed the wiki tutorial. Basically, this involves uncommenting the BASE_URL environment variable and defining (’SERVER_IIS’, true) in core.php in the app/config directory. Now, when I use the $html->link helper, these configurations enabled inserting /tp/index.php/ into the url and everything works! For example, $html->link(’/controllerName/action’) now prints the following:


http://domain.com/tp/index.php/controllerName/action


(And it works too!)

This solves the problem but still doesn’t give us the ideal solution. After all, who wants that index.php within the URL? Not to mention, enabling this configuration setting made it impossible to access the following (original) URL:


http://domain.com/tp/index.php?url=/controllerName/action/params

Is this the expected behavior? As a side note, I can now access URLS as such:


http://domain.com/tp/index.php?/controllerName/action/params

Notice the ‘?’ without the ‘url=’. Is this expected behavior as well? In any case, on to enable ISAPI Rewrite.

Test 3: Enable ISAPI Rewrite

To enable ISAPI Rewrite, we know we had to disable Cake Short URLs by disabling the BASE_URL variable, but at the same time, we decided to leave the IIS_SERVER variable to true. Next, we decided to follow this tutorial on the Cake wiki. No offense to the author, but this entry is incomplete and leaves no explanation as to how the author came to those Rewrite rules. Also, the tutorial doesn’t explain how to enable the pretty URLs for a site running in a virtual directory.

So, we downloaded the ISAPI Rewrite Dll from http://www.isapirewrite.com/. Note, download the free version, but realize that there are limitations on what it can do. Enable the ISAPI Dll @ the Site level since you need the full version for granularity at the virtual directory level. The httpd.ini file that’s listed in the wiki only works if you’re running Cake from the IIS Site level and not from a virtual directory.

Our configuration

Here’s what we did to enable the ISAPI Rewrite from a virtual directory. Our httpd.ini file looks like the following:

[ISAPI_Rewrite] 

// This rule catches the Short URL settings
RewriteRule (.*?\\.php)(\\?[^/]*)?/([^/]*)/(.*) $1(?2$2&:\\?url=/$3/$4) 

//This rule performs the ISAPI Rewrite rules
RewriteRule ^/VIRTUAL_DIRECTORY_NAME_HERE/(.*)/ /VIRTUAL_DIRECTORY_NAME_HERE/index.php?url=/$1

Note, replace virtual_directory_name_here with the name of your virtual directory. As you can see, RewriteRule ^/VIRTUAL_DIRECTORY_NAME_HERE/(.*)/ /VIRTUAL_DIRECTORY_NAME_HERE/index.php?url=/$1 is taking the following URL:

/virtual_directory/controllerName/action/ and rewriting it to /virtual_directory/index.php?url=/controllerName/action.

This is exactly how we want it!

Wait, as you can see though, the RewriteRule matches URLs that have a slash at the end. We figured that the original wiki poster left the slash so that this rule wouldn’t match any of the files being served out of app/webroot such as the css/img files.

Wait… what implications does this have?

Well, this just means that when you use the $html->link helper, you’ll need to end all your actions with a “/”. For example, if you want to link to /controllerName/action, you must now type $html->link(”/controllerName/action/”). Now, this will match the second RewriteRule and everything will work!

However, there’s just one tiny piece we’re forgetting. If you did try this out on your site, you’ll find that the URLs generated from $html->link still don’t have the virtual directory name in it. You’ll see that the links generated will be http://www.domain.com/controllerName/action/. Well, from our experience in past tests, this means you have to define(’WEBROOT_DIR’, ‘virtual_directory_name’) in the app/webroot/index.php file and voila…

Everything now works!

Tagged: , , , , .


Powered by Wordpress. Stalk me.