mirror of
https://github.com/egulias/EmailValidator.git
synced 2026-08-18 04:13:56 +00:00
domain improvements over UTF16 and invalid ascii chars
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
phpunit.result.cache
|
||||
.idea
|
||||
composer.lock
|
||||
report/
|
||||
|
||||
+68
-53
@@ -7,50 +7,52 @@ use Doctrine\Common\Lexer\AbstractLexer;
|
||||
class EmailLexer extends AbstractLexer
|
||||
{
|
||||
//ASCII values
|
||||
const C_DEL = 127;
|
||||
const S_EMPTY = null;
|
||||
const C_NUL = 0;
|
||||
const S_AT = 64;
|
||||
const S_BACKSLASH = 92;
|
||||
const S_DOT = 46;
|
||||
const S_HTAB = 9;
|
||||
const S_LF = 10;
|
||||
const S_CR = 13;
|
||||
const S_SP = 32;
|
||||
const EXCLAMATION = 33;
|
||||
const S_DQUOTE = 34;
|
||||
const NUMBER_SIGN = 35;
|
||||
const DOLLAR = 36;
|
||||
const PERCENTAGE = 37;
|
||||
const AMPERSAND = 38;
|
||||
const S_SQUOTE = 39;
|
||||
const S_OPENPARENTHESIS = 40;
|
||||
const S_CLOSEPARENTHESIS = 41;
|
||||
const ASTERISK = 42;
|
||||
const S_PLUS = 43;
|
||||
const S_COMMA = 44;
|
||||
const S_HYPHEN = 45;
|
||||
const S_DOT = 46;
|
||||
const S_SLASH = 47;
|
||||
const S_COLON = 58;
|
||||
const S_SEMICOLON = 59;
|
||||
const S_LOWERTHAN = 60;
|
||||
const S_EQUAL = 61;
|
||||
const S_GREATERTHAN = 62;
|
||||
const QUESTIONMARK = 63;
|
||||
const S_AT = 64;
|
||||
const S_OPENBRACKET = 91;
|
||||
const S_BACKSLASH = 92;
|
||||
const S_CLOSEBRACKET = 93;
|
||||
const CARET = 94;
|
||||
const S_UNDERSCORE = 95;
|
||||
const S_BACKTICK = 96;
|
||||
const S_OPENCURLYBRACES = 123;
|
||||
const S_CLOSECURLYBRACES = 125;
|
||||
const S_OPENPARENTHESIS = 49;
|
||||
const S_CLOSEPARENTHESIS = 261;
|
||||
const S_OPENBRACKET = 262;
|
||||
const S_CLOSEBRACKET = 263;
|
||||
const S_HYPHEN = 264;
|
||||
const S_COLON = 265;
|
||||
const S_DOUBLECOLON = 266;
|
||||
const S_PIPE = 124;
|
||||
const S_CLOSECURLYBRACES = 125;
|
||||
const S_TILDE = 126;
|
||||
const S_UNDERSCORE = 95;
|
||||
const S_PLUS = 43;
|
||||
const S_EQUAL = 61;
|
||||
const S_SP = 267;
|
||||
const S_HTAB = 268;
|
||||
const S_CR = 269;
|
||||
const S_LF = 270;
|
||||
const S_IPV6TAG = 271;
|
||||
const S_LOWERTHAN = 272;
|
||||
const S_GREATERTHAN = 273;
|
||||
const S_COMMA = 274;
|
||||
const S_SEMICOLON = 275;
|
||||
const S_OPENQBRACKET = 276;
|
||||
const S_CLOSEQBRACKET = 277;
|
||||
const S_SLASH = 278;
|
||||
const S_EMPTY = null;
|
||||
const C_DEL = 127;
|
||||
const INVERT_QUESTIONMARK= 168;
|
||||
const INVERT_EXCLAMATION = 173;
|
||||
const GENERIC = 300;
|
||||
const CRLF = 301;
|
||||
const ASTERISK = 42;
|
||||
const EXCLAMATION = 33;
|
||||
const AMPERSAND = 38;
|
||||
const CARET = 94;
|
||||
const PERCENTAGE = 37;
|
||||
const DOLLAR = 36;
|
||||
const S_IPV6TAG = 301;
|
||||
const INVALID = 302;
|
||||
const CRLF = 1310;
|
||||
const S_DOUBLECOLON = 5858;
|
||||
const ASCII_INVALID_FROM = 127;
|
||||
const ASCII_INVALID_TO = 199;
|
||||
|
||||
@@ -99,6 +101,11 @@ class EmailLexer extends AbstractLexer
|
||||
'_' => self::S_UNDERSCORE,
|
||||
'=' => self::S_EQUAL,
|
||||
'+' => self::S_PLUS,
|
||||
'¿' => self::INVERT_QUESTIONMARK,
|
||||
'?' => self::QUESTIONMARK,
|
||||
'#' => self::NUMBER_SIGN,
|
||||
'¡' => self::INVERT_EXCLAMATION,
|
||||
null => self::S_EMPTY,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -247,7 +254,9 @@ class EmailLexer extends AbstractLexer
|
||||
*/
|
||||
protected function getNonCatchablePatterns()
|
||||
{
|
||||
return array('[\xA0-\xff]+');
|
||||
return [
|
||||
'[\xA0-\xff]+',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,28 +268,38 @@ class EmailLexer extends AbstractLexer
|
||||
*/
|
||||
protected function getType(&$value)
|
||||
{
|
||||
if ($this->isNullType($value)) {
|
||||
$encoded = $value;
|
||||
|
||||
if (mb_detect_encoding($value, 'auto', true) !== 'UTF-8') {
|
||||
$encoded = utf8_encode($value);
|
||||
}
|
||||
|
||||
if ($this->isValid($encoded)) {
|
||||
return $this->charValue[$encoded];
|
||||
}
|
||||
|
||||
if ($this->isNullType($encoded)) {
|
||||
return self::C_NUL;
|
||||
}
|
||||
|
||||
if ($this->isValid($value)) {
|
||||
return $this->charValue[$value];
|
||||
}
|
||||
|
||||
if ($this->isUTF8Invalid($value)) {
|
||||
if ($this->isInvalidChar($encoded)) {
|
||||
$this->hasInvalidTokens = true;
|
||||
return self::INVALID;
|
||||
}
|
||||
|
||||
|
||||
return self::GENERIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isValid($value)
|
||||
protected function isInvalidChar(string $value) : bool
|
||||
{
|
||||
if(preg_match("/[^\p{S}\p{C}\p{Cc}]+/iu", $value) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isValid(string $value) : bool
|
||||
{
|
||||
if (isset($this->charValue[$value])) {
|
||||
return true;
|
||||
@@ -302,11 +321,7 @@ class EmailLexer extends AbstractLexer
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function isUTF8Invalid($value)
|
||||
protected function isUTF8Invalid(string $value) : bool
|
||||
{
|
||||
if (preg_match('/\p{Cc}+/u', $value)) {
|
||||
return true;
|
||||
|
||||
@@ -36,7 +36,7 @@ class DomainLiteral extends Parser
|
||||
|
||||
$this->addObsoleteWarnings();
|
||||
|
||||
if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) {
|
||||
if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
|
||||
return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class DomainLiteral extends Parser
|
||||
$IPv6TAG = true;
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) {
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ class DomainPart extends Parser
|
||||
$validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true;
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) {
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENBRACKET && $prev['type'] !== EmailLexer::S_AT) {
|
||||
return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), $this->lexer->token['value']);
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,10 @@ class EmailLexerTests extends TestCase
|
||||
array('~', EmailLexer::S_TILDE),
|
||||
array('=', EmailLexer::S_EQUAL),
|
||||
array('+', EmailLexer::S_PLUS),
|
||||
array('¿', EmailLexer::INVERT_QUESTIONMARK),
|
||||
array('?', EmailLexer::QUESTIONMARK),
|
||||
array('#', EmailLexer::NUMBER_SIGN),
|
||||
array('¡', EmailLexer::INVERT_EXCLAMATION),
|
||||
array('_', EmailLexer::S_UNDERSCORE),
|
||||
array('', EmailLexer::S_EMPTY),
|
||||
array(chr(31), EmailLexer::INVALID),
|
||||
|
||||
@@ -140,6 +140,13 @@ class RFCValidationDomainPartTest extends TestCase
|
||||
['test@email=a.com'],
|
||||
['test@email+a.com'],
|
||||
['test@email_a.com'],
|
||||
['test@email¡a.com'],
|
||||
['test@email?a.com'],
|
||||
['test@email#a.com'],
|
||||
['test@email¨a.com'],
|
||||
['test@email€a.com'],
|
||||
['test@email$a.com'],
|
||||
['test@email£a.com'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -220,5 +227,20 @@ class RFCValidationDomainPartTest extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
public function invalidUTF16Chars()
|
||||
{
|
||||
return [
|
||||
['example@symƒony.com'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider invalidUTF16Chars
|
||||
*/
|
||||
public function testInvalidUTF16($email)
|
||||
{
|
||||
$this->markTestSkipped('Util finding a way to control this kind of chars');
|
||||
$this->assertFalse($this->validator->isValid($email, $this->lexer));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -148,13 +148,14 @@ class RFCValidationTest extends TestCase
|
||||
['\r\n \r\ntest@iana.org'],
|
||||
['\r\n \r\n test@iana.org'],
|
||||
['test;123@foobar.com'],
|
||||
['examp║le@symfony.com'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidEmailsWithErrors
|
||||
*/
|
||||
public function testInvalidEmailsWithErrorsCheck($error, $email)
|
||||
public function testInvalidDEmailsWithErrorsCheck($error, $email)
|
||||
{
|
||||
$this->assertFalse($this->validator->isValid($email, $this->lexer));
|
||||
$this->assertEquals($error, $this->validator->getError());
|
||||
|
||||
Reference in New Issue
Block a user