<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>DesignDivine Project Blog &#187; taavo</title>
	<atom:link href="http://blog.designdivine.com/author/taavo/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.designdivine.com</link>
	<description>Current Projects, News, Thoughts on Design &#38; Development</description>
	<lastBuildDate>Thu, 12 Jan 2012 17:22:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Attaching .docx files via PHP</title>
		<link>http://blog.designdivine.com/2011/06/attaching-docx-files-via-php/</link>
		<comments>http://blog.designdivine.com/2011/06/attaching-docx-files-via-php/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 22:00:03 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=2539</guid>
		<description><![CDATA[Interesting bug today: A client&#8217;s web form takes file uploads and forwards them as email attachments. Script works great for .doc files, but .docx files end up as mysterious attachments with filenames like ATT00010.txt, whose content starts with this: application/vnd.openxmlformats-officedocument.wordprocessingml.document; name="filename.docx" Content-Disposition: attachment; filename="filename.docx" Content-Transfer-Encoding: base64 This &#8220;header&#8221; is followed by a bunch of base64 [...]]]></description>
			<content:encoded><![CDATA[<p>Interesting bug today: A client&#8217;s web form takes file uploads and forwards them as email attachments. Script works great for .doc files, but .docx files end up as mysterious attachments with filenames like ATT00010.txt, whose content starts with this:</p>
<pre>application/vnd.openxmlformats-officedocument.wordprocessingml.document;
name="filename.docx"
Content-Disposition: attachment;
filename="filename.docx"
Content-Transfer-Encoding: base64</pre>
<p>This &#8220;header&#8221; is followed by a bunch of base64 gobbledygook. In short, my original attachment appeared to be getting itself wrapped in an attachment, prefixed with its headers minus the string &#8220;Content-Type: &#8220;.</p>
<p>Turns out the problem was line-wrapping. I was hardwrapping the entire message to ensure a maximum line length of 70 characters (as recommended by <a href="http://php.net/manual/en/function.mail.php">the docs</a>), and this was causing the obscenely long (&gt; 70 character) mime type used by .docx to wrap onto a separate line from the string &#8220;Content-Type:&#8221;. Subsequently, Outlook was seeing a blank content type, freaking out, and putting the rest of the message into an attachment.</p>
<p>Moral of the story: Don&#8217;t hardwrap your email headers. Or use <a href="http://swiftmailer.org/">a library</a> which keeps you from worrying about absurd implementational details.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2011/06/attaching-docx-files-via-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
		<item>
		<title>One WordPress Install, Multiple Sites</title>
		<link>http://blog.designdivine.com/2010/12/one-wordpress-install-multiple-sites/</link>
		<comments>http://blog.designdivine.com/2010/12/one-wordpress-install-multiple-sites/#comments</comments>
		<pubDate>Wed, 15 Dec 2010 17:05:13 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=1602</guid>
		<description><![CDATA[One of our clients wanted two sites—two URLs, two designs, two sets of content—on a single WordPress install. They wanted to be able to log into a single admin area to manage both sites, and to be able to make posts of certain categories show up on both sites, while other posts would be limited [...]]]></description>
			<content:encoded><![CDATA[<p>One of our clients wanted two sites—two URLs, two designs, two sets of content—on a single WordPress install. They wanted to be able to log into a single admin area to manage both sites, and to be able to make posts of certain categories show up on both sites, while other posts would be limited to just one or the other.</p>
<p>I found my solution in rewrites. Users visit a url such as &#8220;example1.com/about&#8221; or &#8220;example2.com/about&#8221;, and I rewrite it so WordPress treats it as &#8220;example1.com/example1/about&#8221; or &#8220;example1.com/example2/about&#8221; without the user knowing the difference. I tried three different options before stumbling on one that worked well.</p>
<p>1) .htaccess</p>
<p>Didn&#8217;t work. Why? Because WordPress is expecting queries to be directed to index.php, and then it looks at REQUEST_URI to figure out how to dispatch the request. I couldn&#8217;t find a way to change REQUEST_URI with an apache rewrite without directing the request away from WordPress.</p>
<p>2) WordPress rewrite_rules</p>
<p>I got this working, but it was punishingly slow. On every page load, I had WordPress regenerate its rewrite_rules, depending on which HTTP_HOST is being accessed. </p>
<p>3) Change REQUEST_URI inside WordPress</p>
<p>Sounds scarier than it is. As soon as the request is inside WordPress—I chose wp-config.php, because it&#8217;s designed to be user editable—check which HTTP_HOST is being accessed, and then change the REQUEST_URI appropriately. </p>
<p>From there it&#8217;s just a matter of implementing a zillion WordPress hooks to change URLs whenever you output them, to remove the site prefixes. And to filter certain categories from blog listings, blog archives, et cetera. But I&#8217;ll save that for another post.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2010/12/one-wordpress-install-multiple-sites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
		<item>
		<title>PHP-MSSQL on Linux: Easier Than You&#8217;ve Heard</title>
		<link>http://blog.designdivine.com/2010/10/php-mssql-on-linux-easier-than-youve-heard/</link>
		<comments>http://blog.designdivine.com/2010/10/php-mssql-on-linux-easier-than-youve-heard/#comments</comments>
		<pubDate>Mon, 25 Oct 2010 19:23:44 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Server Configuration]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=1328</guid>
		<description><![CDATA[We&#8217;ve integrated in-house Microsoft SQL Server databases with public PHP web sites a number of times, now. Until today, this meant dealing with Windows VPSes for even modest sites, simply because we were unable to find a Windows shared hosting plan which permitted access to remote databases, and all the research I could find suggested [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve integrated in-house Microsoft SQL Server databases with public PHP web sites a number of times, now. Until today, this meant dealing with Windows VPSes for even modest sites, simply because we were unable to find a Windows shared hosting plan which permitted access to remote databases, and all the research I could find suggested connecting to MS SQL from PHP on Linux was an absolute mess.</p>
<p>Those days appear to be over.</p>
<p><code>yum install php-mssql</code></p>
<p>That, my friends, is all we had to do, thanks to the <a href="http://blog.designdivine.com/2010/06/28/install-php5-on-an-uncooperative-vps/">atomic rocket turtle repository and our earlier efforts to modernize our server</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2010/10/php-mssql-on-linux-easier-than-youve-heard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
		<item>
		<title>301 Redirects on IIS 6 with ISAPI_Rewrite</title>
		<link>http://blog.designdivine.com/2010/09/301-redirects-on-iis-6-with-isapi_rewrite/</link>
		<comments>http://blog.designdivine.com/2010/09/301-redirects-on-iis-6-with-isapi_rewrite/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 19:03:15 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Server Configuration]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=981</guid>
		<description><![CDATA[We just launched a new site for one of our clients, and one small improvement we made was replacing all the old and ugly (and not especially SEO-friendly) URLs like /cand_jobs.shtml with shiny new ones like /jobs. The catch here is that Google&#8217;s existing index refers to all the old URLs, and we risk serving [...]]]></description>
			<content:encoded><![CDATA[<p>We just launched a new site for one of our clients, and one small improvement we made was replacing all the old and ugly (and not especially SEO-friendly) URLs like /cand_jobs.shtml with shiny new ones like /jobs. The catch here is that Google&#8217;s existing index refers to all the old URLs, and we risk serving up 404&#8242;s and losing Google juice if we don&#8217;t implement 301 redirects from all the old URLs to the new ones.</p>
<p>On Apache, the normal way to handle this is to add lines like this to your .htaccess:</p>
<p>redirect 301 /old.htm http://www.example.com/new</p>
<p>Unfortunately, in this case we aren&#8217;t using Apache&#8211;we&#8217;re using IIS 6. I could set up redirects from within IIS itself, but as far as I can tell that would require creating dummy files for each of our old URLs, and telling IIS to redirect each to their new URL, and I&#8217;m not interested in having a bunch of dummy files lying around waiting for someone to accidentally delete them. Instead, the smart way to approach the problem is via ISAPI_Rewrite, an IIS module which mimics some parts of Apache&#8217;s configuration, which we happen to already have installed.</p>
<p>Long story short, add this to your httpd.conf:</p>
<p>RewriteCond ^old\.htm$ new [R=301,L]</p>
<p>Why is such a trivial solution worthy of a blog post? Because it took me more than an hour trying different combinations of options to find one that would work. Why? Because <a href="http://www.isapirewrite.com/docs/">ISAPI_Rewrite 2&#8242;s documentation</a> has better Google juice than <a href="http://www.helicontech.com/isapi_rewrite/doc/">ISAPI_Rewrite 3&#8242;s</a>, and I wasted my hour scouring the wrong one and following the advice of others running that version.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2010/09/301-redirects-on-iis-6-with-isapi_rewrite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
		<item>
		<title>Troubleshooting WordPress Automatic Updates on IIS 6</title>
		<link>http://blog.designdivine.com/2010/08/troubleshooting-wordpress-automatic-updates-on-iis-6/</link>
		<comments>http://blog.designdivine.com/2010/08/troubleshooting-wordpress-automatic-updates-on-iis-6/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 14:38:20 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Server Configuration]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=713</guid>
		<description><![CDATA[WordPress automatic updates are awesome. When they work, they&#8217;re as easy as a click of a button. When they fail, however, you&#8217;re left either reconciling yourself to an eternity of manual updates, or troubleshooting your host&#8211;a process that routinely takes much longer than applying the update manually would&#8217;ve. In this case, my VPS was running [...]]]></description>
			<content:encoded><![CDATA[<p>WordPress automatic updates are awesome. When they work, they&#8217;re as easy as a click of a button. When they fail, however, you&#8217;re left either reconciling yourself to an eternity of manual updates, or troubleshooting your host&#8211;a process that routinely takes much longer than applying the update manually would&#8217;ve.</p>
<p>In this case, my VPS was running IIS 6 and the updates weren&#8217;t working. First, the update screen would merely say it was downloading the new version, and it would never make any progress. Then, when I extended PHP&#8217;s max_execution_time, I encountered a FastCGI internal error saying the process exceeded the configured activity timeout. When I corrected that, WordPress reported permissions errors while trying to move the new files into place. My full solution was as follows:</p>
<h3>Backup Everything</h3>
<p>Any time I&#8217;m updating anything; download a full &#038; current copy of the site, and export all tables from the database.</p>
<h3>Fix the FastCGI Timeout</h3>
<p>Open \WINDOWS\system32\inetsrv\fcgiext.ini, and, in the section labelled PHP, add ActivityTimeout = X, where X is the desired number of seconds after which to terminate an unresponsive script. Restart IIS.</p>
<h3>Fix Permissions</h3>
<p>Much like how apache is often configured to run as &#8220;nobody&#8221; in order to prevent malicious scripts from modifying files, IIS (by default) runs as a user named IUSR_[hostname], where [hostname] will be a string you set up when initially configuring your site. Unlike apache, however, on IIS, 777 permissions don&#8217;t necessarily mean any user is permitted to write to a given file or directory.</p>
<p>To fix the problem I had to open up my web root in IIS, and give my IUSR_[hostname] full permissions. I was then able to run the update, after which for security purposes I reduced that users permissions to the original level.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2010/08/troubleshooting-wordpress-automatic-updates-on-iis-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
		<item>
		<title>Install PHP5 on an Uncooperative VPS</title>
		<link>http://blog.designdivine.com/2010/06/install-php5-on-an-uncooperative-vps/</link>
		<comments>http://blog.designdivine.com/2010/06/install-php5-on-an-uncooperative-vps/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 18:56:33 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Server Configuration]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php5]]></category>
		<category><![CDATA[server updates]]></category>
		<category><![CDATA[server upgrades]]></category>
		<category><![CDATA[VPS]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=602</guid>
		<description><![CDATA[A VPS is the standard upgrade when conventional shared hosting won&#8217;t meet your needs. The catch, and most hosts try not to make this clear, is that you&#8217;re then on the hook for all configuration, upgrades, and maintenance. And as an added bonus, many hosts offer default VPS installs configured as though they&#8217;re deliberately trying [...]]]></description>
			<content:encoded><![CDATA[<p>A VPS is the standard upgrade when conventional shared hosting won&#8217;t meet your needs. The catch, and most hosts try not to make this clear, is that you&#8217;re then on the hook for all configuration, upgrades, and maintenance. And as an added bonus, many hosts offer default VPS installs configured as though they&#8217;re deliberately trying to make administration difficult.</p>
<p>For a recent project hosted on one of our VPSes, I was planning to use <a href="http://kohanaframework.org/">Kohana</a>, which requires PHP5. Despite the fact that <a href="http://en.wikipedia.org/wiki/PHP">PHP5 was released in 2004</a>, it wasn&#8217;t installed on the VPS in question. As the VPS was running Plesk, any changes to the PHP installation would have to be made carefully so as not to demolish our hosted sites, but research revealed the <a href="http://www.atomicorp.com/wiki/index.php/PHP">Atomic Rocket Turtle Repository</a>, designed exactly for upgrading machines such as mine. Except that yum wasn&#8217;t even installed.</p>
<p>The procedure was as follows:</p>
<p><b>Install yum</b></p>
<p><i>Note: If you&#8217;re following along at home, instead of just copy pasting my terminal commands, you should probably make sure your rpm -Uvh calls are requesting <a href="http://mirror.centos.org/centos/4/os/i386/CentOS/RPMS/">contemporary versions</a></i></p>
<p>First, install a key from the CentOS mirrors so rpm will work:<br />
rpm –import http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-4</p>
<p>Then, try and fail to install yum in order to get a full list of missing dependencies:<br />
rpm -Uvh http://mirror.centos.org/centos/4/os/i386/CentOS/RPMS/yum-2.4.3-3.el4.centos.noarch.rpm</p>
<p>Next, install each listed dependency with a call to rpm -Uvh</p>
<p>Finally, install yum by re-running the rpm command above</p>
<p>(based on instructions <a href="http://dancameron.org/general/installing-yum-on-centos-4">here</a>)</p>
<p><b>Set up the <a href="http://www.atomicorp.com/wiki/index.php/PHP">Atomic Rocket Turtle repository</a></b></p>
<p>wget -q -O &#8211; http://www.atomicorp.com/installers/atomic.sh | sh</p>
<p><b>Upgrade PHP</b></p>
<p>yum upgrade php</p>
<p><b>Reinstall Ioncube Loader</b></p>
<p>(<i>Note: As we weren&#8217;t using the Ioncube Loader, everything worked without this step. Except that we were getting notices in our logs saying it was missing.</i>)</p>
<p>yum install php-ioncube-loader</p>
<p><b>Set up new (default) php.ini</b></p>
<p>mv /etc/php.ini /etc/php.ini.php4<br />
mv /etc/php.ini.rpmnew /etc/php.ini</p>
<p><b>Restart Plesk</b></p>
<p>/etc/init.d/psa stopall<br />
/etc/init.d/psa startall<br />
/etc/init.d/psa restart</p>
<p>Miraculously, Plesk restarted successfully and all my applications were fully functional under the new install of PHP5.</p>
<p>I could&#8217;ve stopped here, but because the VPS had been running for a few years, and yum hadn&#8217;t been installed, I knew that basically everything (if not <i>literally</i> everything) on the server was out of date. Research and testing aside, the above took less than 10 minutes. The below (upgrading <i>everything</i>) took several hours of troubleshooting.</p>
<p><b>Upgrade everything server-wide</b></p>
<p>yum upgrade</p>
<p>(<i>Note: This might take a while. I made sure to archive the output, because when anything goes wrong, the clues will show up here.</i>)</p>
<p><b>Set up new MySQL configuration</b></p>
<p>(<i>Note: At this point, Plesk wouldn&#8217;t restart because MySQL (just upgraded from 4 to 5) was totally broken.</i>)</p>
<p>mv /etc/my.cnf /etc/my.cnf.old<br />
mv /etc/my.cnf.rpmnew /etc/my.cnf</p>
<p><b>Install new Plesk package to support openssl upgrade</b></p>
<p>(<i>Note: Now MySQL worked, but Plesk was still broken.</i>)</p>
<p>If you update from an old vesion of openssl, you&#8217;re probably going to run into a bug, the quick solution to which you can find <a href="http://kb.parallels.com/8338">here</a>.</p>
<p><b>Update MySQL databases</b></p>
<p>(<i>Note: Plesk would restart, but I couldn&#8217;t log in.</i>)</p>
<p>mysqlcheck &#8211;check-upgrade &#8211;all-databases &#8211;auto-repair -uadmin -pyouradminpassword</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2010/06/install-php5-on-an-uncooperative-vps/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
		<item>
		<title>Updating Drupal</title>
		<link>http://blog.designdivine.com/2009/07/updating-drupal/</link>
		<comments>http://blog.designdivine.com/2009/07/updating-drupal/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 17:43:57 +0000</pubDate>
		<dc:creator>taavo</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Drupal]]></category>

		<guid isPermaLink="false">http://blog.designdivine.com/?p=597</guid>
		<description><![CDATA[Compared to WordPress&#8217;s automated self-updates, Drupal&#8217;s update process is something of a chore. This chore isn&#8217;t made any easier by Drupal&#8217;s documentation (also here), which at the time of writing takes up nine pages, is self-contradictory, unnecessarily time-consuming and somewhat paranoid. And it never offers a canonical pragmatic checklist. After reading all the documentation I [...]]]></description>
			<content:encoded><![CDATA[<p>Compared to WordPress&#8217;s automated self-updates, Drupal&#8217;s update process is something of a chore. This chore isn&#8217;t made any easier by Drupal&#8217;s <a href="http://drupal.org/upgrade/">documentation</a> (also <a href="http://drupal.org/upgrade/tutorial-introduction">here</a>), which at the time of writing takes up nine pages, is self-contradictory, unnecessarily time-consuming and somewhat paranoid. And it never offers a canonical pragmatic checklist.</p>
<p>After reading all the documentation I could stand and going through the process a number of times, this is the protocol I&#8217;ve developed for myself:</p>
<p><b>1. Make sure all your modules are compatible with the new version</b></p>
<p>If they aren&#8217;t, you should deal with this <i>before</i> the update, not after.</p>
<p><b>2. Back up all the files, and the database</b></p>
<p>If anything goes wrong, I need to be able to revert to a known-working state. This also serves as a useful archive, in case anything goes wrong with the site between updates.</p>
<p><b>3. Put the system in maintenance mode</b></p>
<p>This will prevent any visitors from potentially encountering a scarily-broken web site before you&#8217;re done upgrading.</p>
<p><b>4. Create a temporary folder, and move all the existing files in there</b></p>
<p>Don&#8217;t want to run the risk of overwriting anything important (especially .htaccess or /sites). Alternately, you could delete your whole site and then re-upload, but this is faster.</p>
<p><b>5. Upload the new version of Drupal</b></p>
<p><b>6. Replace the freshly installed /sites/all folder with the old one from your temporary directory or your backup</b></p>
<p>This should restore all modules and themes. You&#8217;ll notice that I haven&#8217;t disabled any modules or themes prior to the update: I only work with custom themes, and so far none have broken in an update. I try to use as few modules as possible on any given site, and <i>always</i> check to ensure essential modules are compatible prior to an update.</p>
<p><b>7. Move /sites/default/files from your temporary directory or backup to /sites/default/files.</b></p>
<p>You might need to change the permissions on the old /sites/default/files to do so.</p>
<p><b>8. Reconcile /sites/default/settings.php</b></p>
<p>Compare the old /sites/default/default.settings.php to new one. If they match, you can just move the old /sites/default/settings.php to the new /sites/default directory. If they don&#8217;t, you need to open the old /sites/default/settings.php, copy /sites/default/default.settings.php to /sites/default/default.settings.php,<br />
and migrate all settings to the new /sites/default/settings.php we just<br />
created.</p>
<p><b>9. Reconcile .htaccess</b></p>
<p>If I&#8217;m getting Internal Server Errors after the update, it&#8217;s nearly always because I missed something in this step. Compare your old .htaccess to your new .htaccess, and make sure to migrate any changes over. For me, this nearly always means enabling RewriteBase (to support pretty urls), and ensuring Drupal runs under PHP5 (required by many modules).</p>
<p><b>10. Run update.php</b></p>
<p>This will upgrade all your database tables to the new version.</p>
<p><b>11. Take the system out of maintenance mode</b></p>
<p><b>12. Visit /admin/reports/updates to make sure everything is ok there</b></p>
<p><b>13. Verify functionality</b></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.designdivine.com/2009/07/updating-drupal/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<enclosure url="" type="image/jpeg" />

	</item>
	</channel>
</rss>

