diff --git a/class.phpmailer.php b/class.phpmailer.php index 1c157474..c49bb7d1 100644 --- a/class.phpmailer.php +++ b/class.phpmailer.php @@ -447,6 +447,15 @@ class PHPMailer */ public $XMailer = ''; + /** + * Which validator to use by default when validating email addresses. + * May be a callable to inject your own validator, but there are several built-in validators. + * @see PHPMailer::validateAddress() + * @var string|callable + * @static + */ + public static $validator = 'auto'; + /** * An instance of the SMTP sender class. * @var SMTP @@ -1028,19 +1037,30 @@ class PHPMailer /** * Check that a string looks like an email address. * @param string $address The email address to check - * @param string $patternselect A selector for the validation pattern to use : + * @param string|callable $patternselect A selector for the validation pattern to use : * * `auto` Pick best pattern automatically; * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; * * `pcre` Use old PCRE implementation; * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. * @return boolean * @static * @access public */ - public static function validateAddress($address, $patternselect = 'auto') + public static function validateAddress($address, $patternselect = null) { + if (is_null($patternselect)) { + $patternselect = self::$validator; + } + if (is_callable($patternselect)) { + return call_user_func($patternselect, $address); + } //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { return false; diff --git a/test/phpmailerTest.php b/test/phpmailerTest.php index e41a0d61..69eba1e7 100644 --- a/test/phpmailerTest.php +++ b/test/phpmailerTest.php @@ -515,7 +515,7 @@ class PHPMailerTest extends PHPUnit_Framework_TestCase '"Doug "Ace" L."@iana.org', 'Doug\ \"Ace\"\ L\.@iana.org', 'hello world@iana.org', - //'helloworld@iana .org', + 'helloworld@iana .org', 'gatsby@f.sc.ot.t.f.i.tzg.era.l.d.', 'test.iana.org', 'test.@iana.org', @@ -606,7 +606,9 @@ class PHPMailerTest extends PHPUnit_Framework_TestCase 'first.last@[IPv6:a1:a2:a3:a4:b1:b2:b3:]', 'first.last@[IPv6::a2:a3:a4:b1:b2:b3:b4]', 'first.last@[IPv6:a1:a2:a3:a4::b1:b2:b3:b4]', - "(\r\n RCPT TO:user@example.com\r\n DATA \\\nSubject: spam10\\\n\r\n Hello,\r\n this is a spam mail.\\\n.\r\n QUIT\r\n ) a@example.net" //This is valid RCC5322, but we don't want to allow it + //This is a valid RCC5322 address, but we don't want to allow it for obvious reasons! + "(\r\n RCPT TO:user@example.com\r\n DATA \\\nSubject: spam10\\\n\r\n Hello,\r\n". + " this is a spam mail.\\\n.\r\n QUIT\r\n ) a@example.net" ); // IDNs in Unicode and ASCII forms. $unicodeaddresses = array( @@ -657,6 +659,53 @@ class PHPMailerTest extends PHPUnit_Framework_TestCase $this->assertFalse(PHPMailer::validateAddress('bad', 'noregex')); } + /** + * Test injecting a custom validator. + */ + public function testCustomValidator() + { + //Inject a one-off custom validator + $this->assertTrue( + PHPMailer::validateAddress( + 'user@example.com', + function ($address) { + return (strpos($address, '@') !== false); + } + ), + 'Custom validator false negative' + ); + $this->assertFalse( + PHPMailer::validateAddress( + 'userexample.com', + function ($address) { + return (strpos($address, '@') !== false); + } + ), + 'Custom validator false positive' + ); + //Set the default validator to an injected function + PHPMailer::$validator = function ($address) { + return ('user@example.com' === $address); + }; + $this->assertTrue( + $this->Mail->addAddress('user@example.com'), + 'Custom default validator false negative' + ); + $this->assertFalse( + //Need to pick a failing value which would pass all other validators + //to be sure we're using our custom one + $this->Mail->addAddress('bananas@example.com'), + 'Custom default validator false positive' + ); + //Set default validator to PHP built-in + PHPMailer::$validator = 'php'; + $this->assertFalse( + //This is a valid address that FILTER_VALIDATE_EMAIL thinks is invalid + $this->Mail->addAddress('first.last@example.123'), + 'PHP validator not behaving as expected' + ); + } + /** * Word-wrap an ASCII message. */