mirror of
https://github.com/egulias/EmailValidator.git
synced 2026-08-30 20:18:04 +00:00
#18 - [WIP] - Almost done with erros, dobule backslask left and utf8 chars
This commit is contained in:
@@ -31,10 +31,13 @@ class EmailLexer extends AbstractLexer
|
||||
const S_SEMICOLON = 275;
|
||||
const S_OPENQBRACKET = 276;
|
||||
const S_CLOSEQBRACKET = 277;
|
||||
const S_SLASH = 278;
|
||||
const S_EMPTY = null;
|
||||
const GENERIC = 300;
|
||||
const CRLF = 301;
|
||||
const INVALID = 302;
|
||||
const ASCII_INVALID_FROM = 127;
|
||||
const ASCII_INVALID_TO = 199;
|
||||
|
||||
/**
|
||||
* US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3)
|
||||
@@ -52,6 +55,7 @@ class EmailLexer extends AbstractLexer
|
||||
';' => self::S_SEMICOLON,
|
||||
'@' => self::S_AT,
|
||||
'\\' => self::S_BACKSLASH,
|
||||
'/' => self::S_SLASH,
|
||||
',' => self::S_COMMA,
|
||||
'.' => self::S_DOT,
|
||||
'"' => self::S_DQUOTE,
|
||||
@@ -67,14 +71,25 @@ class EmailLexer extends AbstractLexer
|
||||
'>' => self::S_GREATERTHAN,
|
||||
'{' => self::S_OPENQBRACKET,
|
||||
'}' => self::S_CLOSEQBRACKET,
|
||||
'' => self::S_EMPTY
|
||||
'' => self::S_EMPTY,
|
||||
'\0' => self::C_NUL,
|
||||
);
|
||||
|
||||
protected $invalidASCII = array(226 => 1,);
|
||||
|
||||
protected $hasInvalidTokens = false;
|
||||
|
||||
protected $previous;
|
||||
|
||||
public function hasInvalidTokens()
|
||||
{
|
||||
return $this->hasInvalidTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @throws \UnexpectedValueException
|
||||
* @return boolean
|
||||
*/
|
||||
public function find($type)
|
||||
{
|
||||
@@ -146,14 +161,42 @@ class EmailLexer extends AbstractLexer
|
||||
*/
|
||||
protected function getType(&$value)
|
||||
{
|
||||
|
||||
if ($this->isNullType($value)) {
|
||||
return self::C_NUL;
|
||||
}
|
||||
|
||||
if (isset($this->charValue[$value])) {
|
||||
return $this->charValue[$value];
|
||||
}
|
||||
|
||||
if (preg_match('/[\x10-\x1F]+/', $value)) {
|
||||
if ($this->isInvalid($value)) {
|
||||
$this->hasInvalidTokens = true;
|
||||
return self::INVALID;
|
||||
}
|
||||
|
||||
return self::GENERIC;
|
||||
}
|
||||
|
||||
protected function isNullType($value)
|
||||
{
|
||||
if ($value === "\0") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isInvalid($value)
|
||||
{
|
||||
if (preg_match('/[\x10-\x1F]+/', $value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($this->invalidASCII[ord($value)])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ class EmailParser
|
||||
throw new \InvalidArgumentException('ERR_NOLOCALPART');
|
||||
}
|
||||
|
||||
if ($this->lexer->hasInvalidTokens()) {
|
||||
throw new \InvalidArgumentException('ERR_INVALID_ATEXT');
|
||||
}
|
||||
|
||||
$this->localPartParser->parse($str);
|
||||
$this->domainPartParser->parse($str);
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ class DomainPart extends Parser
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) {
|
||||
throw new \InvalidArgumentException('ERR_NODOMAIN');
|
||||
}
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
|
||||
throw new \InvalidArgumentException('ERR_DOMAINHYPHENEND');
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->warnings[] = EmailValidator::DEPREC_COMMENT;
|
||||
@@ -103,6 +106,10 @@ class DomainPart extends Parser
|
||||
do {
|
||||
$prev = $this->lexer->getPrevious();
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_SLASH) {
|
||||
throw new \InvalidArgumentException('ERR_DOMAIN_CHAR_NOT_ALLOWED');
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->parseComments();
|
||||
$this->lexer->moveNext();
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Egulias\EmailValidator\Parser;
|
||||
|
||||
use Egulias\EmailValidator\EmailLexer;
|
||||
use Egulias\EmailValidator\EmailValidator;
|
||||
use \InvalidArgumentException;
|
||||
|
||||
|
||||
class LocalPart extends Parser
|
||||
@@ -21,10 +22,14 @@ class LocalPart extends Parser
|
||||
|
||||
$closingQuote = $this->checkDQUOTE($closingQuote);
|
||||
if ($closingQuote && $parseDQuote) {
|
||||
$this->parseDoubleQuote();
|
||||
$parseDQuote = false;
|
||||
$parseDQuote = $this->parseDoubleQuote();
|
||||
// $closingQuote = false;
|
||||
}
|
||||
|
||||
// if ($closingQuote && !$parseDQuote) {
|
||||
// throw new InvalidArgumentException("ERR_DOUBLE_DQUOTE");
|
||||
// }
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->parseComments();
|
||||
}
|
||||
@@ -56,23 +61,51 @@ class LocalPart extends Parser
|
||||
|
||||
protected function parseDoubleQuote()
|
||||
{
|
||||
$special = array (
|
||||
$parseAgain = true;
|
||||
$special = array(
|
||||
EmailLexer::S_CR => true,
|
||||
EmailLexer::S_HTAB => true,
|
||||
EmailLexer::S_LF => true
|
||||
);
|
||||
|
||||
$invalid = array(
|
||||
EmailLexer::C_NUL => true,
|
||||
EmailLexer::S_HTAB => true,
|
||||
EmailLexer::S_CR => true,
|
||||
EmailLexer::S_LF => true
|
||||
);
|
||||
$setSpecialsWarning = true;
|
||||
|
||||
$this->lexer->moveNext();
|
||||
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
|
||||
$parseAgain = false;
|
||||
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
|
||||
$this->warnings[] = EmailValidator::CFWS_FWS;
|
||||
$setSpecialsWarning = false;
|
||||
}
|
||||
$this->lexer->moveNext();
|
||||
}
|
||||
}
|
||||
|
||||
$this->lexer->moveNext();
|
||||
|
||||
if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
|
||||
throw new InvalidArgumentException("ERR_EXPECTED_ATEXT");
|
||||
}
|
||||
}
|
||||
|
||||
$prev = $this->lexer->getPrevious();
|
||||
|
||||
if ($prev['type'] === EmailLexer::S_BACKSLASH) {
|
||||
if (!$this->checkDQUOTE(false)) {
|
||||
throw new \InvalidArgumentException("ERR_UNCLOSED_DQUOTE");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
|
||||
throw new \InvalidArgumentException("ERR_EXPECED_AT");
|
||||
}
|
||||
|
||||
return $parseAgain;
|
||||
}
|
||||
|
||||
protected function isInvalidToken($token, $closingQuote)
|
||||
{
|
||||
|
||||
@@ -124,8 +124,7 @@ abstract class Parser
|
||||
|
||||
if ($previous['type'] === EmailLexer::S_BACKSLASH
|
||||
&&
|
||||
($this->lexer->token['type'] === EmailLexer::S_SP ||
|
||||
$this->lexer->token['type'] === EmailLexer::S_HTAB)
|
||||
$this->lexer->token['type'] !== EmailLexer::GENERIC
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -164,6 +163,7 @@ abstract class Parser
|
||||
if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
|
||||
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
|
||||
}
|
||||
|
||||
$this->warnings[] = EmailValidator::RFC5321_QUOTEDSTRING;
|
||||
try {
|
||||
$this->lexer->find(EmailLexer::S_DQUOTE);
|
||||
|
||||
@@ -44,6 +44,15 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($lexer->find(EmailLexer::S_HTAB));
|
||||
}
|
||||
|
||||
public function testLexerHasInvalidTokens()
|
||||
{
|
||||
$lexer = new EmailLexer();
|
||||
$lexer->setInput(chr(226));
|
||||
$lexer->moveNext();
|
||||
$lexer->moveNext();
|
||||
$this->assertTrue($lexer->hasInvalidTokens());
|
||||
}
|
||||
|
||||
public function getTokens()
|
||||
{
|
||||
return array(
|
||||
@@ -61,6 +70,7 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
|
||||
array("\"", EmailLexer::S_DQUOTE),
|
||||
array("-", EmailLexer::S_HYPHEN),
|
||||
array("\\", EmailLexer::S_BACKSLASH),
|
||||
array("/", EmailLexer::S_SLASH),
|
||||
array("(", EmailLexer::S_OPENPARENTHESIS),
|
||||
array(")", EmailLexer::S_CLOSEPARENTHESIS),
|
||||
array('<', EmailLexer::S_LOWERTHAN),
|
||||
@@ -74,7 +84,9 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
|
||||
array('{', EmailLexer::S_OPENQBRACKET),
|
||||
array('}', EmailLexer::S_CLOSEQBRACKET),
|
||||
array('', EmailLexer::S_EMPTY),
|
||||
array(chr(31), EmailLexer::INVALID)
|
||||
array(chr(31), EmailLexer::INVALID),
|
||||
array(chr(226), EmailLexer::INVALID),
|
||||
array(chr(0), EmailLexer::C_NUL)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
|
||||
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('"\\"@iana.org'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,9 +62,10 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
|
||||
public function getInvalidEmails()
|
||||
{
|
||||
return array(
|
||||
|
||||
array('example.@example.co.uk'),
|
||||
array('example@example@example.co.uk'),
|
||||
array('(fabien_potencier@example.fr)'),
|
||||
array('(test_exampel@example.fr)'),
|
||||
array('example(example)example@example.co.uk'),
|
||||
array('.example@localhost'),
|
||||
array('ex\ample@localhost'),
|
||||
@@ -72,6 +78,30 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
|
||||
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('@iana.org'),
|
||||
// array('test@.org'),
|
||||
// array('""@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'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user