Monday, January 4, 2010

Writing a URI Regular Expression

A friend of mine was tasked with writing a regular expression that could recognize a Uniform Resource Identifier (URI) and break apart its primary components. Not a terribly difficult task since there are a lot of sample regexs one can just pluck from the Internet. But he asked my opinion and I deferred to RFC 3986 which outlines the generic syntax for URIs.

The RFC provides this example expression:
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
Personally though I think that's rather sloppy. Were I to write the expression from scratch myself then I'd probably be more verbose and restrictive; I'd expressly match patterns specified in the RFC's ABNF. For example, the RFC defines the scheme portion of a URI as:
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
The portion ^([^:/?#]+): will match characters that are not lexically permitted, such as an underscore or percent-sign. Assuming the i (case-insensitive matching) modifier is used, something like ^([A-Z][A-Z\d\+\-\.]*): would be more correct.

This highlights one of the joys of writing regexs; regexs is one of the few areas of computing in which you don't have to be completely accurate to achieve the desired results. A "close-enough" match will suffice most of the time.

While I'm on the topic of regexs, check out gskinner.com's RegExr: Online Regular Expression Testing Tool at www.gskinner.com/RegExr/ if you haven't already. It’s a great utility!

Sunday, January 3, 2010

PHP and SQLite2 on CentOS

I'm changing shared hosting providers for my websites and the sites I manage for clients as Salt City Tech. Most of the sites are basic websites powered by PHP, share a common code base, and store data in MySQL databases. But I've also been taking advantage of the situation to transition the sites from MySQL to SQLite. There are a lot of things that annoy me about SQLite (such as allowing NULLs in primary-key columns, ignoring foreign key constrains, and incomplete ALTER TABLE support) and a few things that I think are pretty awesome (such as user-defined functions in PHP). Pragmatically speaking, SQLite will be more convenient for deployment to and backup from the shared hosting environment and the sites' simple storage requirements fall exactly in SQLite's sweet-spot.

The transition hasn't been terribly difficult... the biggest obstacle has been configuring a development environment that adequately mirrored the shared hosting deployment environment. I happened to have a cloned virtual CentOS 5.3 image at my disposal so I started with that, but the hosting provider supports SQLite v2 (ancient!), which's storage format is incompatible with the newer version 3 in CentOS. The search engines didn't offer me much help in finding a packaged SQLite2 solution on CentOS that would meet my needs, so I figured I'd post a few notes in case someone else may find them helpful.

Obtain the sqlite-2 RPM for CentOS from RPMForge repository (in case you want to work with the database files directly):
wget http://dag.wieers.com/rpm/packages/sqlite/
sqlite-2.8.17-1.el5.rf.i386.rpm
Install sqlite using the -i and --force options (do not use -U so you do not replace sqlite3):
rpm -i --force sqlite-2.8.17-1.el5.rf.i386.rpm
Install the php-devel package so phpize and phpconfig are available:
yum install php-devel
Obtain the source RPM for PHP (CentOS installs 5.1.6--yuck! Now I remember why I hate using packages for important software):
wget ftp://mirror.switch.ch/pool/3/mirror/centos/5.3/os/SRPMS/
php-5.1.6-23.el5.src.rpm
Extract PHP from the SRPM:
rpm2cpio php-5.1.6-23.el5.src.rpm | cpio -id php-5.1.6.tar.gz
Uncompress the archive:
tar zxvf php-5.1.6.tar.gz
Build the sqlite extension using the standard phpize, ./configure, make routine:
cd php-5.1.6/ext/sqlite
phpize
./configure
make
Install the extension:
cp modules/sqlite.so /usr/lib/php/modules/
echo extension=sqlite.so > /etc/php.d/sqlite2.ini
Even though it's been obsoleted by version 3 for almost 6 years now, version 2 of SQLite works fine for my needs here. And God forbid I have to migrate the sites again or the provider upgrades, upgrading my code base is as simple as this:
sqlite site.db.old .dump | sqlite3 site.db
for f in $(ls *php); do
sed -i 's/new SQLiteDatabase/new SQLite3/g' $f
sed -i 's/fetch\(SQLITE_ASSOC\)/fetchArray\(SQLITE3_ASSOC\)/g' $f
done

Friday, January 1, 2010

Happy 2010!

Happy New Year! I hope everyone has had a rewarding holiday and will have a prosperous new year! Last year I tentatively designated 2009 as my "Year of Balance." I wanted to make a concerted effort to focus more on what's really important in life. With a busy full-time job, a death in the family, juggling several side-projects, and buying a house this year (2009 was probably my "Year of Expense" in retrospect with the new house and all the joys that come with home ownership)... my head would probably have exploded had I not been making that effort. I'm not sure what my theme for 2010 will be, but I'll still be doing my best live, laugh, and love as much as I can and I hope you will be to!