I’ve been coding PHP for a long time. Since 1999 actually. That means that for most of my adult life, I’ve been working with this programming language in the web-o-sphere in general. I’ve gotten to work on many applications and continue to do so. I’ve also gotten to use many off-the-shelf apps including WordPress, Expression Engine and VBulletin. Today, I’d like to rant about two conventions that these all have in common, and why we need to be rid of them.
1. Storing paths and URLs in the database
This happens in WordPress, Expression Engine and VBulletin. Basically, the idea is that all settings must be stored in a database table because…well…it’s supposed to be easier. The user updates a setting in the admin control panel, and it stores those settings in a database. The problem with storing paths in a database like this is that it makes the app less portable. For example, say you want to move an installation of any of the above-said apps to a different domain, it’s not as simple as tarballing the entire application, running mysqldump and restoring on the other side. You’d think that changing the config file would get it to work but this is only half the battle. WordPress and Vbulletin, for example, stores the actual URL of the application in the database, so when it does any redirect (e.g. when you login to the admin control panel), it will redirect to your OLD site.
WordPress does something else that I consider evil. When you upload images, it stores the full web path in the meta data. This is also a problem when you move to another domain because all your images are now pointing to the old domain. I’ve had to write scripts that change all metadata values and wordpress settings when porting from one domain to another. It’s annoying.
Why is this an issue though?
Development. For most people, the above shouldn’t matter because you have a blog that you installed on a webserver; you update it and all’s well. You never run a local copy of the site for development. As a developer though, I have to usually get local and staging copies of the website running. This means that I’m constantly having to do all kinds of shenanigans to get these instances running on different servers.
I used to think that this was simply a bad design limited to a couple of web apps but it seems like a whole plethora of web apps suffer from this. While working for Gnomon, we bought into Expression Engine, thinking that this would be the silver bullet that kills WordPress. Nada. EE is just as BADLY designed! (not just for the reasons above, but many others)
2. Serializing Critical Settings
PHP has a neat function called serialize(). It takes data and turns it into a string. The data can be read back in easily. This is great for many things. For example, if you have user accounts and each user has their own settings, it’s probably useful to just serialize their settings data and save it as a single string in the database.
Crucial site settings though, should NEVER be serialized in a database. I would go as far to say that as a rule of thumb, if the setting is crucial enough to make or break an installation of an app, it should be in a config file. This relates to my first rant as well. Many settings can be put in the database, but some settings (like paths), should just be in flat config files that can be quickly changed when moving the app.
I was absolutely shocked when using Expression Engine that crucial app-breaking settings like upload paths were not only stored in the database but SERIALIZED. I ended up writing a script that can move an entire installation of EE from one server to another in a single command line, and it’s really long because it had to connect to the database, unserialize the data, make modifications, re-serialize the data, write back to database.
It shouldn’t be this hard.
My recommendation
My recommendation is to follow this rule of thumb: if the setting is crucial enough to make or break an installation of an app, it should be in a config file.
Absolute paths like upload paths, etc. should be stored in a config file.
If the application needs a site-wide URL, this should be in a config file.
Individual asset links in the database should link to the relative location (i.e. minus the hostname.) e.g. not http://leonardteo.com/image1.jpg, but /image1.jpg instead. Even better, just store ‘image1.jpg’ and use a configuration setting to determine what the path to that image is.
The litmus test should be: Tarball an application, dump the database. Copy everything to a different computer/hostname. Restore everything. If you can’t get the site up and running again without accessing and changing values in the database, fail.
A practical benefit – fast deployment
On a closing note, one of the benefits of running critical site settings in config files, is that you can switch configurations based on the hostname.
E.g. in your config file:
switch ($_SERVER['SERVER_NAME']){
case 'cgacontest.local':
define('SITE_MODE', "LOCAL");
break;
case 'cgacontest.test':
define('SITE_MODE', "TEST");
break;
case '3dsmaxdesign.cgarchitect.com':
define('SITE_MODE', "LIVE");
break;
}
With the above code, we can switch between site modes and run different configurations automatically based on the hostname. This means that when it comes to deployment, I simply push any changes to the server without having to change configuration.