One of the strong assets of Zend Framework is its rich built in package of validators. It has validators for just about anything, from simple email addresses and digits to credit card numbers and database rows. Yet, sometimes things go wrong and they need to be hacked back on track. Today’s problem was with the email address validator that sometimes generates some very user-unfriendly error messages. Like such:
‘bad.email’ is no valid hostname for email address ‘testing@bad.email’
‘bad.email’ does not match the expected structure for a DNS hostname
‘bad.email’ appears to be a local network name but local network names are not allowed
For the average user, these messages can be very confusing and sometimes is much better to just show an easy to understand “Please enter a correct email” message. How hard can that be with Zend Framework!?! Well…let’s say it’s not as simple as it looks.
The obvious thing to do is to add custom error messages (basically adding the same message over and over again). Like such:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
$email->setOptions( array( 'label' => 'Email', 'required' => true, 'filters' => array( 'StringTrim', 'StripTags', ), 'validators' => array( array( 'EmailAddress', true, array( 'allow' => Zend_Validate_Hostname::ALLOW_DNS, 'domain' => true, 'mx' => true, 'deep' => true, 'messages' => array( Zend_Validate_EmailAddress::INVALID => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_FORMAT => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_HOSTNAME => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_MX_RECORD => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_SEGMENT => 'Please enter a correct email', Zend_Validate_EmailAddress::DOT_ATOM => 'Please enter a correct email', Zend_Validate_EmailAddress::QUOTED_STRING => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_LOCAL_PART => 'Please enter a correct email' ), ), ), ), ) ); |
But it won’t work. That’s because Zend_Validate_EmailAddress calls Zend_Validate_Hostname internally, so custom error messages should be added also for the Zend_Validate_Hostname validator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
$email->setOptions( array( 'label' => 'Email', 'required' => true, 'filters' => array( 'StringTrim', 'StripTags', ), 'validators' => array( array( 'EmailAddress', true, array( 'allow' => Zend_Validate_Hostname::ALLOW_DNS, 'domain' => true, 'mx' => true, 'deep' => true, 'messages' => array( Zend_Validate_EmailAddress::INVALID => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_FORMAT => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_HOSTNAME => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_MX_RECORD => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_SEGMENT => 'Please enter a correct email', Zend_Validate_EmailAddress::DOT_ATOM => 'Please enter a correct email', Zend_Validate_EmailAddress::QUOTED_STRING => 'Please enter a correct email', Zend_Validate_EmailAddress::INVALID_LOCAL_PART => 'Please enter a correct email', Zend_Validate_EmailAddress::LENGTH_EXCEEDED => 'Please enter a correct email', Zend_Validate_Hostname::CANNOT_DECODE_PUNYCODE => 'Please enter a correct email', Zend_Validate_Hostname::INVALID => 'Please enter a correct email', Zend_Validate_Hostname::INVALID_DASH => 'Please enter a correct email', Zend_Validate_Hostname::INVALID_HOSTNAME => 'Please enter a correct email', Zend_Validate_Hostname::INVALID_HOSTNAME_SCHEMA => 'Please enter a correct email', Zend_Validate_Hostname::INVALID_LOCAL_NAME => 'Please enter a correct email', Zend_Validate_Hostname::INVALID_URI => 'Please enter a correct email', Zend_Validate_Hostname::IP_ADDRESS_NOT_ALLOWED => 'Please enter a correct email', Zend_Validate_Hostname::LOCAL_NAME_NOT_ALLOWED => 'Please enter a correct email', Zend_Validate_Hostname::UNDECIPHERABLE_TLD => 'Please enter a correct email', Zend_Validate_Hostname::UNKNOWN_TLD => 'Please enter a correct email', ), ), ), ), ) ); |
Pretty long. Yet still not working. But it is somewhat better – as no creepy error messages are being displayed – instead the same message appears multiple times. This is not a validator chain, so the programmer can’t force the breaking of the chain after the first failed test 🙁
In the end, after few hours of digging through the code and the docs, I came up with my own solution, which still harnesses the power of the original Zend_Validate_EmailAddress validator while providing a way to add a simple “Please enter a correct email” message. One time :). It uses the Zend_Validate_Callback class and PHP 5.3 anonymus functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
$email->setOptions( array( 'label' => 'Email', 'required' => TRUE, 'filters' => array( 'StringTrim', 'StripTags', ), 'validators' => array( array( 'Callback', true, array( 'callback' => function($value) { $validator = new Zend_Validate_EmailAddress( array( 'allow' => Zend_Validate_Hostname::ALLOW_DNS, 'domain' => true, 'mx' => true, 'deep' => true, ) ); return $validator->isValid($value); }, 'messages' => array( Zend_Validate_Callback::INVALID_VALUE => 'Please enter a correct email', ), ), ), ), ) ); |
It might seem a little far fetched, but it works 😛