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
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.
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?
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 [...]
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.
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).
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
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.
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 [...]
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 [...]
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!