EmailAddressTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Validate
  17. * @subpackage UnitTests
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. if (!defined('PHPUnit_MAIN_METHOD')) {
  23. define('PHPUnit_MAIN_METHOD', 'Zend_Validate_EmailAddressTest::main');
  24. }
  25. /**
  26. * Test helper
  27. */
  28. require_once dirname(__FILE__) . '/../../TestHelper.php';
  29. /**
  30. * @see Zend_Validate_EmailAddress
  31. */
  32. require_once 'Zend/Validate/EmailAddress.php';
  33. /**
  34. * @category Zend
  35. * @package Zend_Validate
  36. * @subpackage UnitTests
  37. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. * @group Zend_Validate
  40. */
  41. class Zend_Validate_EmailAddressTest extends PHPUnit_Framework_TestCase
  42. {
  43. /**
  44. * Default instance created for all test methods
  45. *
  46. * @var Zend_Validate_EmailAddress
  47. */
  48. protected $_validator;
  49. /**
  50. * Runs this test suite
  51. *
  52. * @return void
  53. */
  54. public static function main()
  55. {
  56. $suite = new PHPUnit_Framework_TestSuite(__CLASS__);
  57. $result = PHPUnit_TextUI_TestRunner::run($suite);
  58. }
  59. /**
  60. * Creates a new Zend_Validate_EmailAddress object for each test method
  61. *
  62. * @return void
  63. */
  64. public function setUp()
  65. {
  66. $this->_validator = new Zend_Validate_EmailAddress();
  67. }
  68. /**
  69. * Ensures that a basic valid e-mail address passes validation
  70. *
  71. * @return void
  72. */
  73. public function testBasic()
  74. {
  75. $this->assertTrue($this->_validator->isValid('username@example.com'));
  76. }
  77. /**
  78. * Ensures that localhost address is valid
  79. *
  80. * @return void
  81. */
  82. public function testLocalhostAllowed()
  83. {
  84. $validator = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_ALL);
  85. $this->assertTrue($validator->isValid('username@localhost'));
  86. }
  87. /**
  88. * Ensures that local domain names are valid
  89. *
  90. * @return void
  91. */
  92. public function testLocaldomainAllowed()
  93. {
  94. $validator = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_ALL);
  95. $this->assertTrue($validator->isValid('username@localhost.localdomain'));
  96. }
  97. /**
  98. * Ensures that IP hostnames are valid
  99. *
  100. * @return void
  101. */
  102. public function testIPAllowed()
  103. {
  104. $validator = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_DNS | Zend_Validate_Hostname::ALLOW_IP);
  105. $valuesExpected = array(
  106. array(Zend_Validate_Hostname::ALLOW_DNS, true, array('bob@212.212.20.4')),
  107. array(Zend_Validate_Hostname::ALLOW_DNS, false, array('bob@localhost'))
  108. );
  109. foreach ($valuesExpected as $element) {
  110. foreach ($element[2] as $input) {
  111. $this->assertEquals($element[1], $validator->isValid($input), implode("\n", $validator->getMessages()));
  112. }
  113. }
  114. }
  115. /**
  116. * Ensures that validation fails when the local part is missing
  117. *
  118. * @return void
  119. */
  120. public function testLocalPartMissing()
  121. {
  122. $this->assertFalse($this->_validator->isValid('@example.com'));
  123. $messages = $this->_validator->getMessages();
  124. $this->assertEquals(1, count($messages));
  125. $this->assertContains('local-part@hostname', current($messages));
  126. }
  127. /**
  128. * Ensures that validation fails and produces the expected messages when the local part is invalid
  129. *
  130. * @return void
  131. */
  132. public function testLocalPartInvalid()
  133. {
  134. $this->assertFalse($this->_validator->isValid('Some User@example.com'));
  135. $messages = $this->_validator->getMessages();
  136. $this->assertEquals(3, count($messages));
  137. $this->assertContains('Some User', current($messages));
  138. $this->assertContains('dot-atom', current($messages));
  139. $this->assertContains('Some User', next($messages));
  140. $this->assertContains('quoted-string', current($messages));
  141. $this->assertContains('Some User', next($messages));
  142. $this->assertContains('no valid local part', current($messages));
  143. }
  144. /**
  145. * Ensures that no validation failure message is produced when the local part follows the quoted-string format
  146. *
  147. * @return void
  148. */
  149. public function testLocalPartQuotedString()
  150. {
  151. $this->assertTrue($this->_validator->isValid('"Some User"@example.com'));
  152. $messages = $this->_validator->getMessages();
  153. $this->assertType('array', $messages);
  154. $this->assertEquals(0, count($messages));
  155. }
  156. /**
  157. * Ensures that validation fails when the hostname is invalid
  158. *
  159. * @return void
  160. */
  161. public function testHostnameInvalid()
  162. {
  163. $this->assertFalse($this->_validator->isValid('username@ example . com'));
  164. $messages = $this->_validator->getMessages();
  165. $this->assertThat(count($messages), $this->greaterThanOrEqual(1));
  166. $this->assertContains('no valid hostname', current($messages));
  167. }
  168. /**
  169. * Ensures that quoted-string local part is considered valid
  170. *
  171. * @return void
  172. */
  173. public function testQuotedString()
  174. {
  175. $emailAddresses = array(
  176. '"username"@example.com',
  177. '"bob%jones"@domain.com',
  178. '"bob jones"@domain.com',
  179. '"bob@jones"@domain.com',
  180. '"[[ bob ]]"@domain.com',
  181. '"jones"@domain.com'
  182. );
  183. foreach ($emailAddresses as $input) {
  184. $this->assertTrue($this->_validator->isValid($input), "$input failed to pass validation:\n"
  185. . implode("\n", $this->_validator->getMessages()));
  186. }
  187. }
  188. /**
  189. * Ensures that validation fails when the e-mail is given as for display,
  190. * with angle brackets around the actual address
  191. *
  192. * @return void
  193. */
  194. public function testEmailDisplay()
  195. {
  196. $this->assertFalse($this->_validator->isValid('User Name <username@example.com>'));
  197. $messages = $this->_validator->getMessages();
  198. $this->assertThat(count($messages), $this->greaterThanOrEqual(3));
  199. $this->assertContains('no valid hostname', current($messages));
  200. $this->assertContains('cannot match TLD', next($messages));
  201. $this->assertContains('does not appear to be a valid local network name', next($messages));
  202. }
  203. /**
  204. * Ensures that the validator follows expected behavior for valid email addresses
  205. *
  206. * @return void
  207. */
  208. public function testBasicValid()
  209. {
  210. $emailAddresses = array(
  211. 'bob@domain.com',
  212. 'bob.jones@domain.co.uk',
  213. 'bob.jones.smythe@domain.co.uk',
  214. 'BoB@domain.museum',
  215. 'bobjones@domain.info',
  216. "B.O'Callaghan@domain.com",
  217. 'bob+jones@domain.us',
  218. 'bob+jones@domain.co.uk',
  219. 'bob@some.domain.uk.com',
  220. 'bob@verylongdomainsupercalifragilisticexpialidociousspoonfulofsugar.com'
  221. );
  222. foreach ($emailAddresses as $input) {
  223. $this->assertTrue($this->_validator->isValid($input), "$input failed to pass validation:\n"
  224. . implode("\n", $this->_validator->getMessages()));
  225. }
  226. }
  227. /**
  228. * Ensures that the validator follows expected behavior for invalid email addresses
  229. *
  230. * @return void
  231. */
  232. public function testBasicInvalid()
  233. {
  234. $emailAddresses = array(
  235. '',
  236. 'bob
  237. @domain.com',
  238. 'bob jones@domain.com',
  239. '.bobJones@studio24.com',
  240. 'bobJones.@studio24.com',
  241. 'bob.Jones.@studio24.com',
  242. '"bob%jones@domain.com',
  243. 'bob@verylongdomainsupercalifragilisticexpialidociousaspoonfulofsugar.com',
  244. 'bob+domain.com',
  245. 'bob.domain.com',
  246. 'bob @domain.com',
  247. 'bob@ domain.com',
  248. 'bob @ domain.com',
  249. 'Abc..123@example.com'
  250. );
  251. foreach ($emailAddresses as $input) {
  252. $this->assertFalse($this->_validator->isValid($input), implode("\n", $this->_validator->getMessages()) . $input);
  253. }
  254. }
  255. /**
  256. * Ensures that the validator follows expected behavior for valid email addresses with complex local parts
  257. *
  258. * @return void
  259. */
  260. public function testComplexLocalValid()
  261. {
  262. $emailAddresses = array(
  263. 'Bob.Jones@domain.com',
  264. 'Bob.Jones!@domain.com',
  265. 'Bob&Jones@domain.com',
  266. '/Bob.Jones@domain.com',
  267. '#Bob.Jones@domain.com',
  268. 'Bob.Jones?@domain.com',
  269. 'Bob~Jones@domain.com'
  270. );
  271. foreach ($emailAddresses as $input) {
  272. $this->assertTrue($this->_validator->isValid($input));
  273. }
  274. }
  275. /**
  276. * Ensures that the validator follows expected behavior for checking MX records
  277. *
  278. * @return void
  279. */
  280. public function testMXRecords()
  281. {
  282. if (!defined('TESTS_ZEND_VALIDATE_ONLINE_ENABLED')
  283. || !constant('TESTS_ZEND_VALIDATE_ONLINE_ENABLED')
  284. ) {
  285. $this->markTestSkipped('Testing MX records only works when a valid internet connection is available');
  286. return;
  287. }
  288. $validator = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_DNS, true);
  289. // Are MX checks supported by this system?
  290. if (!$validator->validateMxSupported()) {
  291. $this->markTestSkipped('Testing MX records is not supported with this configuration');
  292. return;
  293. }
  294. $valuesExpected = array(
  295. array(true, array('Bob.Jones@zend.com', 'Bob.Jones@php.net')),
  296. array(false, array('Bob.Jones@bad.example.com', 'Bob.Jones@anotherbad.example.com'))
  297. );
  298. foreach ($valuesExpected as $element) {
  299. foreach ($element[1] as $input) {
  300. $this->assertEquals($element[0], $validator->isValid($input), implode("\n", $validator->getMessages()));
  301. }
  302. }
  303. // Try a check via setting the option via a method
  304. unset($validator);
  305. $validator = new Zend_Validate_EmailAddress();
  306. $validator->setValidateMx(true);
  307. foreach ($valuesExpected as $element) {
  308. foreach ($element[1] as $input) {
  309. $this->assertEquals($element[0], $validator->isValid($input), implode("\n", $validator->getMessages()));
  310. }
  311. }
  312. }
  313. /**
  314. * Test changing hostname settings via EmailAddress object
  315. *
  316. * @return void
  317. */
  318. public function testHostnameSettings()
  319. {
  320. $validator = new Zend_Validate_EmailAddress();
  321. // Check no IDN matching
  322. $validator->getHostnameValidator()->setValidateIdn(false);
  323. $valuesExpected = array(
  324. array(false, array('name@b�rger.de', 'name@h�llo.de', 'name@h�llo.se'))
  325. );
  326. foreach ($valuesExpected as $element) {
  327. foreach ($element[1] as $input) {
  328. $this->assertEquals($element[0], $validator->isValid($input), implode("\n", $validator->getMessages()));
  329. }
  330. }
  331. // Check no TLD matching
  332. $validator->getHostnameValidator()->setValidateTld(false);
  333. $valuesExpected = array(
  334. array(true, array('name@domain.xx', 'name@domain.zz', 'name@domain.madeup'))
  335. );
  336. foreach ($valuesExpected as $element) {
  337. foreach ($element[1] as $input) {
  338. $this->assertEquals($element[0], $validator->isValid($input), implode("\n", $validator->getMessages()));
  339. }
  340. }
  341. }
  342. /**
  343. * Ensures that getMessages() returns expected default value (an empty array)
  344. *
  345. * @return void
  346. */
  347. public function testGetMessages()
  348. {
  349. $this->assertEquals(array(), $this->_validator->getMessages());
  350. }
  351. /**
  352. * @see ZF-2861
  353. */
  354. public function testHostnameValidatorMessagesShouldBeTranslated()
  355. {
  356. require_once 'Zend/Validate/Hostname.php';
  357. $hostnameValidator = new Zend_Validate_Hostname();
  358. require_once 'Zend/Translate.php';
  359. $translations = array(
  360. 'hostnameIpAddressNotAllowed' => 'hostnameIpAddressNotAllowed translation',
  361. 'hostnameUnknownTld' => 'hostnameUnknownTld translation',
  362. 'hostnameDashCharacter' => 'hostnameDashCharacter translation',
  363. 'hostnameInvalidHostnameSchema' => 'hostnameInvalidHostnameSchema translation',
  364. 'hostnameUndecipherableTld' => 'hostnameUndecipherableTld translation',
  365. 'hostnameInvalidHostname' => 'hostnameInvalidHostname translation',
  366. 'hostnameInvalidLocalName' => 'hostnameInvalidLocalName translation',
  367. 'hostnameLocalNameNotAllowed' => 'hostnameLocalNameNotAllowed translation',
  368. );
  369. $translator = new Zend_Translate('array', $translations);
  370. $this->_validator->setTranslator($translator)->setHostnameValidator($hostnameValidator);
  371. $this->_validator->isValid('_XX.!!3xx@0.239,512.777');
  372. $messages = $hostnameValidator->getMessages();
  373. $found = false;
  374. foreach ($messages as $code => $message) {
  375. if (array_key_exists($code, $translations)) {
  376. $this->assertEquals($translations[$code], $message);
  377. $found = true;
  378. break;
  379. }
  380. }
  381. $this->assertTrue($found);
  382. }
  383. /**
  384. * @see ZF-4888
  385. */
  386. public function testEmailsExceedingLength()
  387. {
  388. $emailAddresses = array(
  389. 'thislocalpathoftheemailadressislongerthantheallowedsizeof64characters@domain.com',
  390. 'bob@verylongdomainsupercalifragilisticexpialidociousspoonfulofsugarverylongdomainsupercalifragilisticexpialidociousspoonfulofsugarverylongdomainsupercalifragilisticexpialidociousspoonfulofsugarverylongdomainsupercalifragilisticexpialidociousspoonfulofsugarexpialidociousspoonfulofsugar.com',
  391. );
  392. foreach ($emailAddresses as $input) {
  393. $this->assertFalse($this->_validator->isValid($input));
  394. }
  395. }
  396. /**
  397. * @see ZF-4352
  398. */
  399. public function testNonStringValidation()
  400. {
  401. $this->assertFalse($this->_validator->isValid(array(1 => 1)));
  402. }
  403. /**
  404. * @see ZF-7490
  405. */
  406. public function testSettingHostnameMessagesThroughEmailValidator()
  407. {
  408. $translations = array(
  409. 'hostnameIpAddressNotAllowed' => 'hostnameIpAddressNotAllowed translation',
  410. 'hostnameUnknownTld' => 'hostnameUnknownTld translation',
  411. 'hostnameDashCharacter' => 'hostnameDashCharacter translation',
  412. 'hostnameInvalidHostnameSchema' => 'hostnameInvalidHostnameSchema translation',
  413. 'hostnameUndecipherableTld' => 'hostnameUndecipherableTld translation',
  414. 'hostnameInvalidHostname' => 'hostnameInvalidHostname translation',
  415. 'hostnameInvalidLocalName' => 'hostnameInvalidLocalName translation',
  416. 'hostnameLocalNameNotAllowed' => 'hostnameLocalNameNotAllowed translation',
  417. );
  418. $this->_validator->setMessages($translations);
  419. $this->_validator->isValid('_XX.!!3xx@0.239,512.777');
  420. $messages = $this->_validator->getMessages();
  421. $found = false;
  422. foreach ($messages as $code => $message) {
  423. if (array_key_exists($code, $translations)) {
  424. $this->assertEquals($translations[$code], $message);
  425. $found = true;
  426. break;
  427. }
  428. }
  429. $this->assertTrue($found);
  430. }
  431. /**
  432. * Testing initializing with several options
  433. */
  434. public function testInstanceWithOldOptions()
  435. {
  436. $handler = set_error_handler(array($this, 'errorHandler'), E_USER_NOTICE);
  437. $validator = new Zend_Validate_EmailAddress();
  438. $options = $validator->getOptions();
  439. $this->assertEquals(Zend_Validate_Hostname::ALLOW_DNS, $options['allow']);
  440. $this->assertFalse($options['mx']);
  441. try {
  442. $validator = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_ALL, true, new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL));
  443. $options = $validator->getOptions();
  444. $this->assertEquals(Zend_Validate_Hostname::ALLOW_ALL, $options['allow']);
  445. $this->assertTrue($options['mx']);
  446. set_error_handler($handler);
  447. } catch (Zend_Exception $e) {
  448. $this->markTestSkipped('MX not available on this system');
  449. }
  450. }
  451. /**
  452. * Testing setOptions
  453. */
  454. public function testSetOptions()
  455. {
  456. $this->_validator->setOptions(array('messages' => array(Zend_Validate_EmailAddress::INVALID => 'TestMessage')));
  457. $messages = $this->_validator->getMessageTemplates();
  458. $this->assertEquals('TestMessage', $messages[Zend_Validate_EmailAddress::INVALID]);
  459. $oldHostname = $this->_validator->getHostnameValidator();
  460. $this->_validator->setOptions(array('hostname' => new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL)));
  461. $hostname = $this->_validator->getHostnameValidator();
  462. $this->assertNotEquals($oldHostname, $hostname);
  463. }
  464. /**
  465. * Testing setMessage
  466. */
  467. public function testSetSingleMessage()
  468. {
  469. $messages = $this->_validator->getMessageTemplates();
  470. $this->assertNotEquals('TestMessage', $messages[Zend_Validate_EmailAddress::INVALID]);
  471. $this->_validator->setMessage('TestMessage');
  472. $messages = $this->_validator->getMessageTemplates();
  473. $this->assertEquals('TestMessage', $messages[Zend_Validate_EmailAddress::INVALID]);
  474. }
  475. /**
  476. * Testing validateMxSupported
  477. */
  478. public function testValidateMxSupported()
  479. {
  480. if (function_exists('getmxrr')) {
  481. $this->assertTrue($this->_validator->validateMxSupported());
  482. } else {
  483. $this->assertFalse($this->_validator->validateMxSupported());
  484. }
  485. }
  486. /**
  487. * Testing getValidateMx
  488. */
  489. public function testGetValidateMx()
  490. {
  491. $this->assertFalse($this->_validator->getValidateMx());
  492. }
  493. /**
  494. * Testing getDeepMxCheck
  495. */
  496. public function testGetDeepMxCheck()
  497. {
  498. $this->assertFalse($this->_validator->getDeepMxCheck());
  499. }
  500. /**
  501. * Testing getDomainCheck
  502. */
  503. public function testGetDomainCheck()
  504. {
  505. $this->assertTrue($this->_validator->getDomainCheck());
  506. }
  507. public function errorHandler($errno, $errstr)
  508. {
  509. if (strstr($errstr, 'deprecated')) {
  510. $this->multipleOptionsDetected = true;
  511. }
  512. }
  513. }
  514. if (PHPUnit_MAIN_METHOD == 'Zend_Validate_EmailAddressTest::main') {
  515. Zend_Validate_EmailAddressTest::main();
  516. }