Compare commits

..

1 Commits

Author SHA1 Message Date
Eduardo Gulias Davis 39b451bb2b #19 and #10 - Improvement of QuotedPart parsing 2014-09-02 00:35:48 +02:00
5 changed files with 92 additions and 14 deletions
@@ -84,6 +84,7 @@ class EmailLexer extends AbstractLexer
if (!$search->lookahead) { if (!$search->lookahead) {
throw new \UnexpectedValueException($type . ' not found'); throw new \UnexpectedValueException($type . ' not found');
} }
return true;
} }
/** /**
+49 -11
View File
@@ -3,7 +3,6 @@
namespace Egulias\EmailValidator\Parser; namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Parser\Parser;
use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\EmailValidator;
@@ -11,7 +10,9 @@ class LocalPart extends Parser
{ {
public function parse($localPart) public function parse($localPart)
{ {
$parseDQuote = true;
$closingQuote = false; $closingQuote = false;
while ($this->lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) { while ($this->lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) {
if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) { if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) {
@@ -19,6 +20,10 @@ class LocalPart extends Parser
} }
$closingQuote = $this->checkDQUOTE($closingQuote); $closingQuote = $this->checkDQUOTE($closingQuote);
if ($closingQuote && $parseDQuote) {
$this->parseDoubleQuote();
$parseDQuote = false;
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->parseComments(); $this->parseComments();
@@ -26,20 +31,15 @@ class LocalPart extends Parser
$this->checkConsecutiveDots(); $this->checkConsecutiveDots();
if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_AT)) { if (
$this->lexer->token['type'] === EmailLexer::S_DOT &&
$this->lexer->isNextToken(EmailLexer::S_AT)
) {
throw new \InvalidArgumentException('ERR_DOT_END'); throw new \InvalidArgumentException('ERR_DOT_END');
} }
$this->warnEscaping(); $this->warnEscaping();
$this->isInvalidToken($this->lexer->token, $closingQuote);
if ($this->lexer->isNextTokenAny(
array(
EmailLexer::INVALID, EmailLexer::S_LOWERTHAN, EmailLexer::S_GREATERTHAN
)
)
) {
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
if ($this->isFWS()) { if ($this->isFWS()) {
$this->parseFWS(); $this->parseFWS();
@@ -53,4 +53,42 @@ class LocalPart extends Parser
$this->warnings[] = EmailValidator::RFC5322_LOCAL_TOOLONG; $this->warnings[] = EmailValidator::RFC5322_LOCAL_TOOLONG;
} }
} }
protected function parseDoubleQuote()
{
$special = array (
EmailLexer::S_CR => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_LF => true
);
$setSpecialsWarning = true;
$this->lexer->moveNext();
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
$this->warnings[] = EmailValidator::CFWS_FWS;
$setSpecialsWarning = false;
}
$this->lexer->moveNext();
}
}
protected function isInvalidToken($token, $closingQuote)
{
$forbidden = array(
EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET,
EmailLexer::S_GREATERTHAN,
EmailLexer::S_LOWERTHAN,
EmailLexer::S_COLON,
EmailLexer::S_SEMICOLON,
EmailLexer::INVALID
);
if (in_array($token['type'], $forbidden) && !$closingQuote) {
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
}
} }
@@ -102,6 +102,10 @@ abstract class Parser
protected function isFWS() protected function isFWS()
{ {
if ($this->escaped()) {
return false;
}
if ($this->lexer->token['type'] === EmailLexer::S_SP || if ($this->lexer->token['type'] === EmailLexer::S_SP ||
$this->lexer->token['type'] === EmailLexer::S_HTAB || $this->lexer->token['type'] === EmailLexer::S_HTAB ||
$this->lexer->token['type'] === EmailLexer::S_CR || $this->lexer->token['type'] === EmailLexer::S_CR ||
@@ -114,6 +118,21 @@ abstract class Parser
return false; return false;
} }
protected function escaped()
{
$previous = $this->lexer->getPrevious();
if ($previous['type'] === EmailLexer::S_BACKSLASH
&&
($this->lexer->token['type'] === EmailLexer::S_SP ||
$this->lexer->token['type'] === EmailLexer::S_HTAB)
) {
return true;
}
return false;
}
protected function warnEscaping() protected function warnEscaping()
{ {
if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
@@ -36,6 +36,14 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
$this->assertEquals(EmailLexer::S_HTAB, $lexer->token['type']); $this->assertEquals(EmailLexer::S_HTAB, $lexer->token['type']);
} }
public function testLexerSearchToken()
{
$lexer = new EmailLexer();
$lexer->setInput("foo\tbar");
$lexer->moveNext();
$this->assertTrue($lexer->find(EmailLexer::S_HTAB));
}
public function getTokens() public function getTokens()
{ {
return array( return array(
@@ -34,11 +34,15 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array('fabien_potencier@example.fr'), array('fabien_potencier@example.fr'),
array('example@localhost'), array('example@localhost'),
array('fab\'ien@symfony.com'), array('fab\'ien@symfony.com'),
array('fab\ ien@symfony.com'),
array('example((example))@fakedfake.co.uk'), array('example((example))@fakedfake.co.uk'),
array('example@faked(fake).co.uk'), array('example@faked(fake).co.uk'),
array('fabien+@symfony.com'), array('fabien+@symfony.com'),
array('инфо@письмо.рф'), array('инфо@письмо.рф'),
array('"username"@example.com'),
array('"user,name"@example.com'),
array('"user name"@example.com'),
array('"user@name"@example.com'),
); );
} }
@@ -66,6 +70,8 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array('example@(fake).com'), array('example@(fake).com'),
array('example@(fake.com'), array('example@(fake.com'),
array('username@example,com'), array('username@example,com'),
array('usern,ame@example.com'),
array('user[na]me@example.com'),
); );
} }
@@ -105,14 +111,13 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array(EmailValidator::ERR_CR_NO_LF, "example@exa\rmple.co.uk"), array(EmailValidator::ERR_CR_NO_LF, "example@exa\rmple.co.uk"),
array(EmailValidator::ERR_CR_NO_LF, "example@[\r]"), array(EmailValidator::ERR_CR_NO_LF, "example@[\r]"),
array(EmailValidator::ERR_CR_NO_LF, "exam\rple@example.co.uk"), array(EmailValidator::ERR_CR_NO_LF, "exam\rple@example.co.uk"),
array(EmailValidator::ERR_CR_NO_LF, "\"\r\"@localhost"),
); );
} }
/** /**
* @dataProvider getInvalidEmailsWithWarnings * @dataProvider getInvalidEmailsWithWarnings
*/ */
public function testInvalidEmailsWithWarningsCheck($warnings, $email) public function testValidEmailsWithWarningsCheck($warnings, $email)
{ {
$this->assertTrue($this->validator->isValid($email, true)); $this->assertTrue($this->validator->isValid($email, true));
@@ -139,6 +144,13 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
), ),
"\"\t\"@example.co.uk" "\"\t\"@example.co.uk"
), ),
array(
array(
EmailValidator::RFC5321_QUOTEDSTRING,
EmailValidator::CFWS_FWS,
),
"\"\r\"@example.co.uk"
),
array( array(
array( array(
EmailValidator::RFC5321_ADDRESSLITERAL, EmailValidator::RFC5321_ADDRESSLITERAL,