On the pitfalls of date validation with the Zend Framework

I’m writing this post as a warning for people using Zend_Date to validate dates, either as a standalone or as a validator in a chain. I’ve been using Zend_Validate_Date validator, which uses the Zend_Date::isDate() method internally, for a while now – mainly for form processing.

I’ve recently completed a project where a very bizarre bug would occur on some machines, and I wasn’t able to reproduce it myself on any test machine that I tried. The bug manifested in a calendar system we built for the project, and in certain situations form submissions would not pass the date validation through Zend_Validate_Date, despite using the exact same input that was passing on the test machines.

After bringing in one of the “affected” machines for testing, I used the process of elimination to determine the problem originates in the Zend_Date::isDate() method, which has different behavior on different machines.

Zend_Date tries to validate dates according to a given format (with a default fallback). The dangerous behavior is that it tries to convert the given format to a localized format using Zend_Locale. Zend_Locale attempts to detect automatically the locale of the requesting client, and it appears that on the machines that were exhibiting the bug, a different locale was determined than those I was testing it on.

Despite trying to validate a non-localized format (to be exact, the MySQL timestamp format – YYYY-MM-dd HH:mm:sss), it was being converted on the affected machine sdue to the auto-detection by Zend_Locale (on a side note – it was happening on Internet Explorer 8 on Windows 7). To avoid this issue, I set the locale for all requests manually to en_US, since I don’t have any other use for Zend_Locale in the application. I put the following lines in the bootstrap –

$locale = new Zend_Locale('en_US');
Zend_Registry::set('Zend_Locale', $locale);

As recommended by the manual to achieve this effect.

In my opinion, the Locale should be not be auto-detected by default – it should be an opt-in feature if it affects other components behind the scenes.