diff --git a/.gitignore b/.gitignore index 3cb9f7e..e529acc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ phpunit.result.cache .phpunit* .idea .vscode +.php-version diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 143a307..c58beb0 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,14 +1,13 @@ imports: - - php + - php build: - environment: - php: '7.4' - tests: - override: - - - command: 'vendor/bin/phpunit --coverage-clover=clover.xml --exclude-group flaky' - coverage: - file: 'clover.xml' - format: 'clover' - - php-scrutinizer-run + environment: + php: "8.1" + tests: + override: + - command: "vendor/bin/phpunit --coverage-clover=clover.xml --exclude-group flaky" + coverage: + file: "clover.xml" + format: "clover" + - php-scrutinizer-run diff --git a/README.md b/README.md index 54aa57d..d189fbf 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,17 @@ This library aims to support RFCs: **Current major version with full support is v3** -| Version | Released | EOL | Only critical bug fixes | Full | -| ---- | :----: | :----: | :----: | :----: | -| v3.x | 2020/12/29 | - | X | X | -| v2.1.x | 2016/05/16 | 01/2022 | X | | -| v1.2 | 2013/19/05 | YES | | | +| Version | Released | EOL | Only critical bug fixes | Full | +| ------- | :--------: | :---: | :---------------------: | :---: | +| v4.x | | - | X | X | +| v3.x | 2020/12/29 | - | X | X | +| v2.1.x | 2016/05/16 | YES | X | | +| v1.2 | 2013/19/05 | YES | | | ## Requirements ## - * PHP 7.2 + * PHP 8.1 * [Composer](https://getcomposer.org) is required for installation * [Spoofchecking](/src/Validation/Extra/SpoofCheckValidation.php) and [DNSCheckValidation](/src/Validation/DNSCheckValidation.php) validation requires that your PHP system has the [PHP Internationalization Libraries](https://php.net/manual/en/book.intl.php) (also known as PHP Intl) diff --git a/composer.json b/composer.json index 6a273e2..72ac5d4 100644 --- a/composer.json +++ b/composer.json @@ -1,21 +1,21 @@ { - "name": "egulias/email-validator", - "description": "A library for validating emails against several RFCs", - "homepage": "https://github.com/egulias/EmailValidator", - "keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"], - "license": "MIT", + "name": "egulias/email-validator", + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"], + "license": "MIT", "authors": [ {"name": "Eduardo Gulias Davis"} ], "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "require": { - "php": ">=7.2", - "doctrine/lexer": "^1.2|^2", - "symfony/polyfill-intl-idn": "^1.15" + "php": ">=8.1", + "doctrine/lexer": "^2.0 || ^3.0", + "symfony/polyfill-intl-idn": "^1.26" }, "require-dev": { "phpunit/phpunit": "^8.5.8|^9.3.3", @@ -34,4 +34,4 @@ "Egulias\\EmailValidator\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/src/EmailLexer.php b/src/EmailLexer.php index 6add6bd..1eb480a 100644 --- a/src/EmailLexer.php +++ b/src/EmailLexer.php @@ -5,13 +5,11 @@ namespace Egulias\EmailValidator; use Doctrine\Common\Lexer\AbstractLexer; use Doctrine\Common\Lexer\Token; -/** - * @extends AbstractLexer - */ +/** @extends AbstractLexer */ class EmailLexer extends AbstractLexer { //ASCII values - public const S_EMPTY = null; + public const S_EMPTY = -1; public const C_NUL = 0; public const S_HTAB = 9; public const S_LF = 10; @@ -50,7 +48,7 @@ class EmailLexer extends AbstractLexer public const S_CLOSECURLYBRACES = 125; public const S_TILDE = 126; public const C_DEL = 127; - public const INVERT_QUESTIONMARK= 168; + public const INVERT_QUESTIONMARK = 168; public const INVERT_EXCLAMATION = 173; public const GENERIC = 300; public const S_IPV6TAG = 301; @@ -135,38 +133,28 @@ class EmailLexer extends AbstractLexer protected $hasInvalidTokens = false; /** - * @var array - * - * @psalm-var array{value:string, type:null|int, position:int}|array + * @var Token */ - protected $previous = []; + protected Token $previous; /** * The last matched/seen token. * - * @var array|Token - * - * @psalm-suppress NonInvariantDocblockPropertyType - * @psalm-var array{value:string, type:null|int, position:int}|Token + * @var Token */ - public $token; + public Token $current; /** * The next token in the input. * - * @var array|Token|null - * - * @psalm-suppress NonInvariantDocblockPropertyType - * @psalm-var array{position: int, type: int|null|string, value: int|string}|Token|null + * @var Token|null */ - public $lookahead; + public Token|null $lookahead; - /** @psalm-var array{value:'', type:null, position:0} */ - private static $nullToken = [ - 'value' => '', - 'type' => null, - 'position' => 0, - ]; + /** + * @var Token + */ + private Token $nullToken; /** @var string */ private $accumulator = ''; @@ -176,15 +164,19 @@ class EmailLexer extends AbstractLexer public function __construct() { - $this->previous = $this->token = self::$nullToken; + /** @var Token $nullToken */ + $nullToken = new Token('', self::S_EMPTY, 0); + $this->nullToken = $nullToken; + + $this->current = $this->previous = $this->nullToken; $this->lookahead = null; } - public function reset() : void + public function reset(): void { $this->hasInvalidTokens = false; parent::reset(); - $this->previous = $this->token = self::$nullToken; + $this->current = $this->previous = $this->nullToken; } /** @@ -194,7 +186,7 @@ class EmailLexer extends AbstractLexer * * @psalm-suppress InvalidScalarArgument */ - public function find($type) : bool + public function find($type): bool { $search = clone $this; $search->skipUntil($type); @@ -210,24 +202,23 @@ class EmailLexer extends AbstractLexer * * @return boolean */ - public function moveNext() : bool + public function moveNext(): bool { - if ($this->hasToRecord && $this->previous === self::$nullToken) { - $this->accumulator .= $this->token['value']; + if ($this->hasToRecord && $this->previous === $this->nullToken) { + $this->accumulator .= $this->current->value; } - $this->previous = $this->token instanceof Token - ? ['value' => $this->token->value, 'type' => $this->token->type, 'position' => $this->token->position] - : $this->token; - - if($this->lookahead === null) { - $this->lookahead = self::$nullToken; + $this->previous = $this->current; + + if ($this->lookahead === null) { + $this->lookahead = $this->nullToken; } $hasNext = parent::moveNext(); + $this->current = $this->token ?? $this->nullToken; if ($this->hasToRecord) { - $this->accumulator .= $this->token['value']; + $this->accumulator .= $this->current->value; } return $hasNext; @@ -240,7 +231,7 @@ class EmailLexer extends AbstractLexer * @throws \InvalidArgumentException * @return integer */ - protected function getType(&$value) + protected function getType(&$value): int { $encoded = $value; @@ -261,31 +252,30 @@ class EmailLexer extends AbstractLexer return self::INVALID; } - - return self::GENERIC; + return self::GENERIC; } - protected function isValid(string $value) : bool + protected function isValid(string $value): bool { return isset($this->charValue[$value]); } - protected function isNullType(string $value) : bool + protected function isNullType(string $value): bool { return $value === "\0"; } - protected function isInvalidChar(string $value) : bool + protected function isInvalidChar(string $value): bool { return !preg_match(self::INVALID_CHARS_REGEX, $value); } - protected function isUTF8Invalid(string $value) : bool + protected function isUTF8Invalid(string $value): bool { return preg_match(self::VALID_UTF8_REGEX, $value) !== false; } - public function hasInvalidTokens() : bool + public function hasInvalidTokens(): bool { return $this->hasInvalidTokens; } @@ -293,9 +283,9 @@ class EmailLexer extends AbstractLexer /** * getPrevious * - * @return array + * @return Token */ - public function getPrevious() : array + public function getPrevious(): Token { return $this->previous; } @@ -305,7 +295,7 @@ class EmailLexer extends AbstractLexer * * @return string[] */ - protected function getCatchablePatterns() : array + protected function getCatchablePatterns(): array { return self::CATCHABLE_PATTERNS; } @@ -315,33 +305,33 @@ class EmailLexer extends AbstractLexer * * @return string[] */ - protected function getNonCatchablePatterns() : array + protected function getNonCatchablePatterns(): array { return self::NON_CATCHABLE_PATTERNS; } - protected function getModifiers() : string + protected function getModifiers(): string { return self::MODIFIERS; } - public function getAccumulatedValues() : string + public function getAccumulatedValues(): string { return $this->accumulator; } - public function startRecording() : void + public function startRecording(): void { $this->hasToRecord = true; } - public function stopRecording() : void + public function stopRecording(): void { $this->hasToRecord = false; } - public function clearRecorded() : void + public function clearRecorded(): void { $this->accumulator = ''; } -} +} \ No newline at end of file diff --git a/src/EmailParser.php b/src/EmailParser.php index 352eae4..788d016 100644 --- a/src/EmailParser.php +++ b/src/EmailParser.php @@ -24,7 +24,7 @@ class EmailParser extends Parser */ protected $localPart = ''; - public function parse(string $str) : Result + public function parse(string $str): Result { $result = parent::parse($str); @@ -32,11 +32,11 @@ class EmailParser extends Parser return $result; } - + protected function preLeftParsing(): Result { if (!$this->hasAtToken()) { - return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]); + return new InvalidEmail(new NoLocalPart(), $this->lexer->current->value); } return new ValidEmail(); } @@ -51,7 +51,7 @@ class EmailParser extends Parser return $this->processDomainPart(); } - private function processLocalPart() : Result + private function processLocalPart(): Result { $localPartParser = new LocalPart($this->lexer); $localPartResult = $localPartParser->parse(); @@ -61,27 +61,27 @@ class EmailParser extends Parser return $localPartResult; } - private function processDomainPart() : Result + private function processDomainPart(): Result { $domainPartParser = new DomainPart($this->lexer); $domainPartResult = $domainPartParser->parse(); $this->domainPart = $domainPartParser->domainPart(); $this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings); - + return $domainPartResult; } - public function getDomainPart() : string + public function getDomainPart(): string { return $this->domainPart; } - public function getLocalPart() : string + public function getLocalPart(): string { return $this->localPart; } - private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void + private function addLongEmailWarning(string $localPart, string $parsedDomainPart): void { if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) { $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); diff --git a/src/MessageIDParser.php b/src/MessageIDParser.php index b0b6720..9df27db 100644 --- a/src/MessageIDParser.php +++ b/src/MessageIDParser.php @@ -25,7 +25,7 @@ class MessageIDParser extends Parser */ protected $idRight = ''; - public function parse(string $str) : Result + public function parse(string $str): Result { $result = parent::parse($str); @@ -33,11 +33,11 @@ class MessageIDParser extends Parser return $result; } - + protected function preLeftParsing(): Result { if (!$this->hasAtToken()) { - return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]); + return new InvalidEmail(new NoLocalPart(), $this->lexer->current->value); } return new ValidEmail(); } @@ -52,7 +52,7 @@ class MessageIDParser extends Parser return $this->processIDRight(); } - private function processIDLeft() : Result + private function processIDLeft(): Result { $localPartParser = new IDLeftPart($this->lexer); $localPartResult = $localPartParser->parse(); @@ -62,27 +62,27 @@ class MessageIDParser extends Parser return $localPartResult; } - private function processIDRight() : Result + private function processIDRight(): Result { $domainPartParser = new IDRightPart($this->lexer); $domainPartResult = $domainPartParser->parse(); $this->idRight = $domainPartParser->domainPart(); $this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings); - + return $domainPartResult; } - public function getLeftPart() : string + public function getLeftPart(): string { return $this->idLeft; } - public function getRightPart() : string + public function getRightPart(): string { return $this->idRight; } - private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void + private function addLongEmailWarning(string $localPart, string $parsedDomainPart): void { if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAILID_MAX_LENGTH) { $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); diff --git a/src/Parser.php b/src/Parser.php index b1905f9..d577e3e 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -22,22 +22,22 @@ abstract class Parser /** * id-left "@" id-right */ - abstract protected function parseRightFromAt() : Result; - abstract protected function parseLeftFromAt() : Result; - abstract protected function preLeftParsing() : Result; + abstract protected function parseRightFromAt(): Result; + abstract protected function parseLeftFromAt(): Result; + abstract protected function preLeftParsing(): Result; public function __construct(EmailLexer $lexer) { - $this->lexer = $lexer; + $this->lexer = $lexer; } - public function parse(string $str) : Result + public function parse(string $str): Result { $this->lexer->setInput($str); if ($this->lexer->hasInvalidTokens()) { - return new InvalidEmail(new ExpectingATEXT("Invalid tokens found"), $this->lexer->token["value"]); + return new InvalidEmail(new ExpectingATEXT("Invalid tokens found"), $this->lexer->current->value); } $preParsingResult = $this->preLeftParsing(); @@ -51,7 +51,7 @@ abstract class Parser return $localPartResult; } - $domainPartResult = $this->parseRightFromAt(); + $domainPartResult = $this->parseRightFromAt(); if ($domainPartResult->isInvalid()) { return $domainPartResult; @@ -63,16 +63,16 @@ abstract class Parser /** * @return Warning\Warning[] */ - public function getWarnings() : array + public function getWarnings(): array { return $this->warnings; } - protected function hasAtToken() : bool + protected function hasAtToken(): bool { $this->lexer->moveNext(); $this->lexer->moveNext(); - return $this->lexer->token['type'] !== EmailLexer::S_AT; + return !$this->lexer->current->isA(EmailLexer::S_AT); } } diff --git a/src/Parser/Comment.php b/src/Parser/Comment.php index d6f3032..9e4ab21 100644 --- a/src/Parser/Comment.php +++ b/src/Parser/Comment.php @@ -29,39 +29,39 @@ class Comment extends PartParser $this->commentStrategy = $commentStrategy; } - public function parse() : Result + public function parse(): Result { - if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + if ($this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS)) { $this->openedParenthesis++; - if($this->noClosingParenthesis()) { - return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']); + if ($this->noClosingParenthesis()) { + return new InvalidEmail(new UnclosedComment(), $this->lexer->current->value); } } - if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { - return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS)) { + return new InvalidEmail(new UnOpenedComment(), $this->lexer->current->value); } $this->warnings[WarningComment::CODE] = new WarningComment(); $moreTokens = true; - while ($this->commentStrategy->exitCondition($this->lexer, $this->openedParenthesis) && $moreTokens){ + while ($this->commentStrategy->exitCondition($this->lexer, $this->openedParenthesis) && $moreTokens) { if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) { $this->openedParenthesis++; } $this->warnEscaping(); - if($this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { + if ($this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { $this->openedParenthesis--; } $moreTokens = $this->lexer->moveNext(); } - if($this->openedParenthesis >= 1) { - return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']); + if ($this->openedParenthesis >= 1) { + return new InvalidEmail(new UnclosedComment(), $this->lexer->current->value); } if ($this->openedParenthesis < 0) { - return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']); + return new InvalidEmail(new UnOpenedComment(), $this->lexer->current->value); } $finalValidations = $this->commentStrategy->endOfLoopValidations($this->lexer); @@ -75,10 +75,10 @@ class Comment extends PartParser /** * @return bool */ - private function warnEscaping() : bool + private function warnEscaping(): bool { //Backslash found - if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { + if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { return false; } @@ -87,12 +87,11 @@ class Comment extends PartParser } $this->warnings[QuotedPart::CODE] = - new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); + new QuotedPart($this->lexer->getPrevious()->type, $this->lexer->current->type); return true; - } - private function noClosingParenthesis() : bool + private function noClosingParenthesis(): bool { try { $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); diff --git a/src/Parser/CommentStrategy/CommentStrategy.php b/src/Parser/CommentStrategy/CommentStrategy.php index 410032f..8834db0 100644 --- a/src/Parser/CommentStrategy/CommentStrategy.php +++ b/src/Parser/CommentStrategy/CommentStrategy.php @@ -4,15 +4,19 @@ namespace Egulias\EmailValidator\Parser\CommentStrategy; use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\Result\Result; +use Egulias\EmailValidator\Warning\Warning; interface CommentStrategy { /** * Return "true" to continue, "false" to exit */ - public function exitCondition(EmailLexer $lexer, int $openedParenthesis) : bool; + public function exitCondition(EmailLexer $lexer, int $openedParenthesis): bool; - public function endOfLoopValidations(EmailLexer $lexer) : Result; + public function endOfLoopValidations(EmailLexer $lexer): Result; - public function getWarnings() : array; + /** + * @return Warning[] + */ + public function getWarnings(): array; } diff --git a/src/Parser/CommentStrategy/DomainComment.php b/src/Parser/CommentStrategy/DomainComment.php index cbbe3f2..a197c27 100644 --- a/src/Parser/CommentStrategy/DomainComment.php +++ b/src/Parser/CommentStrategy/DomainComment.php @@ -10,20 +10,20 @@ use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; class DomainComment implements CommentStrategy { - public function exitCondition(EmailLexer $lexer, int $openedParenthesis) : bool + public function exitCondition(EmailLexer $lexer, int $openedParenthesis): bool { - if (($openedParenthesis === 0 && $lexer->isNextToken(EmailLexer::S_DOT))){ // || !$internalLexer->moveNext()) { + if (($openedParenthesis === 0 && $lexer->isNextToken(EmailLexer::S_DOT))) { // || !$internalLexer->moveNext()) { return false; } return true; } - public function endOfLoopValidations(EmailLexer $lexer) : Result + public function endOfLoopValidations(EmailLexer $lexer): Result { //test for end of string if (!$lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new ExpectingATEXT('DOT not found near CLOSEPARENTHESIS'), $lexer->token['value']); + return new InvalidEmail(new ExpectingATEXT('DOT not found near CLOSEPARENTHESIS'), $lexer->current->value); } //add warning //Address is valid within the message but cannot be used unmodified for the envelope diff --git a/src/Parser/CommentStrategy/LocalComment.php b/src/Parser/CommentStrategy/LocalComment.php index e72319a..5c18b44 100644 --- a/src/Parser/CommentStrategy/LocalComment.php +++ b/src/Parser/CommentStrategy/LocalComment.php @@ -16,15 +16,15 @@ class LocalComment implements CommentStrategy */ private $warnings = []; - public function exitCondition(EmailLexer $lexer, int $openedParenthesis) : bool + public function exitCondition(EmailLexer $lexer, int $openedParenthesis): bool { return !$lexer->isNextToken(EmailLexer::S_AT); } - public function endOfLoopValidations(EmailLexer $lexer) : Result + public function endOfLoopValidations(EmailLexer $lexer): Result { if (!$lexer->isNextToken(EmailLexer::S_AT)) { - return new InvalidEmail(new ExpectingATEXT('ATEX is not expected after closing comments'), $lexer->token['value']); + return new InvalidEmail(new ExpectingATEXT('ATEX is not expected after closing comments'), $lexer->current->value); } $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); return new ValidEmail(); diff --git a/src/Parser/DomainLiteral.php b/src/Parser/DomainLiteral.php index e6d66d0..e99498d 100644 --- a/src/Parser/DomainLiteral.php +++ b/src/Parser/DomainLiteral.php @@ -1,4 +1,5 @@ addTagWarnings(); @@ -39,14 +40,14 @@ class DomainLiteral extends PartParser $addressLiteral = ''; do { - if ($this->lexer->token['type'] === EmailLexer::C_NUL) { - return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::C_NUL)) { + return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value); } $this->addObsoleteWarnings(); if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) { - return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']); + return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value); } if ($this->lexer->isNextTokenAny( @@ -57,22 +58,21 @@ class DomainLiteral extends PartParser } if ($this->lexer->isNextToken(EmailLexer::S_CR)) { - return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']); + return new InvalidEmail(new CRNoLF(), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) { - return new InvalidEmail(new UnusualElements($this->lexer->token['value']), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { + return new InvalidEmail(new UnusualElements($this->lexer->current->value), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) { + if ($this->lexer->current->isA(EmailLexer::S_IPV6TAG)) { $IPv6TAG = true; } - if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) { + if ($this->lexer->current->isA(EmailLexer::S_CLOSEBRACKET)) { break; } - $addressLiteral .= $this->lexer->token['value']; - + $addressLiteral .= $this->lexer->current->value; } while ($this->lexer->moveNext()); @@ -102,10 +102,10 @@ class DomainLiteral extends PartParser * @param string $addressLiteral * @param int $maxGroups */ - public function checkIPV6Tag($addressLiteral, $maxGroups = 8) : void + public function checkIPV6Tag($addressLiteral, $maxGroups = 8): void { $prev = $this->lexer->getPrevious(); - if ($prev['type'] === EmailLexer::S_COLON) { + if ($prev->isA(EmailLexer::S_COLON)) { $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd(); } @@ -144,8 +144,8 @@ class DomainLiteral extends PartParser $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated(); } } - - public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string + + public function convertIPv4ToIPv6(string $addressLiteralIPv4): string { $matchesIP = []; $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP); @@ -168,7 +168,7 @@ class DomainLiteral extends PartParser * * @return bool */ - protected function checkIPV4Tag($addressLiteral) : bool + protected function checkIPV4Tag($addressLiteral): bool { $matchesIP = []; $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP); @@ -187,14 +187,14 @@ class DomainLiteral extends PartParser return true; } - private function addObsoleteWarnings() : void + private function addObsoleteWarnings(): void { - if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) { + if (in_array($this->lexer->current->type, self::OBSOLETE_WARNINGS)) { $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); } } - private function addTagWarnings() : void + private function addTagWarnings(): void { if ($this->lexer->isNextToken(EmailLexer::S_COLON)) { $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); @@ -207,5 +207,4 @@ class DomainLiteral extends PartParser } } } - } diff --git a/src/Parser/DomainPart.php b/src/Parser/DomainPart.php index e1f5b3b..6aca537 100644 --- a/src/Parser/DomainPart.php +++ b/src/Parser/DomainPart.php @@ -38,7 +38,7 @@ class DomainPart extends PartParser */ protected $label = ''; - public function parse() : Result + public function parse(): Result { $this->lexer->clearRecorded(); $this->lexer->startRecording(); @@ -50,8 +50,8 @@ class DomainPart extends PartParser return $domainChecks; } - if ($this->lexer->token['type'] === EmailLexer::S_AT) { - return new InvalidEmail(new ConsecutiveAt(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_AT)) { + return new InvalidEmail(new ConsecutiveAt(), $this->lexer->current->value); } $result = $this->doParseDomainPart(); @@ -69,67 +69,66 @@ class DomainPart extends PartParser $length = strlen($this->domainPart); if ($length > self::DOMAIN_MAX_LENGTH) { - return new InvalidEmail(new DomainTooLong(), $this->lexer->token['value']); + return new InvalidEmail(new DomainTooLong(), $this->lexer->current->value); } return new ValidEmail(); } - private function checkEndOfDomain() : Result + private function checkEndOfDomain(): Result { $prev = $this->lexer->getPrevious(); - if ($prev['type'] === EmailLexer::S_DOT) { - return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']); + if ($prev->isA(EmailLexer::S_DOT)) { + return new InvalidEmail(new DotAtEnd(), $this->lexer->current->value); } - if ($prev['type'] === EmailLexer::S_HYPHEN) { - return new InvalidEmail(new DomainHyphened('Hypen found at the end of the domain'), $prev['value']); + if ($prev->isA(EmailLexer::S_HYPHEN)) { + return new InvalidEmail(new DomainHyphened('Hypen found at the end of the domain'), $prev->value); } - if ($this->lexer->token['type'] === EmailLexer::S_SP) { - return new InvalidEmail(new CRLFAtTheEnd(), $prev['value']); + if ($this->lexer->current->isA(EmailLexer::S_SP)) { + return new InvalidEmail(new CRLFAtTheEnd(), $prev->value); } return new ValidEmail(); - } - private function performDomainStartChecks() : Result + private function performDomainStartChecks(): Result { $invalidTokens = $this->checkInvalidTokensAfterAT(); if ($invalidTokens->isInvalid()) { return $invalidTokens; } - + $missingDomain = $this->checkEmptyDomain(); if ($missingDomain->isInvalid()) { return $missingDomain; } - if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + if ($this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS)) { $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); } return new ValidEmail(); } - private function checkEmptyDomain() : Result + private function checkEmptyDomain(): Result { - $thereIsNoDomain = $this->lexer->token['type'] === EmailLexer::S_EMPTY || - ($this->lexer->token['type'] === EmailLexer::S_SP && - !$this->lexer->isNextToken(EmailLexer::GENERIC)); + $thereIsNoDomain = $this->lexer->current->isA(EmailLexer::S_EMPTY) || + ($this->lexer->current->isA(EmailLexer::S_SP) && + !$this->lexer->isNextToken(EmailLexer::GENERIC)); if ($thereIsNoDomain) { - return new InvalidEmail(new NoDomainPart(), $this->lexer->token['value']); + return new InvalidEmail(new NoDomainPart(), $this->lexer->current->value); } return new ValidEmail(); } - private function checkInvalidTokensAfterAT() : Result + private function checkInvalidTokensAfterAT(): Result { - if ($this->lexer->token['type'] === EmailLexer::S_DOT) { - return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_DOT)) { + return new InvalidEmail(new DotAtStart(), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) { - return new InvalidEmail(new DomainHyphened('After AT'), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_HYPHEN)) { + return new InvalidEmail(new DomainHyphened('After AT'), $this->lexer->current->value); } return new ValidEmail(); } @@ -143,7 +142,7 @@ class DomainPart extends PartParser return $result; } - protected function doParseDomainPart() : Result + protected function doParseDomainPart(): Result { $tldMissing = true; $hasComments = false; @@ -151,18 +150,20 @@ class DomainPart extends PartParser do { $prev = $this->lexer->getPrevious(); - $notAllowedChars = $this->checkNotAllowedChars($this->lexer->token); + $notAllowedChars = $this->checkNotAllowedChars($this->lexer->current); if ($notAllowedChars->isInvalid()) { return $notAllowedChars; } - if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS || - $this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) { + if ( + $this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS) || + $this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS) + ) { $hasComments = true; $commentsResult = $this->parseComments(); //Invalid comment parsing - if($commentsResult->isInvalid()) { + if ($commentsResult->isInvalid()) { return $commentsResult; } } @@ -172,26 +173,26 @@ class DomainPart extends PartParser return $dotsResult; } - if ($this->lexer->token['type'] === EmailLexer::S_OPENBRACKET) { + if ($this->lexer->current->isA(EmailLexer::S_OPENBRACKET)) { $literalResult = $this->parseDomainLiteral(); $this->addTLDWarnings($tldMissing); return $literalResult; } - $labelCheck = $this->checkLabelLength(); - if ($labelCheck->isInvalid()) { - return $labelCheck; - } + $labelCheck = $this->checkLabelLength(); + if ($labelCheck->isInvalid()) { + return $labelCheck; + } $FwsResult = $this->parseFWS(); - if($FwsResult->isInvalid()) { + if ($FwsResult->isInvalid()) { return $FwsResult; } - $domain .= $this->lexer->token['value']; + $domain .= $this->lexer->current->value; - if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::GENERIC)) { + if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::GENERIC)) { $tldMissing = false; } @@ -200,8 +201,7 @@ class DomainPart extends PartParser return $exceptionsResult; } $this->lexer->moveNext(); - - } while (null !== $this->lexer->token['type']); + } while (!$this->lexer->current->isA(EmailLexer::S_EMPTY)); $labelCheck = $this->checkLabelLength(true); if ($labelCheck->isInvalid()) { @@ -213,14 +213,16 @@ class DomainPart extends PartParser return new ValidEmail(); } - /** - * @psalm-param array|Token $token + /** + * @param Token $token + * + * @return Result */ - private function checkNotAllowedChars($token) : Result + private function checkNotAllowedChars(Token $token): Result { - $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; - if (isset($notAllowed[$token['type']])) { - return new InvalidEmail(new CharNotAllowed(), $token['value']); + $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH => true]; + if (isset($notAllowed[$token->type])) { + return new InvalidEmail(new CharNotAllowed(), $token->value); } return new ValidEmail(); } @@ -228,12 +230,12 @@ class DomainPart extends PartParser /** * @return Result */ - protected function parseDomainLiteral() : Result + protected function parseDomainLiteral(): Result { try { $this->lexer->find(EmailLexer::S_CLOSEBRACKET); } catch (\RuntimeException $e) { - return new InvalidEmail(new ExpectingDomainLiteralClose(), $this->lexer->token['value']); + return new InvalidEmail(new ExpectingDomainLiteralClose(), $this->lexer->current->value); } $domainLiteralParser = new DomainLiteralParser($this->lexer); @@ -242,25 +244,33 @@ class DomainPart extends PartParser return $result; } - protected function checkDomainPartExceptions(array $prev, bool $hasComments) : Result + /** + * @param Token $prev + * @param bool $hasComments + * + * @return Result + */ + protected function checkDomainPartExceptions(Token $prev, bool $hasComments): Result { - 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']); + if ($this->lexer->current->isA(EmailLexer::S_OPENBRACKET) && $prev->type !== EmailLexer::S_AT) { + return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_HYPHEN) && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH - && $this->lexer->isNextToken(EmailLexer::GENERIC)) { - return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), $this->lexer->token['value']); + if ( + $this->lexer->current->isA(EmailLexer::S_BACKSLASH) + && $this->lexer->isNextToken(EmailLexer::GENERIC) + ) { + return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), $this->lexer->current->value); } return $this->validateTokens($hasComments); } - protected function validateTokens(bool $hasComments) : Result + protected function validateTokens(bool $hasComments): Result { $validDomainTokens = array( EmailLexer::GENERIC => true, @@ -273,27 +283,27 @@ class DomainPart extends PartParser $validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true; } - if (!isset($validDomainTokens[$this->lexer->token['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']); + if (!isset($validDomainTokens[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->current->value), $this->lexer->current->value); } return new ValidEmail(); } - private function checkLabelLength(bool $isEndOfDomain = false) : Result + private function checkLabelLength(bool $isEndOfDomain = false): Result { - if ($this->lexer->token['type'] === EmailLexer::S_DOT || $isEndOfDomain) { + if ($this->lexer->current->isA(EmailLexer::S_DOT) || $isEndOfDomain) { if ($this->isLabelTooLong($this->label)) { - return new InvalidEmail(new LabelTooLong(), $this->lexer->token['value']); + return new InvalidEmail(new LabelTooLong(), $this->lexer->current->value); } $this->label = ''; } - $this->label .= $this->lexer->token['value']; + $this->label .= $this->lexer->current->value; return new ValidEmail(); } - private function isLabelTooLong(string $label) : bool + private function isLabelTooLong(string $label): bool { if (preg_match('/[^\x00-\x7F]/', $label)) { idn_to_ascii($label, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo); @@ -302,15 +312,15 @@ class DomainPart extends PartParser return strlen($label) > self::LABEL_MAX_LENGTH; } - private function addTLDWarnings(bool $isTLDMissing) : void + private function addTLDWarnings(bool $isTLDMissing): void { if ($isTLDMissing) { $this->warnings[TLD::CODE] = new TLD(); } } - public function domainPart() : string + public function domainPart(): string { return $this->domainPart; } -} +} \ No newline at end of file diff --git a/src/Parser/DoubleQuote.php b/src/Parser/DoubleQuote.php index b32e2b6..b96dba5 100644 --- a/src/Parser/DoubleQuote.php +++ b/src/Parser/DoubleQuote.php @@ -1,4 +1,5 @@ checkDQUOTE(); - if($validQuotedString->isInvalid()) return $validQuotedString; + if ($validQuotedString->isInvalid()) return $validQuotedString; $special = [ EmailLexer::S_CR => true, @@ -30,58 +31,57 @@ class DoubleQuote extends PartParser EmailLexer::S_CR => true, EmailLexer::S_LF => true ]; - + $setSpecialsWarning = true; $this->lexer->moveNext(); - while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) { - if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) { + while (!$this->lexer->current->isA(EmailLexer::S_DQUOTE) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) { + if (isset($special[$this->lexer->current->type]) && $setSpecialsWarning) { $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); $setSpecialsWarning = false; } - if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) { + if ($this->lexer->current->isA(EmailLexer::S_BACKSLASH) && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) { $this->lexer->moveNext(); } $this->lexer->moveNext(); - if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) { - return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->token['value']); + if (!$this->escaped() && isset($invalid[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->current->value); } } $prev = $this->lexer->getPrevious(); - if ($prev['type'] === EmailLexer::S_BACKSLASH) { + if ($prev->isA(EmailLexer::S_BACKSLASH)) { $validQuotedString = $this->checkDQUOTE(); - if($validQuotedString->isInvalid()) return $validQuotedString; + if ($validQuotedString->isInvalid()) return $validQuotedString; } - if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) { - return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->token['value']); + if (!$this->lexer->isNextToken(EmailLexer::S_AT) && !$prev->isA(EmailLexer::S_BACKSLASH)) { + return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->current->value); } return new ValidEmail(); } - protected function checkDQUOTE() : Result + protected function checkDQUOTE(): Result { $previous = $this->lexer->getPrevious(); - if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) { + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous->isA(EmailLexer::GENERIC)) { $description = 'https://tools.ietf.org/html/rfc5322#section-3.2.4 - quoted string should be a unit'; - return new InvalidEmail(new ExpectingATEXT($description), $this->lexer->token['value']); + return new InvalidEmail(new ExpectingATEXT($description), $this->lexer->current->value); } try { $this->lexer->find(EmailLexer::S_DQUOTE); } catch (\Exception $e) { - return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->token['value']); + return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->current->value); } - $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']); + $this->warnings[QuotedString::CODE] = new QuotedString($previous->value, $this->lexer->current->value); return new ValidEmail(); } - } diff --git a/src/Parser/FoldingWhiteSpace.php b/src/Parser/FoldingWhiteSpace.php index fff6ec3..348a7af 100644 --- a/src/Parser/FoldingWhiteSpace.php +++ b/src/Parser/FoldingWhiteSpace.php @@ -1,4 +1,5 @@ isFWS()) { return new ValidEmail(); @@ -36,19 +37,19 @@ class FoldingWhiteSpace extends PartParser return $resultCRLF; } - if ($this->lexer->token['type'] === EmailLexer::S_CR) { - return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_CR)) { + return new InvalidEmail(new CRNoLF(), $this->lexer->current->value); } - if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) { - return new InvalidEmail(new AtextAfterCFWS(), $this->lexer->token['value']); + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && !$previous->isA(EmailLexer::S_AT)) { + return new InvalidEmail(new AtextAfterCFWS(), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) { - return new InvalidEmail(new ExpectingCTEXT(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_LF) || $this->lexer->current->isA(EmailLexer::C_NUL)) { + return new InvalidEmail(new ExpectingCTEXT(), $this->lexer->current->value); } - if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) { + if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous->isA(EmailLexer::S_AT)) { $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); } else { $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); @@ -57,30 +58,30 @@ class FoldingWhiteSpace extends PartParser return new ValidEmail(); } - protected function checkCRLFInFWS() : Result + protected function checkCRLFInFWS(): Result { - if ($this->lexer->token['type'] !== EmailLexer::CRLF) { + if (!$this->lexer->current->isA(EmailLexer::CRLF)) { return new ValidEmail(); } if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { - return new InvalidEmail(new CRLFX2(), $this->lexer->token['value']); + return new InvalidEmail(new CRLFX2(), $this->lexer->current->value); } //this has no coverage. Condition is repeated from above one if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { - return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->token['value']); + return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->current->value); } return new ValidEmail(); } - - protected function isFWS() : bool + + protected function isFWS(): bool { if ($this->escaped()) { return false; } - return in_array($this->lexer->token['type'], self::FWS_TYPES); + return in_array($this->lexer->current->type, self::FWS_TYPES); } } diff --git a/src/Parser/IDLeftPart.php b/src/Parser/IDLeftPart.php index 5fd9cdf..bedcf7b 100644 --- a/src/Parser/IDLeftPart.php +++ b/src/Parser/IDLeftPart.php @@ -10,6 +10,6 @@ class IDLeftPart extends LocalPart { protected function parseComments(): Result { - return new InvalidEmail(new CommentsInIDRight(), $this->lexer->token['value']); + return new InvalidEmail(new CommentsInIDRight(), $this->lexer->current->value); } } diff --git a/src/Parser/IDRightPart.php b/src/Parser/IDRightPart.php index 1a1268f..d2fc1d7 100644 --- a/src/Parser/IDRightPart.php +++ b/src/Parser/IDRightPart.php @@ -10,7 +10,7 @@ use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; class IDRightPart extends DomainPart { - protected function validateTokens(bool $hasComments) : Result + protected function validateTokens(bool $hasComments): Result { $invalidDomainTokens = [ EmailLexer::S_DQUOTE => true, @@ -20,9 +20,9 @@ class IDRightPart extends DomainPart EmailLexer::S_GREATERTHAN => true, EmailLexer::S_LOWERTHAN => true, ]; - - if (isset($invalidDomainTokens[$this->lexer->token['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']); + + if (isset($invalidDomainTokens[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->current->value), $this->lexer->current->value); } return new ValidEmail(); } diff --git a/src/Parser/LocalPart.php b/src/Parser/LocalPart.php index 154521b..a6087e6 100644 --- a/src/Parser/LocalPart.php +++ b/src/Parser/LocalPart.php @@ -32,42 +32,45 @@ class LocalPart extends PartParser private $localPart = ''; - public function parse() : Result + public function parse(): Result { $this->lexer->startRecording(); - while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) { + while (!$this->lexer->current->isA(EmailLexer::S_AT) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) { if ($this->hasDotAtStart()) { - return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']); + return new InvalidEmail(new DotAtStart(), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_DQUOTE) { + if ($this->lexer->current->isA(EmailLexer::S_DQUOTE)) { $dquoteParsingResult = $this->parseDoubleQuote(); //Invalid double quote parsing - if($dquoteParsingResult->isInvalid()) { + if ($dquoteParsingResult->isInvalid()) { return $dquoteParsingResult; } } - if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS || - $this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) { + if ( + $this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS) || + $this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS) + ) { $commentsResult = $this->parseComments(); //Invalid comment parsing - if($commentsResult->isInvalid()) { + if ($commentsResult->isInvalid()) { return $commentsResult; } } - if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new ConsecutiveDot(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new ConsecutiveDot(), $this->lexer->current->value); } - if ($this->lexer->token['type'] === EmailLexer::S_DOT && + if ( + $this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::S_AT) ) { - return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']); + return new InvalidEmail(new DotAtEnd(), $this->lexer->current->value); } $resultEscaping = $this->validateEscaping(); @@ -81,7 +84,7 @@ class LocalPart extends PartParser } $resultFWS = $this->parseLocalFWS(); - if($resultFWS->isInvalid()) { + if ($resultFWS->isInvalid()) { return $resultFWS; } @@ -97,20 +100,20 @@ class LocalPart extends PartParser return new ValidEmail(); } - protected function validateTokens(bool $hasComments) : Result + protected function validateTokens(bool $hasComments): Result { - if (isset(self::INVALID_TOKENS[$this->lexer->token['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']); + if (isset(self::INVALID_TOKENS[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->current->value); } return new ValidEmail(); } - public function localPart() : string + public function localPart(): string { return $this->localPart; } - private function parseLocalFWS() : Result + private function parseLocalFWS(): Result { $foldingWS = new FoldingWhiteSpace($this->lexer); $resultFWS = $foldingWS->parse(); @@ -120,12 +123,12 @@ class LocalPart extends PartParser return $resultFWS; } - private function hasDotAtStart() : bool + private function hasDotAtStart(): bool { - return $this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type']; + return $this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->getPrevious()->isA(EmailLexer::S_EMPTY); } - private function parseDoubleQuote() : Result + private function parseDoubleQuote(): Result { $dquoteParser = new DoubleQuote($this->lexer); $parseAgain = $dquoteParser->parse(); @@ -139,21 +142,21 @@ class LocalPart extends PartParser $commentParser = new Comment($this->lexer, new LocalComment()); $result = $commentParser->parse(); $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); - if($result->isInvalid()) { + if ($result->isInvalid()) { return $result; } return $result; } - private function validateEscaping() : Result + private function validateEscaping(): Result { //Backslash found - if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { + if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { return new ValidEmail(); } if ($this->lexer->isNextToken(EmailLexer::GENERIC)) { - return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->token['value']); + return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->current->value); } if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { diff --git a/src/Parser/PartParser.php b/src/Parser/PartParser.php index a75a172..d0ed5fd 100644 --- a/src/Parser/PartParser.php +++ b/src/Parser/PartParser.php @@ -7,11 +7,12 @@ use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\Reason\ConsecutiveDot; use Egulias\EmailValidator\Result\Result; use Egulias\EmailValidator\Result\ValidEmail; +use Egulias\EmailValidator\Warning\Warning; abstract class PartParser { /** - * @var array + * @var Warning[] */ protected $warnings = []; @@ -25,17 +26,17 @@ abstract class PartParser $this->lexer = $lexer; } - abstract public function parse() : Result; + abstract public function parse(): Result; /** - * @return \Egulias\EmailValidator\Warning\Warning[] + * @return Warning[] */ public function getWarnings() { return $this->warnings; } - protected function parseFWS() : Result + protected function parseFWS(): Result { $foldingWS = new FoldingWhiteSpace($this->lexer); $resultFWS = $foldingWS->parse(); @@ -43,21 +44,20 @@ abstract class PartParser return $resultFWS; } - protected function checkConsecutiveDots() : Result + protected function checkConsecutiveDots(): Result { - if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new ConsecutiveDot(), $this->lexer->token['value']); + if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new ConsecutiveDot(), $this->lexer->current->value); } return new ValidEmail(); } - protected function escaped() : bool + protected function escaped(): bool { $previous = $this->lexer->getPrevious(); - return $previous && $previous['type'] === EmailLexer::S_BACKSLASH - && - $this->lexer->token['type'] !== EmailLexer::GENERIC; + return $previous->isA(EmailLexer::S_BACKSLASH) + && !$this->lexer->current->isA(EmailLexer::GENERIC); } } diff --git a/src/Result/InvalidEmail.php b/src/Result/InvalidEmail.php index 180f4d8..82699ac 100644 --- a/src/Result/InvalidEmail.php +++ b/src/Result/InvalidEmail.php @@ -6,11 +6,15 @@ use Egulias\EmailValidator\Result\Reason\Reason; class InvalidEmail implements Result { - private $token; + /** + * @var string + */ + private string $token; + /** * @var Reason */ - protected $reason; + protected Reason $reason; public function __construct(Reason $reason, string $token) { @@ -38,9 +42,8 @@ class InvalidEmail implements Result return $this->reason->code(); } - public function reason() : Reason + public function reason(): Reason { return $this->reason; } - } diff --git a/src/Validation/DNSCheckValidation.php b/src/Validation/DNSCheckValidation.php index 4882b80..d9ffaad 100644 --- a/src/Validation/DNSCheckValidation.php +++ b/src/Validation/DNSCheckValidation.php @@ -9,6 +9,7 @@ use Egulias\EmailValidator\Result\Reason\LocalOrReservedDomain; use Egulias\EmailValidator\Result\Reason\NoDNSRecord as ReasonNoDNSRecord; use Egulias\EmailValidator\Result\Reason\UnableToGetDNSRecord; use Egulias\EmailValidator\Warning\NoDNSMXRecord; +use Egulias\EmailValidator\Warning\Warning; class DNSCheckValidation implements EmailValidation { @@ -20,6 +21,8 @@ class DNSCheckValidation implements EmailValidation /** * Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2), * mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G) + * + * @var string[] */ public const RESERVED_DNS_TOP_LEVEL_NAMES = [ // Reserved Top Level DNS Names @@ -39,9 +42,9 @@ class DNSCheckValidation implements EmailValidation 'home', 'lan', ]; - + /** - * @var array + * @var Warning[] */ private $warnings = []; @@ -73,7 +76,7 @@ class DNSCheckValidation implements EmailValidation $this->dnsGetRecord = $dnsGetRecord; } - public function isValid(string $email, EmailLexer $emailLexer) : bool + public function isValid(string $email, EmailLexer $emailLexer): bool { // use the input to check DNS if we cannot extract something similar to a domain $host = $email; @@ -98,12 +101,15 @@ class DNSCheckValidation implements EmailValidation return $this->checkDns($host); } - public function getError() : ?InvalidEmail + public function getError(): ?InvalidEmail { return $this->error; } - public function getWarnings() : array + /** + * @return Warning[] + */ + public function getWarnings(): array { return $this->warnings; } @@ -130,7 +136,7 @@ class DNSCheckValidation implements EmailValidation * * @return bool True on success. */ - private function validateDnsRecords($host) : bool + private function validateDnsRecords($host): bool { $dnsRecordsResult = $this->dnsGetRecord->getRecords($host, static::DNS_RECORD_TYPES_TO_CHECK); @@ -167,7 +173,7 @@ class DNSCheckValidation implements EmailValidation * * @return bool True if valid. */ - private function validateMxRecord($dnsRecord) : bool + private function validateMxRecord($dnsRecord): bool { if (!isset($dnsRecord['type'])) { $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); diff --git a/src/Validation/DNSGetRecordWrapper.php b/src/Validation/DNSGetRecordWrapper.php index f493c57..25e2fa0 100644 --- a/src/Validation/DNSGetRecordWrapper.php +++ b/src/Validation/DNSGetRecordWrapper.php @@ -1,4 +1,5 @@ records = $records; $this->error = $error; } - public function getRecords() : array + /** + * @return array + */ + public function getRecords(): array { return $this->records; } - public function withError() : bool + public function withError(): bool { return $this->error; } - - } diff --git a/src/Validation/MessageIDValidation.php b/src/Validation/MessageIDValidation.php index 0e02043..97d1ea7 100644 --- a/src/Validation/MessageIDValidation.php +++ b/src/Validation/MessageIDValidation.php @@ -6,12 +6,13 @@ use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\MessageIDParser; use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\Reason\ExceptionFound; +use Egulias\EmailValidator\Warning\Warning; class MessageIDValidation implements EmailValidation { /** - * @var array + * @var Warning[] */ private $warnings = []; @@ -39,6 +40,9 @@ class MessageIDValidation implements EmailValidation return true; } + /** + * @return Warning[] + */ public function getWarnings(): array { return $this->warnings; diff --git a/src/Validation/MultipleValidationWithAnd.php b/src/Validation/MultipleValidationWithAnd.php index abafe75..f23e84b 100644 --- a/src/Validation/MultipleValidationWithAnd.php +++ b/src/Validation/MultipleValidationWithAnd.php @@ -6,6 +6,7 @@ use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Validation\Exception\EmptyValidationList; use Egulias\EmailValidator\Result\MultipleErrors; +use Egulias\EmailValidator\Warning\Warning; class MultipleValidationWithAnd implements EmailValidation { @@ -27,7 +28,7 @@ class MultipleValidationWithAnd implements EmailValidation private $validations = []; /** - * @var array + * @var Warning[] */ private $warnings = []; @@ -58,7 +59,7 @@ class MultipleValidationWithAnd implements EmailValidation /** * {@inheritdoc} */ - public function isValid(string $email, EmailLexer $emailLexer) : bool + public function isValid(string $email, EmailLexer $emailLexer): bool { $result = true; foreach ($this->validations as $validation) { @@ -78,14 +79,14 @@ class MultipleValidationWithAnd implements EmailValidation return $result; } - private function initErrorStorage() : void + private function initErrorStorage(): void { if (null === $this->error) { $this->error = new MultipleErrors(); } } - private function processError(EmailValidation $validation) : void + private function processError(EmailValidation $validation): void { if (null !== $validation->getError()) { $this->initErrorStorage(); @@ -94,7 +95,7 @@ class MultipleValidationWithAnd implements EmailValidation } } - private function shouldStop(bool $result) : bool + private function shouldStop(bool $result): bool { return !$result && $this->mode === self::STOP_ON_ERROR; } @@ -102,15 +103,15 @@ class MultipleValidationWithAnd implements EmailValidation /** * Returns the validation errors. */ - public function getError() : ?InvalidEmail + public function getError(): ?InvalidEmail { return $this->error; } /** - * {@inheritdoc} + * @return Warning[] */ - public function getWarnings() : array + public function getWarnings(): array { return $this->warnings; } diff --git a/src/Validation/RFCValidation.php b/src/Validation/RFCValidation.php index e2c27ba..f5819d8 100644 --- a/src/Validation/RFCValidation.php +++ b/src/Validation/RFCValidation.php @@ -6,6 +6,7 @@ use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\EmailParser; use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\Reason\ExceptionFound; +use Egulias\EmailValidator\Warning\Warning; class RFCValidation implements EmailValidation { @@ -15,16 +16,16 @@ class RFCValidation implements EmailValidation private $parser; /** - * @var array + * @var Warning[] */ - private $warnings = []; + private array $warnings = []; /** * @var ?InvalidEmail */ private $error; - public function isValid(string $email, EmailLexer $emailLexer) : bool + public function isValid(string $email, EmailLexer $emailLexer): bool { $this->parser = new EmailParser($emailLexer); try { @@ -43,12 +44,15 @@ class RFCValidation implements EmailValidation return true; } - public function getError() : ?InvalidEmail + public function getError(): ?InvalidEmail { return $this->error; } - public function getWarnings() : array + /** + * @return Warning[] + */ + public function getWarnings(): array { return $this->warnings; } diff --git a/src/Warning/QuotedPart.php b/src/Warning/QuotedPart.php index afa1f9e..c3e017d 100644 --- a/src/Warning/QuotedPart.php +++ b/src/Warning/QuotedPart.php @@ -7,8 +7,8 @@ class QuotedPart extends Warning public const CODE = 36; /** - * @param scalar $prevToken - * @param scalar $postToken + * @param scalar|null $prevToken + * @param scalar|null $postToken */ public function __construct($prevToken, $postToken) { diff --git a/src/Warning/Warning.php b/src/Warning/Warning.php index 8b39d64..e5b6ad8 100644 --- a/src/Warning/Warning.php +++ b/src/Warning/Warning.php @@ -4,6 +4,9 @@ namespace Egulias\EmailValidator\Warning; abstract class Warning { + /** + * @var int CODE + */ public const CODE = 0; /** @@ -40,8 +43,11 @@ abstract class Warning return $this->rfcNumber; } - public function __toString() + /** + * @return string + */ + public function __toString(): string { - return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE; + return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . strval(static::CODE); } } diff --git a/tests/EmailValidator/EmailLexerTest.php b/tests/EmailValidator/EmailLexerTest.php index a09ebe2..c800e93 100644 --- a/tests/EmailValidator/EmailLexerTest.php +++ b/tests/EmailValidator/EmailLexerTest.php @@ -24,7 +24,7 @@ class EmailLexerTest extends TestCase $lexer->setInput($str); $lexer->moveNext(); $lexer->moveNext(); - $this->assertEquals($token, $lexer->token['type']); + $this->assertEquals($token, $lexer->current->type); } public function testLexerParsesMultipleSpaces() @@ -33,9 +33,9 @@ class EmailLexerTest extends TestCase $lexer->setInput(' '); $lexer->moveNext(); $lexer->moveNext(); - $this->assertEquals(EmailLexer::S_SP, $lexer->token['type']); + $this->assertEquals(EmailLexer::S_SP, $lexer->current->type); $lexer->moveNext(); - $this->assertEquals(EmailLexer::S_SP, $lexer->token['type']); + $this->assertEquals(EmailLexer::S_SP, $lexer->current->type); } /** @@ -48,7 +48,7 @@ class EmailLexerTest extends TestCase $lexer->moveNext(); $lexer->moveNext(); - $this->assertEquals(EmailLexer::INVALID, $lexer->token['type']); + $this->assertEquals(EmailLexer::INVALID, $lexer->current->type); } public function invalidUTF8CharsProvider() @@ -77,18 +77,18 @@ class EmailLexerTest extends TestCase } elseif ($code_point < 0x800) { $hex[0] = 0x1C0 | $code_point >> 6; $hex[1] = 0x80 | $code_point & 0x3F; - $ret = chr($hex[0]).chr($hex[1]); + $ret = chr($hex[0]) . chr($hex[1]); } elseif ($code_point < 0x10000) { $hex[0] = 0xE0 | $code_point >> 12; $hex[1] = 0x80 | $code_point >> 6 & 0x3F; $hex[2] = 0x80 | $code_point & 0x3F; - $ret = chr($hex[0]).chr($hex[1]).chr($hex[2]); + $ret = chr($hex[0]) . chr($hex[1]) . chr($hex[2]); } else { $hex[0] = 0xF0 | $code_point >> 18; $hex[1] = 0x80 | $code_point >> 12 & 0x3F; $hex[2] = 0x80 | $code_point >> 6 & 0x3F; $hex[3] = 0x80 | $code_point & 0x3F; - $ret = chr($hex[0]).chr($hex[1]).chr($hex[2]).chr($hex[3]); + $ret = chr($hex[0]) . chr($hex[1]) . chr($hex[2]) . chr($hex[3]); } return $ret; @@ -101,7 +101,7 @@ class EmailLexerTest extends TestCase $lexer->moveNext(); $lexer->skipUntil(EmailLexer::S_HTAB); $lexer->moveNext(); - $this->assertEquals(EmailLexer::S_HTAB, $lexer->token['type']); + $this->assertEquals(EmailLexer::S_HTAB, $lexer->current->type); } public function testLexerForUTF8() @@ -110,9 +110,9 @@ class EmailLexerTest extends TestCase $lexer->setInput("áÇ@bar.com"); $lexer->moveNext(); $lexer->moveNext(); - $this->assertEquals(EmailLexer::GENERIC, $lexer->token['type']); + $this->assertEquals(EmailLexer::GENERIC, $lexer->current->type); $lexer->moveNext(); - $this->assertEquals(EmailLexer::GENERIC, $lexer->token['type']); + $this->assertEquals(EmailLexer::GENERIC, $lexer->current->type); } public function testLexerSearchToken()