#62 - Change validation interface

This commit is contained in:
Eduardo Gulias Davis
2016-04-30 00:48:07 +02:00
parent fa5dd33577
commit 0f768c989e
30 changed files with 417 additions and 429 deletions
+16 -45
View File
@@ -6,44 +6,36 @@ use Egulias\EmailValidator\Warning\NoDNSMXRecord;
use Egulias\EmailValidator\Warning\NoDNSRecord;
use Egulias\EmailValidator\Warning\DomainLiteral;
use Egulias\EmailValidator\Warning\TLD;
use Egulias\EmailValidator\Validation\EmailValidation;
/**
* EmailValidator
*
* @author Eduardo Gulias Davis <me@egulias.com>
*/
class EmailValidator
{
const ERR_DEPREC_REACHED = 151;
protected $parser;
/**
* @var EmailLexer
*/
private $lexer;
protected $warnings;
protected $error;
protected $threshold = 255;
public function __construct()
{
$this->parser = new EmailParser(new EmailLexer());
$this->lexer = new EmailLexer();
}
public function isValid($email, $checkDNS = false, $strict = false)
/**
* @param $email
* @param EmailValidation $emailValidation
* @return bool
*/
public function isValid($email, EmailValidation $emailValidation)
{
try {
$this->parser->parse((string)$email);
$this->warnings = $this->parser->getWarnings();
} catch (InvalidEmail $invalid) {
$this->error = $invalid->getCode();
return false;
} catch (\Exception $e) {
$rClass = new \ReflectionClass($this);
$this->error = $rClass->getConstant($e->getMessage());
return false;
}
$dns = true;
if ($checkDNS) {
$dns = $this->checkDNS();
}
$isValid = $emailValidation->isValid($email, $this->lexer);
$this->warnings = $emailValidation->getWarnings();
$this->error = $emailValidation->getError();
return $isValid;
// if ($this->hasWarnings() && ((int) max($this->warnings) > $this->threshold)) {
// $this->error = self::ERR_DEPREC_REACHED;
@@ -51,7 +43,6 @@ class EmailValidator
// return false;
// }
return !$strict || (!$this->hasWarnings() && $dns);
}
/**
@@ -78,26 +69,6 @@ class EmailValidator
return $this->error;
}
/**
* @param int $threshold
*
* @return EmailValidator
*/
public function setThreshold($threshold)
{
$this->threshold = (int) $threshold;
return $this;
}
/**
* @return int
*/
public function getThreshold()
{
return $this->threshold;
}
protected function checkDNS()
{
$checked = true;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class AtextAfterCFWS extends InvalidEmail
{
const CODE = 133;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class CRLFAtTheEnd extends InvalidEmail
{
const CODE = 149;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class CRLFX2 extends InvalidEmail
{
const CODE = 148;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class CRNoLF extends InvalidEmail
{
const CODE = 150;
@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CharNotAllowed extends InvalidEmail
{
const CODE = 201;
const REASON = "Non allowed character in domain";
}
@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CommaInDomain extends InvalidEmail
{
const CODE = 200;
const REASON = "Comma ',' is not allowed in domain part";
}
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class ConsecutiveAt extends InvalidEmail
{
const CODE = 128;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class ConsecutiveDot extends InvalidEmail
{
const CODE = 132;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class DomainHyphened extends InvalidEmail
{
const CODE = 144;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class DotAtEnd extends InvalidEmail
{
const CODE = 142;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class DotAtStart extends InvalidEmail
{
const CODE = 141;
@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingAT extends InvalidEmail
{
const CODE = 202;
const REASON = "Expecting AT '@' ";
}
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class ExpectingATEXT extends InvalidEmail
{
const CODE = 137;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class ExpectingCTEXT extends InvalidEmail
{
const CODE = 139;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class ExpectingDTEXT extends InvalidEmail
{
const CODE = 129;
@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingDomainLiteralClose extends InvalidEmail
{
const CODE = 137;
const REASON = "Closing bracket ']' for domain literal not found";
}
@@ -2,10 +2,8 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class ExpectedQPair extends InvalidEmail
{
const CODE = 136;
const REASON = "Expecting QPAIR";
}
}
@@ -1,9 +1,12 @@
<?php
namespace Egulias\EmailValidator;
namespace Egulias\EmailValidator\Exception;
abstract class InvalidEmail extends \InvalidArgumentException
{
const REASON = "Invalid email";
const CODE = 0;
public function __construct()
{
parent::__construct(static::REASON, static::CODE);
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class NoDomainPart extends InvalidEmail
{
const CODE = 131;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class NoLocalPart extends InvalidEmail
{
const CODE = 130;
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class UnclosedComment extends InvalidEmail
{
const CODE = 146;
@@ -2,11 +2,8 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class UnclosedQuotedString extends InvalidEmail
{
const CODE = 145;
const REASON = "Unclosed quoted string";
}
}
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\InvalidEmail;
class UnopenedComment extends InvalidEmail
{
const CODE = 152;
@@ -4,6 +4,8 @@
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\CharNotAllowed;
use Egulias\EmailValidator\Exception\CommaInDomain;
use Egulias\EmailValidator\Exception\ConsecutiveAt;
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
use Egulias\EmailValidator\Exception\CRNoLF;
@@ -11,6 +13,7 @@ use Egulias\EmailValidator\Exception\DomainHyphened;
use Egulias\EmailValidator\Exception\DotAtEnd;
use Egulias\EmailValidator\Exception\DotAtStart;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\ExpectingDomainLiteralClose;
use Egulias\EmailValidator\Exception\ExpectingDTEXT;
use Egulias\EmailValidator\Exception\NoDomainPart;
use Egulias\EmailValidator\EmailValidator;
@@ -131,7 +134,7 @@ class DomainPart extends Parser
$prev = $this->lexer->getPrevious();
if ($this->lexer->token['type'] === EmailLexer::S_SLASH) {
throw new \InvalidArgumentException('ERR_DOMAIN_CHAR_NOT_ALLOWED');
throw new CharNotAllowed();
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
@@ -291,7 +294,7 @@ class DomainPart extends Parser
}
if ($this->lexer->token['type'] === EmailLexer::S_COMMA) {
throw new \InvalidArgumentException('ERR_COMMA_IN_DOMAIN');
throw new CommaInDomain();
}
if ($this->lexer->token['type'] === EmailLexer::S_AT) {
@@ -321,7 +324,7 @@ class DomainPart extends Parser
try {
$this->lexer->find(EmailLexer::S_CLOSEBRACKET);
} catch (\RuntimeException $e) {
throw new \InvalidArgumentException('ERR_EXPECTING_DOMLIT_CLOSE');
throw new ExpectingDomainLiteralClose();
}
return true;
@@ -6,7 +6,9 @@ use Egulias\EmailValidator\Exception\DotAtEnd;
use Egulias\EmailValidator\Exception\DotAtStart;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Exception\ExpectingAT;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
use Egulias\EmailValidator\Exception\UnopenedComment;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
use Egulias\EmailValidator\Warning\LocalTooLong;
@@ -94,7 +96,7 @@ class LocalPart extends Parser
$this->lexer->moveNext();
if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
throw new \InvalidArgumentException('ERR_EXPECTED_ATEXT');
throw new ExpectingATEXT();
}
}
@@ -102,12 +104,12 @@ class LocalPart extends Parser
if ($prev['type'] === EmailLexer::S_BACKSLASH) {
if (!$this->checkDQUOTE(false)) {
throw new \InvalidArgumentException('ERR_UNCLOSED_DQUOTE');
throw new UnclosedQuotedString();
}
}
if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
throw new \InvalidArgumentException('ERR_EXPECED_AT');
throw new ExpectingAT();
}
return $parseAgain;
@@ -0,0 +1,20 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
interface EmailValidation
{
public function isValid($email, EmailLexer $emailLexer);
/**
* @return InvalidArgumentException or InvalidEmail
*/
public function getError();
/**
* @return array of Warning
*/
public function getWarnings();
}
@@ -0,0 +1,38 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\EmailParser;
use Egulias\EmailValidator\Exception\InvalidEmail;
class RFCValidation implements EmailValidation
{
private $parser;
private $warnings;
private $error;
public function isValid($email, EmailLexer $emailLexer)
{
$this->parser = new EmailParser($emailLexer);
try {
$this->parser->parse((string)$email);
} catch (InvalidEmail $invalid) {
$this->error = $invalid;
return false;
}
$this->warnings = $this->parser->getWarnings();
return true;
}
public function getError()
{
return $this->error;
}
public function getWarnings()
{
return $this->warnings;
}
}
@@ -3,348 +3,17 @@
namespace Egulias\Tests\EmailValidator;
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Exception\AtextAfterCFWS;
use Egulias\EmailValidator\Exception\ConsecutiveAt;
use Egulias\EmailValidator\Exception\ConsecutiveDot;
use Egulias\EmailValidator\Exception\CRNoLF;
use Egulias\EmailValidator\Exception\DomainHyphened;
use Egulias\EmailValidator\Exception\DotAtEnd;
use Egulias\EmailValidator\Exception\DotAtStart;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\ExpectingDTEXT;
use Egulias\EmailValidator\Exception\NoDomainPart;
use Egulias\EmailValidator\Exception\NoLocalPart;
use Egulias\EmailValidator\Exception\UnclosedComment;
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
use Egulias\EmailValidator\Exception\UnopenedComment;
use Egulias\EmailValidator\Warning\AddressLiteral;
use Egulias\EmailValidator\Warning\CFWSNearAt;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
use Egulias\EmailValidator\Warning\Comment;
use Egulias\EmailValidator\Warning\DomainLiteral;
use Egulias\EmailValidator\Warning\DomainTooLong;
use Egulias\EmailValidator\Warning\IPV6BadChar;
use Egulias\EmailValidator\Warning\IPV6ColonEnd;
use Egulias\EmailValidator\Warning\IPV6ColonStart;
use Egulias\EmailValidator\Warning\IPV6Deprecated;
use Egulias\EmailValidator\Warning\IPV6DoubleColon;
use Egulias\EmailValidator\Warning\IPV6GroupCount;
use Egulias\EmailValidator\Warning\IPV6MaxGroups;
use Egulias\EmailValidator\Warning\LabelTooLong;
use Egulias\EmailValidator\Warning\LocalTooLong;
use Egulias\EmailValidator\Warning\NoDNSMXRecord;
use Egulias\EmailValidator\Warning\NoDNSRecord;
use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
use Egulias\EmailValidator\Warning\QuotedString;
class EmailValidatorTest extends \PHPUnit_Framework_TestCase
{
protected $validator;
protected function setUp()
public function testValidationIsUsed()
{
$this->validator = new EmailValidator();
}
$validator = new EmailValidator();
$validation = $this->getMock("Egulias\\EmailValidator\\Validation\\EmailValidation");
$validation->expects($this->once())->method("isValid")->willReturn(true);
$validation->expects($this->once())->method("getWarnings")->willReturn([]);
$validation->expects($this->once())->method("getError")->willReturn(new \InvalidArgumentException());
protected function tearDown()
{
$this->validator = null;
}
/**
* @dataProvider getValidEmails
*/
public function testValidEmails($email)
{
$this->assertTrue($this->validator->isValid($email));
}
public function testInvalidUTF8Email()
{
$validator = new EmailValidator;
$email = "\x80\x81\x82@\x83\x84\x85.\x86\x87\x88";
$this->assertFalse($validator->isValid($email));
}
public function getValidEmails()
{
return array(
array('â@iana.org'),
array('fabien@symfony.com'),
array('example@example.co.uk'),
array('fabien_potencier@example.fr'),
array('example@localhost'),
array('fab\'ien@symfony.com'),
array('fab\ ien@symfony.com'),
array('example((example))@fakedfake.co.uk'),
array('example@faked(fake).co.uk'),
array('fabien+@symfony.com'),
array('инфо@письмо.рф'),
array('"username"@example.com'),
array('"user,name"@example.com'),
array('"user name"@example.com'),
array('"user@name"@example.com'),
array('"\a"@iana.org'),
array('"test\ test"@iana.org'),
array('""@iana.org'),
array('"\""@iana.org'),
array('müller@möller.de'),
array('test@email*'),
array('test@email!'),
array('test@email&'),
array('test@email^'),
array('test@email%'),
array('test@email$'),
);
}
/**
* @dataProvider getInvalidEmails
*/
public function testInvalidEmails($email)
{
$this->assertFalse($this->validator->isValid($email));
}
public function getInvalidEmails()
{
return array(
array('test@example.com test'),
array('user name@example.com'),
array('user name@example.com'),
array('example.@example.co.uk'),
array('example@example@example.co.uk'),
array('(test_exampel@example.fr)'),
array('example(example)example@example.co.uk'),
array('.example@localhost'),
array('ex\ample@localhost'),
array('example@local\host'),
array('example@localhost.'),
array('user name@example.com'),
array('username@ example . com'),
array('example@(fake).com'),
array('example@(fake.com'),
array('username@example,com'),
array('usern,ame@example.com'),
array('user[na]me@example.com'),
array('"""@iana.org'),
array('"\"@iana.org'),
array('"test"test@iana.org'),
array('"test""test"@iana.org'),
array('"test"."test"@iana.org'),
array('"test".test@iana.org'),
array('"test"' . chr(0) . '@iana.org'),
array('"test\"@iana.org'),
array(chr(226) . '@iana.org'),
array('test@' . chr(226) . '.org'),
array('\r\ntest@iana.org'),
array('\r\n test@iana.org'),
array('\r\n \r\ntest@iana.org'),
array('\r\n \r\ntest@iana.org'),
array('\r\n \r\n test@iana.org'),
array('test@iana.org \r\n'),
array('test@iana.org \r\n '),
array('test@iana.org \r\n \r\n'),
array('test@iana.org \r\n\r\n'),
array('test@iana.org \r\n\r\n '),
array('test@iana/icann.org'),
array('test@foo;bar.com'),
array('test;123@foobar.com'),
array('test@example..com'),
array('email.email@email."'),
array('test@email>'),
array('test@email<'),
array('test@email{'),
);
}
/**
* @dataProvider getInvalidEmailsWithErrors
*/
public function testInvalidEmailsWithErrorsCheck($errors, $email)
{
$this->assertFalse($this->validator->isValid($email));
$this->assertEquals($errors, $this->validator->getError());
}
public function getInvalidEmailsWithErrors()
{
return array(
array(NoLocalPart::CODE, '@example.co.uk'),
array(NoDomainPart::CODE, 'example@'),
array(DomainHyphened::CODE, 'example@example-.co.uk'),
array(DomainHyphened::CODE, 'example@example-'),
array(ConsecutiveAt::CODE, 'example@@example.co.uk'),
array(ConsecutiveDot::CODE, 'example..example@example.co.uk'),
array(ConsecutiveDot::CODE, 'example@example..co.uk'),
array(ExpectingATEXT::CODE, '<fabien_potencier>@example.fr'),
array(DotAtStart::CODE, '.example@localhost'),
array(DotAtStart::CODE, 'example@.localhost'),
array(DotAtEnd::CODE, 'example@localhost.'),
array(DotAtEnd::CODE, 'example.@example.co.uk'),
array(UnclosedComment::CODE, '(example@localhost'),
array(UnclosedQuotedString::CODE, '"example@localhost'),
array(ExpectingATEXT::CODE, 'exa"mple@localhost'),
array(UnclosedComment::CODE, '(example@localhost'),
array(UnopenedComment::CODE, 'comment)example@localhost'),
array(UnopenedComment::CODE, 'example(comment))@localhost'),
array(UnopenedComment::CODE, 'example@comment)localhost'),
array(UnopenedComment::CODE, 'example@localhost(comment))'),
array(UnopenedComment::CODE, 'example@(comment))example.com'),
//This was the original. But atext is not allowed after \n
//array(EmailValidator::ERR_EXPECTING_ATEXT, "exampl\ne@example.co.uk"),
array(AtextAfterCFWS::CODE, "exampl\ne@example.co.uk"),
array(ExpectingDTEXT::CODE, "example@[[]"),
array(AtextAfterCFWS::CODE, "exampl\te@example.co.uk"),
array(CRNoLF::CODE, "example@exa\rmple.co.uk"),
array(CRNoLF::CODE, "example@[\r]"),
array(CRNoLF::CODE, "exam\rple@example.co.uk"),
);
}
/**
* @dataProvider getInvalidEmailsWithWarnings
*/
public function testInvalidEmailsWithWarningsCheck($expectedWarnings, $email)
{
$this->assertTrue($this->validator->isValid($email, true));
$warnings = $this->validator->getWarnings();
$this->assertTrue(
count($warnings) === count($expectedWarnings),
"Expected: " . implode(",", $expectedWarnings) . " and got " . implode(",", $warnings)
);
foreach ($warnings as $warning) {
$this->assertTrue(isset($expectedWarnings[$warning->code()]));
}
}
/**
* @dataProvider getInvalidEmailsWithWarnings
*/
public function testInvalidEmailsWithDnsCheckAndStrictMode($expectedWarnings, $email)
{
$this->assertFalse($this->validator->isValid($email, true, true));
$warnings = $this->validator->getWarnings();
$this->assertTrue(
count($warnings) === count($expectedWarnings),
"Expected: " . implode(",", $expectedWarnings) . " and got " . implode(",", $warnings)
);
foreach ($warnings as $warning) {
$this->assertTrue(isset($expectedWarnings[$warning->code()]));
}
}
public function getInvalidEmailsWithWarnings()
{
return array(
[
[CFWSNearAt::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example @invalid.example.com'
],
[
[CFWSNearAt::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@ invalid.example.com'
],
[
[Comment::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@invalid.example(examplecomment).com'
],
[
[Comment::CODE, CFWSNearAt::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example(examplecomment)@invalid.example.com'
],
[
[QuotedString::CODE, CFWSWithFWS::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
"\"\t\"@invalid.example.com"
],
[
[QuotedString::CODE, CFWSWithFWS::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
"\"\r\"@invalid.example.com"
],
[
[AddressLiteral::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[127.0.0.1]'
],
[
[AddressLiteral::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]'
],
[
[AddressLiteral::CODE, IPV6Deprecated::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370::]'
],
[
[AddressLiteral::CODE, IPV6MaxGroups::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334::]'
],
[
[AddressLiteral::CODE, IPV6DoubleColon::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[IPv6:1::1::1]'
],
[
[ObsoleteDTEXT::CODE, DomainLiteral::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
"example@[\n]"
],
[
[DomainLiteral::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[::1]'
],
[
[DomainLiteral::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[::123.45.67.178]'
],
[
[IPV6ColonStart::CODE, AddressLiteral::CODE, IPV6GroupCount::CODE, NoDNSMXRecord::CODE,
NoDNSRecord::CODE],
'example@[IPv6::2001:0db8:85a3:0000:0000:8a2e:0370:7334]'
],
[
[AddressLiteral::CODE, IPV6BadChar::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[IPv6:z001:0db8:85a3:0000:0000:8a2e:0370:7334]'
],
[
[AddressLiteral::CODE, IPV6ColonEnd::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:]'
],
[
[QuotedString::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'"example"@invalid.example.com'
],
[
[LocalTooLong::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'too_long_localpart_too_long_localpart_too_long_localpart_too_long_localpart@invalid.example.com'
],
[
[LabelTooLong::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart.co.uk'
],
[
[DomainTooLong::CODE, LabelTooLong::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example2@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocal'.
'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'.
'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'
],
[
[DomainTooLong::CODE, LabelTooLong::CODE, NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'example@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocal'.
'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'.
'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpar'
],
[
[NoDNSMXRecord::CODE, NoDNSRecord::CODE],
'test@test'
],
);
}
public function testInvalidEmailsWithStrict()
{
$this->assertFalse($this->validator->isValid('"test"@test', false, true));
$this->assertTrue($validator->isValid("example@example.com", $validation));
}
}
@@ -0,0 +1,283 @@
<?php
namespace Egulias\EmailValidator\Tests;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Validation\RFCValidation;
use Egulias\EmailValidator\Exception\AtextAfterCFWS;
use Egulias\EmailValidator\Exception\ConsecutiveAt;
use Egulias\EmailValidator\Exception\ConsecutiveDot;
use Egulias\EmailValidator\Exception\CRNoLF;
use Egulias\EmailValidator\Exception\DomainHyphened;
use Egulias\EmailValidator\Exception\DotAtEnd;
use Egulias\EmailValidator\Exception\DotAtStart;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\ExpectingDTEXT;
use Egulias\EmailValidator\Exception\NoDomainPart;
use Egulias\EmailValidator\Exception\NoLocalPart;
use Egulias\EmailValidator\Exception\UnclosedComment;
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
use Egulias\EmailValidator\Exception\UnopenedComment;
use Egulias\EmailValidator\Warning\AddressLiteral;
use Egulias\EmailValidator\Warning\CFWSNearAt;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
use Egulias\EmailValidator\Warning\Comment;
use Egulias\EmailValidator\Warning\DomainLiteral;
use Egulias\EmailValidator\Warning\DomainTooLong;
use Egulias\EmailValidator\Warning\IPV6BadChar;
use Egulias\EmailValidator\Warning\IPV6ColonEnd;
use Egulias\EmailValidator\Warning\IPV6ColonStart;
use Egulias\EmailValidator\Warning\IPV6Deprecated;
use Egulias\EmailValidator\Warning\IPV6DoubleColon;
use Egulias\EmailValidator\Warning\IPV6GroupCount;
use Egulias\EmailValidator\Warning\IPV6MaxGroups;
use Egulias\EmailValidator\Warning\LabelTooLong;
use Egulias\EmailValidator\Warning\LocalTooLong;
use Egulias\EmailValidator\Warning\NoDNSMXRecord;
use Egulias\EmailValidator\Warning\NoDNSRecord;
use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
use Egulias\EmailValidator\Warning\QuotedString;
class RFCValidationTest extends \PHPUnit_Framework_TestCase
{
/**
* @var RFCValidation
*/
protected $validator;
/**
* @var EmailLexer
*/
protected $lexer;
protected function setUp()
{
$this->validator = new RFCValidation();
$this->lexer = new EmailLexer();
}
protected function tearDown()
{
$this->validator = null;
}
/**
* @dataProvider getValidEmails
*/
public function testValidEmails($email)
{
$this->assertTrue($this->validator->isValid($email, $this->lexer));
}
public function getValidEmails()
{
return array(
array('â@iana.org'),
array('fabien@symfony.com'),
array('example@example.co.uk'),
array('fabien_potencier@example.fr'),
array('example@localhost'),
array('fab\'ien@symfony.com'),
array('fab\ ien@symfony.com'),
array('example((example))@fakedfake.co.uk'),
array('example@faked(fake).co.uk'),
array('fabien+@symfony.com'),
array('инфо@письмо.рф'),
array('"username"@example.com'),
array('"user,name"@example.com'),
array('"user name"@example.com'),
array('"user@name"@example.com'),
array('"\a"@iana.org'),
array('"test\ test"@iana.org'),
array('""@iana.org'),
array('"\""@iana.org'),
array('müller@möller.de'),
array('test@email*'),
array('test@email!'),
array('test@email&'),
array('test@email^'),
array('test@email%'),
array('test@email$'),
);
}
public function testInvalidUTF8Email()
{
$email = "\x80\x81\x82@\x83\x84\x85.\x86\x87\x88";
$this->assertFalse($this->validator->isValid($email, $this->lexer));
}
/**
* @dataProvider getInvalidEmails
*/
public function testInvalidEmails($email)
{
$this->assertFalse($this->validator->isValid($email, $this->lexer));
}
public function getInvalidEmails()
{
return [
['test@example.com test'],
['user name@example.com'],
['user name@example.com'],
['example.@example.co.uk'],
['example@example@example.co.uk'],
['(test_exampel@example.fr]'],
['example(example]example@example.co.uk'],
['.example@localhost'],
['ex\ample@localhost'],
['example@local\host'],
['example@localhost.'],
['user name@example.com'],
['username@ example . com'],
['example@(fake].com'],
['example@(fake.com'],
['username@example,com'],
['usern,ame@example.com'],
['user[na]me@example.com'],
['"""@iana.org'],
['"\"@iana.org'],
['"test"test@iana.org'],
['"test""test"@iana.org'],
['"test"."test"@iana.org'],
['"test".test@iana.org'],
['"test"' . chr(0) . '@iana.org'],
['"test\"@iana.org'],
[chr(226) . '@iana.org'],
['test@' . chr(226) . '.org'],
['\r\ntest@iana.org'],
['\r\n test@iana.org'],
['\r\n \r\ntest@iana.org'],
['\r\n \r\ntest@iana.org'],
['\r\n \r\n test@iana.org'],
['test@iana.org \r\n'],
['test@iana.org \r\n '],
['test@iana.org \r\n \r\n'],
['test@iana.org \r\n\r\n'],
['test@iana.org \r\n\r\n '],
['test@iana/icann.org'],
['test@foo;bar.com'],
['test;123@foobar.com'],
['test@example..com'],
['email.email@email."'],
['test@email>'],
['test@email<'],
['test@email{'],
];
}
/**
* @dataProvider getInvalidEmailsWithErrors
*/
public function testInvalidEmailsWithErrorsCheck($error, $email)
{
$this->assertFalse($this->validator->isValid($email, $this->lexer));
$this->assertEquals($error, $this->validator->getError());
}
public function getInvalidEmailsWithErrors()
{
return [
[new NoLocalPart(), '@example.co.uk'],
[new NoDomainPart(), 'example@'],
[new DomainHyphened(), 'example@example-.co.uk'],
[new DomainHyphened(), 'example@example-'],
[new ConsecutiveAt(), 'example@@example.co.uk'],
[new ConsecutiveDot(), 'example..example@example.co.uk'],
[new ConsecutiveDot(), 'example@example..co.uk'],
[new ExpectingATEXT(), '<example_example>@example.fr'],
[new DotAtStart(), '.example@localhost'],
[new DotAtStart(), 'example@.localhost'],
[new DotAtEnd(), 'example@localhost.'],
[new DotAtEnd(), 'example.@example.co.uk'],
[new UnclosedComment(), '(example@localhost'],
[new UnclosedQuotedString(), '"example@localhost'],
[new ExpectingATEXT(), 'exa"mple@localhost'],
[new UnclosedComment(), '(example@localhost'],
[new UnopenedComment(), 'comment)example@localhost'],
[new UnopenedComment(), 'example(comment))@localhost'],
[new UnopenedComment(), 'example@comment)localhost'],
[new UnopenedComment(), 'example@localhost(comment))'],
[new UnopenedComment(), 'example@(comment))example.com'],
//This was the original. But atext is not allowed after \n
//array(EmailValidator::ERR_EXPECTING_ATEXT, "exampl\ne@example.co.uk"),
[new AtextAfterCFWS(), "exampl\ne@example.co.uk"],
[new ExpectingDTEXT(), "example@[[]"],
[new AtextAfterCFWS(), "exampl\te@example.co.uk"],
[new CRNoLF(), "example@exa\rmple.co.uk"],
[new CRNoLF(), "example@[\r]"],
[new CRNoLF(), "exam\rple@example.co.uk"],
];
}
/**
* @dataProvider getInvalidEmailsWithWarnings
*/
public function testInvalidEmailsWithWarningsCheck($expectedWarnings, $email)
{
$this->assertTrue($this->validator->isValid($email, $this->lexer));
$warnings = $this->validator->getWarnings();
$this->assertTrue(
count($warnings) === count($expectedWarnings),
"Expected: " . implode(",", $expectedWarnings) . " and got " . implode(",", $warnings)
);
foreach ($warnings as $warning) {
$this->assertTrue(isset($expectedWarnings[$warning->code()]));
}
}
public function getInvalidEmailsWithWarnings()
{
return [
[[CFWSNearAt::CODE], 'example @invalid.example.com'],
[[CFWSNearAt::CODE], 'example@ invalid.example.com'],
[[Comment::CODE], 'example@invalid.example(examplecomment).com'],
[[Comment::CODE,CFWSNearAt::CODE], 'example(examplecomment)@invalid.example.com'],
[[QuotedString::CODE, CFWSWithFWS::CODE,], "\"\t\"@invalid.example.com"],
[[QuotedString::CODE, CFWSWithFWS::CODE,], "\"\r\"@invalid.example.com"],
[[AddressLiteral::CODE,], 'example@[127.0.0.1]'],
[[AddressLiteral::CODE,], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]'],
[[AddressLiteral::CODE, IPV6Deprecated::CODE], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370::]'],
[[AddressLiteral::CODE, IPV6MaxGroups::CODE,], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334::]'],
[[AddressLiteral::CODE, IPV6DoubleColon::CODE,], 'example@[IPv6:1::1::1]'],
[[ObsoleteDTEXT::CODE, DomainLiteral::CODE,], "example@[\n]"],
[[DomainLiteral::CODE,], 'example@[::1]'],
[[DomainLiteral::CODE,], 'example@[::123.45.67.178]'],
[
[IPV6ColonStart::CODE, AddressLiteral::CODE, IPV6GroupCount::CODE,],
'example@[IPv6::2001:0db8:85a3:0000:0000:8a2e:0370:7334]'
],
[
[AddressLiteral::CODE, IPV6BadChar::CODE,],
'example@[IPv6:z001:0db8:85a3:0000:0000:8a2e:0370:7334]'
],
[
[AddressLiteral::CODE, IPV6ColonEnd::CODE,],
'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:]'
],
[[QuotedString::CODE,], '"example"@invalid.example.com'],
[
[LocalTooLong::CODE,],
'too_long_localpart_too_long_localpart_too_long_localpart_too_long_localpart@invalid.example.com'
],
[
[LabelTooLong::CODE,],
'example@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart.co.uk'
],
[
[DomainTooLong::CODE, LabelTooLong::CODE,],
'example2@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocal'.
'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'.
'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'
],
[
[DomainTooLong::CODE, LabelTooLong::CODE,],
'example@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocal'.
'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'.
'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpar'
],
];
}
}