Relax email validation rules even more.

While filter_var() allows a number of email addresses that
Validation::email() does not, it misses out of email address that
contain IDN host names, and unicode mailboxes. Both of these are
generally deliverable, and should be permitted. filter_var() also fails
on local mailboxes like `root@localhost` which is useful in the context
of cron jobs.

Fixes #3742
This commit is contained in:
mark_story 2014-06-30 10:42:37 -04:00
parent a966f089d2
commit dc34d80f6f
2 changed files with 18 additions and 15 deletions

View file

@ -314,11 +314,13 @@ class CakeEmail {
/**
* Regex for email validation
* If null, filter_var() will be used.
*
* If null, filter_var() will be used. Use the emailPattern() method
* to set a custom pattern.'
*
* @var string
*/
protected $_emailPattern = null;
protected $_emailPattern = '/^((?:[\p{L}0-9!#$%&\'*+\/=?^_`{|}~-]+)*@[\p{L}0-9-.]+)$/ui';
/**
* The class name used for email configuration.
@ -547,8 +549,8 @@ class CakeEmail {
* @param string $regex for email address validation
* @return string|$this
*/
public function emailPattern($regex = null) {
if ($regex === null) {
public function emailPattern($regex = false) {
if ($regex === false) {
return $this->_emailPattern;
}
$this->_emailPattern = $regex;
@ -593,13 +595,12 @@ class CakeEmail {
* @throws SocketException If email address does not validate
*/
protected function _validateEmail($email) {
$valid = (($this->_emailPattern !== null &&
preg_match($this->_emailPattern, $email)) ||
filter_var($email, FILTER_VALIDATE_EMAIL)
);
if (!$valid) {
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
if ($this->_emailPattern === null && filter_var($email, FILTER_VALIDATE_EMAIL)) {
return;
} elseif (preg_match($this->_emailPattern, $email)) {
return;
}
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
}
/**

View file

@ -249,12 +249,16 @@ class CakeEmailTest extends CakeTestCase {
$this->assertSame($this->CakeEmail->to(), $expected);
$list = array(
'root@localhost' => 'root',
'bjørn@hammeröath.com' => 'Bjorn',
'cake@cakephp.org' => 'Cake PHP',
'cake-php@googlegroups.com' => 'Cake Groups',
'root@cakephp.org'
);
$this->CakeEmail->to($list);
$expected = array(
'root@localhost' => 'root',
'bjørn@hammeröath.com' => 'Bjorn',
'cake@cakephp.org' => 'Cake PHP',
'cake-php@googlegroups.com' => 'Cake Groups',
'root@cakephp.org' => 'root@cakephp.org'
@ -265,6 +269,8 @@ class CakeEmailTest extends CakeTestCase {
$this->CakeEmail->addTo('mark_story@cakephp.org', 'Mark Story');
$result = $this->CakeEmail->addTo(array('phpnut@cakephp.org' => 'PhpNut', 'jose_zap@cakephp.org'));
$expected = array(
'root@localhost' => 'root',
'bjørn@hammeröath.com' => 'Bjorn',
'cake@cakephp.org' => 'Cake PHP',
'cake-php@googlegroups.com' => 'Cake Groups',
'root@cakephp.org' => 'root@cakephp.org',
@ -275,11 +281,9 @@ class CakeEmailTest extends CakeTestCase {
);
$this->assertSame($this->CakeEmail->to(), $expected);
$this->assertSame($this->CakeEmail, $result);
$this->setExpectedException('SocketException');
$this->CakeEmail->to(array('cake@localhost', 'CakePHP'));
}
/**
* Data provider function for testBuildInvalidData
*
@ -291,8 +295,6 @@ class CakeEmailTest extends CakeTestCase {
array(''),
array('string'),
array('<tag>'),
array('some@one-whereis'),
array('wrong@key' => 'Name'),
array(array('ok@cakephp.org', 1.0, '', 'string'))
);
}