A Better Postal/Zip Code Validation Method for CakePHP 1.2

11 Dec
2009

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]) && 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
        )
    );
}
?>

10 Responses to A Better Postal/Zip Code Validation Method for CakePHP 1.2

Avatar

Abba Bryant

December 14th, 2009 at 2:03 pm

Thanks for this, I had solved the same problem ( my company has clients in Canada and the United States and validating either type was a pain) in much the same way. Our code even looks 90% similar, which as I based mine on the original function I guess it should be expected.

Consider opening a ticket in the new cakephp lighthouse to allow for the validation of more than one localized piece of data. Would work for phone, postal codes, etc. Might be a worthwhile addition.

Avatar

Ken Guest

December 15th, 2009 at 5:35 am

Would it not make more sense, and save you time implementing, debugging and updating your own solution, by utilising PEAR’s Validate class ( http://pear.php.net/package/Validate) and other associated classes such as Validate_UK, Validate_US etc?

Also, you’ve a bug in your code – it allows for US zipcodes that the United Stated Postal Service tool at http://zip4.usps.com/zip4/citytown_zip.jsp does not recognise, such as ’00000′ – unless this weak level of validation is intentional?

Avatar

A response to “Better Postal/Zip Code Validation Method for CakePHP 1.2″ « Ken Guest’s online diary

December 15th, 2009 at 5:59 am

[...] a few minutes ago I read Jamie Nay’s A Better Postal/Zip Code Validation Method for CakePHP 1.2 blog [...]

Avatar

Jamie

December 15th, 2009 at 8:14 am

Hi Ken – I posted almost the same response on your blog, but I wanted to repeat much of what I said for the benefit of the readers here.

As my post implies, I was addressing a deficiency with the CakePHP framework’s postal validation code. So, my solution is based on the existing Validation::postal() method that comes with CakePHP. While PEAR is a good solution, it was beyond the scope of my article to suggest scrapping Cake’s entire Validation class in favour of another library. I used the existing regular expressions (from the Cake method), which is why 000000 validates as a US postal code. I might suggest it’s beyond the scope of a data format validator to decide whether a postal code is ‘real’ anyway.

Avatar

Jamie

December 15th, 2009 at 8:15 am

Abba – good call on the lighthouse ticket. I just might do that today (if you haven’t already).

Avatar

mark

December 16th, 2009 at 8:23 pm

check out the new cake1.3 branches
there localized validation is already supported by using different classes
they can be stored in app/libs/localized/XY_validation.php
whereas XY would be your country code

Avatar

Jamie

December 16th, 2009 at 8:38 pm

Thanks for the heads up, Mark – I admit I haven’t had much time to check out 1.3 yet. I was planning to wait until it came out of beta to upgrade, at least on the high traffic production servers we have at work. But I guess that means I don’t have to do a lighthouse ticket now. :)

Avatar

Ken Guest’s Blog: A response to “Better Postal/Zip Code Validation Method for CakePHP 1.2″ | Webs Developer

December 17th, 2009 at 10:01 am

[...] response to a different post he read on a postal/zip code validation topic, Ken Guest has points out other resources that can be [...]

Avatar

Ken Guest’s Blog: A response to “Better Postal/Zip Code Validation Method for CakePHP 1.2″ | Development Blog With Code Updates : Developercast.com

December 17th, 2009 at 10:20 am

[...] response to a different post he read on a postal/zip code validation topic, Ken Guest has points out other resources that can be [...]

Avatar

Schaffer Riggs

January 7th, 2010 at 2:32 pm

I found your blog on technorati and read a couple of of your previous posts. Keep up the good work. I just added up your RSS feed to my Yahoo News Reader. Looking forward to reading more from you down the road!

Comment Form

top