Converting from PHP to ColdFusion

As a bit of relaxation on the Labor Day weekend 2004, I decided to move my site from Hurricane Electric (who have been absolutely fabulous for the last nearly five years!) to SmarterLinux which is a division of HostMySite. They've also been exemplary in their helpfulness, getting me up and running in a very short space of time. In made the move purely so that I could convert my site from PHP over to ColdFusion, and stop all those embarrassing questions about why such a staunch advocate of ColdFusion (me) would be maintaining their own site using another technology!

First Steps

The first thing to do was get the basic site moved across and up and running on the new host. I had a variety of Perl CGI scripts that needed some tweaking, partly to handle the different path (htdocs instead of public_html) and partly to address how SmarterLinux handles sendmail (they require an explicit "from" address be supplied at the command-line). Having moved Movable Type over, none of the database files were readable. Fortunately, I was able to export the entire blog from my old site and import it into the new MT install so nothing was lost (I think!).

PHP to ColdFusion

I copied my mach-ii.xml file to mach-ii-cf.xml and did a find'n'replace to change .php to .cfm throughout. Then I created some shell scripts to do the brunt of the raw file conversion. If you have read my Fusebox to Mach II conversion, you'll know that I set the title in my view pages using this PHP code:

<? $GLOBALS['title'] = "the page title"; ?>

The ColdFusion equivalent is:

<cfset request.title = "the page title" />

A simple sed script (Unix stream editor) combined with the Unix find command allowed me to create .cfm versions of every .php page with the correct title setting code and all references to the local index.php replaced by index.cfm. Time to try http://localhost/index.cfm for the first time... a white screen of death. I picked apart the exception view - it still had PHP code in it. I converted it and tried again. White screen of death. Hmm. Then I realized I had applicationRoot set to "." which was what I had needed for the PHP version (as opposed to "/" which I'm used to from ColdFusion). I set it to "" and tried again. Bingo! An exception page appeared. At least I had a debuggable error to deal with. After about another half hour of rewriting PHP code in a few views to CFML, I was able to get a basic page to appear. I continued replacing PHP <? ?> code with CFML, mostly simple stuff like replacing:

<? include('lay_topnav.php'); ?> and <? echo $GLOBALS['content']; ?>

with:

<cfinclude template="lay_topnav.cfm" /> and <cfoutput>#request.content#</cfoutput>

Soon I had most of the site working in ColdFusion. I wrote another find script to search for <? inside .cfm pages and systematically replaced the last vestiges of PHP code (in the views!) with CFML. It was just looping code or layout code. The next thing to work on was the small collection of PHP classes.

Classes to Components

The PHP version of the site had just two listeners: one to send email, one to power the bookstore. The first one was very simple - a single method that sent email:

function email($who,$where,$email,$subject,$message) {
	$args = compact('who','where','email','subject','message');
	if ( $where == 'corfield.org' || $where == 'bangles.com' ) {
		mail( $who.'@'.$where, '['.$where.'] '.$subject,
			$message, "From: webmaster@corfield.org\nReply-To: ".$email );
	}
}

became:

<cffunction name="email" returntype="void" access="public" output="false">
	<cfargument name="who" type="string" required="yes"/>
	<cfargument name="where" type="string" required="yes"/>
	<cfargument name="email" type="string" required="yes"/>
	<cfargument name="subject" type="string" required="yes"/>
	<cfif arguments.where is 'corfield.org' or arguments.where is 'bangles.com'>
		<cfmail from="webmaster@corfield.org" to="#arguments.who#@#arguments.where#"
			subject="[#arguments.where#] #arguments.subject#"
			replyto="#arguments.email#">#arguments.message#</cfmail>
	</cfif>
</cffunction>

The second one was more daunting. My bookstore section is driven by an XML file that specifies all the sections, books, authors and keywords listed on the bookstore page. In PHP, the XML is parsed with a SAX parser so you need start-element handlers and end-element handlers that are called implicitly as the parser reads the XML. I constructed a tree of objects on the fly for each request based on the XML. It's pretty ugly. You need to keep track of which sub-element you are working on and maintain a lot of state information. ColdFusion provides much neater ways to handle XML so I wrote a completely new listener that read the XML file and called XMLParse() on it and then responded directly to the three renderXxx() calls that were in the corresponding view. Yes, that means I have presentation logic in my model which is not ideal of course but it was the quickest way to provide identical functionality to what I had before and still take advantage of the power of CF. The net result is 200 lines of CFML compared to 400 lines of PHP. I actually do quite a bit of low-level programmatic manipulation on the data in the XML file so I'm not certain that I can just use XSL here. I might look at reorganizing the XML file to make XSLT a possibility in the future.

That was it as far as the website code was concerned. A new, CF-powered corfield.org was up and running with only about a day of work (a long day, admittedly).

Redirects

The final issue was that several RSS aggregators and robots were still spidering the old site because they had not spotted the DNS change. With CF-based aggregators, that seems to be a bug in cfhttp that caches the DNS lookup and never notices a site moved until you restart the server. An msnbot program seemed to be the other major culprit. Since SmarterLinux provide a transition domain ({domain}.tempwebpage.com) while you are getting things set up, I was able to add redirects from certain key files on the old site (e.g., /blog/index.rdf) to the equivalent file on the transitional domain. Makes me glad my old ISP (and my new one!) both use Apache so I can simply slip a couple of Redirect directives into my .htaccess file!

I shall keep track of requests on the old site and see when it seems reasonable to shut down the old account.

Now, what cool things can I do on this site now that I have ColdFusion...?