THIS CONTENT IS OUT OF DATE! IF YOU’RE USING CAKE 2, YOU SHOULDN’T READ THIS.

The Validation::postal() method that comes with CakePHP 1.2 is good in that it can handle a number of different country formats, but the problem is you can only validate your data against one country. What if you want to accept, say, either Canadian or US postal/zip code formats? I ran into this problem earlier today, and decided to write my own postal() function that can take either a string as the country, just like Validation::postal(), or an array of countries.

Here’s the function, which also resides in its Github repository:

<?php
class AppModel extends Model {
    /**
     * Modified version of Validation::postal - allows for multiple
     * countries to be specified as an array.
     */
    function postal($check, $regex = null, $country = null) {
        // List of regular expressions to use, if a custom one isn't specified.
        $countryRegs = array(
            'uk' => '/\\A\\b[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][ABD-HJLNP-UW-Z]{2}\\b\\z/i',
            'ca' => '/\\A\\b[ABCEGHJKLMNPRSTVXY][0-9][A-Z][ ]?[0-9][A-Z][0-9]\\b\\z/i',
            'it' => '/^[0-9]{5}$/i',
            'de' => '/^[0-9]{5}$/i',
            'be' => '/^[1-9]{1}[0-9]{3}$/i',
            'us' => '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i',
            'default' => '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i' // Same as US.
        );

        $value = array_values($check);
        $value = $value[0];
        if ($regex) {
            return preg_match($regex, $value);
        } else if (!is_array($country)) {
            return preg_match($countryRegs[$country], $value);
        }

        foreach ($country as $check) {
            if (!isset($countryRegs[$check]) &amp;&amp; preg_match($countryRegs['default'], $value)) {
                return true;
            } else if (preg_match($countryRegs[$check], $value)) {
                return true;
            }
        }

        return false;
    }
}
?>

I put the function in my AppModel, but you can put it in an individual model if you don’t want it to apply to every model in your application. Usage is pretty simple. For example, to validate data that can be either US or Canadian format:

<?php
class MyModel extends AppModel {
    var $validate = array(
        'postal_zip' => array(
            'rule' => array('postal', null, array('us', 'ca')),
            'message' => 'Please enter a valid postal or zip code.',
            'required' => true
        )
    );
}
?>