diff --git a/composer.json b/composer.json index d1fd5f125..24256d331 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "deepdiver/zipstreamer": "^v2.0.2", "deepdiver1975/tarstreamer": "^2.1.0", "doctrine/dbal": "^3.7.0", - "egulias/email-validator": "^3.2.6", + "egulias/email-validator": "^4.0.2", "fusonic/opengraph": "^2.3.0", "giggsey/libphonenumber-for-php-lite": "^8.13.12", "guzzlehttp/guzzle": "^7.8.1", diff --git a/composer.lock b/composer.lock index 5b6d1cc08..530b65a46 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dee17b8d020b8d4689b859483251d262", + "content-hash": "56028816e1d278224ea6eda9aefd1b4c", "packages": [ { "name": "aws/aws-crt-php", @@ -763,28 +763,27 @@ }, { "name": "doctrine/lexer", - "version": "2.1.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^5.21" }, "type": "library", "autoload": { @@ -821,7 +820,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" + "source": "https://github.com/doctrine/lexer/tree/3.0.1" }, "funding": [ { @@ -837,30 +836,30 @@ "type": "tidelift" } ], - "time": "2022-12-14T08:49:07+00:00" + "time": "2024-02-05T11:56:58+00:00" }, { "name": "egulias/email-validator", - "version": "3.2.6", + "version": "4.0.2", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7" + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7", - "reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", "shasum": "" }, "require": { - "doctrine/lexer": "^1.2|^2", - "php": ">=7.2", - "symfony/polyfill-intl-idn": "^1.15" + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" }, "require-dev": { - "phpunit/phpunit": "^8.5.8|^9.3.3", - "vimeo/psalm": "^4" + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -868,7 +867,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -896,7 +895,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/3.2.6" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" }, "funding": [ { @@ -904,7 +903,7 @@ "type": "github" } ], - "time": "2023-06-01T07:04:22+00:00" + "time": "2023-10-06T06:47:41+00:00" }, { "name": "fusonic/opengraph", @@ -5079,16 +5078,16 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919", + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919", "shasum": "" }, "require": { @@ -5101,9 +5100,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5146,7 +5142,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0" }, "funding": [ { @@ -5162,7 +5158,7 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:30:37+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-normalizer", @@ -5327,16 +5323,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", "shasum": "" }, "require": { @@ -5344,9 +5340,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5383,7 +5376,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" }, "funding": [ { @@ -5399,7 +5392,7 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php73", diff --git a/composer/installed.json b/composer/installed.json index 2d8458a1e..39382dc64 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -790,31 +790,30 @@ }, { "name": "doctrine/lexer", - "version": "2.1.0", - "version_normalized": "2.1.0.0", + "version": "3.0.1", + "version_normalized": "3.0.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^5.21" }, - "time": "2022-12-14T08:49:07+00:00", + "time": "2024-02-05T11:56:58+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -851,7 +850,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" + "source": "https://github.com/doctrine/lexer/tree/3.0.1" }, "funding": [ { @@ -871,36 +870,36 @@ }, { "name": "egulias/email-validator", - "version": "3.2.6", - "version_normalized": "3.2.6.0", + "version": "4.0.2", + "version_normalized": "4.0.2.0", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7" + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7", - "reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", "shasum": "" }, "require": { - "doctrine/lexer": "^1.2|^2", - "php": ">=7.2", - "symfony/polyfill-intl-idn": "^1.15" + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" }, "require-dev": { - "phpunit/phpunit": "^8.5.8|^9.3.3", - "vimeo/psalm": "^4" + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, - "time": "2023-06-01T07:04:22+00:00", + "time": "2023-10-06T06:47:41+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "installation-source": "dist", @@ -929,7 +928,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/3.2.6" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" }, "funding": [ { @@ -5300,17 +5299,17 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.28.0", - "version_normalized": "1.28.0.0", + "version": "v1.29.0", + "version_normalized": "1.29.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919", + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919", "shasum": "" }, "require": { @@ -5321,12 +5320,9 @@ "suggest": { "ext-intl": "For best performance" }, - "time": "2023-01-26T09:30:37+00:00", + "time": "2024-01-29T20:11:03+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5370,7 +5366,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0" }, "funding": [ { @@ -5557,28 +5553,25 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.28.0", - "version_normalized": "1.28.0.0", + "version": "v1.29.0", + "version_normalized": "1.29.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", "shasum": "" }, "require": { "php": ">=7.1" }, - "time": "2023-01-26T09:26:14+00:00", + "time": "2024-01-29T20:11:03+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5616,7 +5609,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" }, "funding": [ { diff --git a/composer/installed.php b/composer/installed.php index 8c2889d9d..69528c9db 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'nextcloud/3rdparty', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '9cc1b0eca17eac65fbbe9141df52b60320f24d5d', + 'reference' => '945c283afd81531aaf4110bf0eba4add4d33bbc5', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), @@ -110,18 +110,18 @@ 'dev_requirement' => false, ), 'doctrine/lexer' => array( - 'pretty_version' => '2.1.0', - 'version' => '2.1.0.0', - 'reference' => '39ab8fcf5a51ce4b85ca97c7a7d033eb12831124', + 'pretty_version' => '3.0.1', + 'version' => '3.0.1.0', + 'reference' => '31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/lexer', 'aliases' => array(), 'dev_requirement' => false, ), 'egulias/email-validator' => array( - 'pretty_version' => '3.2.6', - 'version' => '3.2.6.0', - 'reference' => 'e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7', + 'pretty_version' => '4.0.2', + 'version' => '4.0.2.0', + 'reference' => 'ebaaf5be6c0286928352e054f2d5125608e5405e', 'type' => 'library', 'install_path' => __DIR__ . '/../egulias/email-validator', 'aliases' => array(), @@ -292,7 +292,7 @@ 'nextcloud/3rdparty' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '9cc1b0eca17eac65fbbe9141df52b60320f24d5d', + 'reference' => '945c283afd81531aaf4110bf0eba4add4d33bbc5', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), @@ -758,9 +758,9 @@ 'dev_requirement' => false, ), 'symfony/polyfill-intl-idn' => array( - 'pretty_version' => 'v1.28.0', - 'version' => '1.28.0.0', - 'reference' => 'ecaafce9f77234a6a449d29e49267ba10499116d', + 'pretty_version' => 'v1.29.0', + 'version' => '1.29.0.0', + 'reference' => 'a287ed7475f85bf6f61890146edbc932c0fff919', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', 'aliases' => array(), @@ -785,9 +785,9 @@ 'dev_requirement' => false, ), 'symfony/polyfill-php72' => array( - 'pretty_version' => 'v1.28.0', - 'version' => '1.28.0.0', - 'reference' => '70f4aebd92afca2f865444d30a4d2151c13c3179', + 'pretty_version' => 'v1.29.0', + 'version' => '1.29.0.0', + 'reference' => '861391a8da9a04cbad2d232ddd9e4893220d6e25', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php72', 'aliases' => array(), diff --git a/doctrine/lexer/src/AbstractLexer.php b/doctrine/lexer/src/AbstractLexer.php index eed4c5139..2436885e4 100644 --- a/doctrine/lexer/src/AbstractLexer.php +++ b/doctrine/lexer/src/AbstractLexer.php @@ -7,7 +7,6 @@ use ReflectionClass; use UnitEnum; -use function get_class; use function implode; use function preg_split; use function sprintf; @@ -27,54 +26,46 @@ abstract class AbstractLexer { /** * Lexer original input string. - * - * @var string */ - private $input; + private string $input; /** * Array of scanned tokens. * * @var list> */ - private $tokens = []; + private array $tokens = []; /** * Current lexer position in input string. - * - * @var int */ - private $position = 0; + private int $position = 0; /** * Current peek of current lexer position. - * - * @var int */ - private $peek = 0; + private int $peek = 0; /** * The next token in the input. * - * @var mixed[]|null - * @psalm-var Token|null + * @var Token|null */ - public $lookahead; + public Token|null $lookahead; /** * The last matched/seen token. * - * @var mixed[]|null - * @psalm-var Token|null + * @var Token|null */ - public $token; + public Token|null $token; /** * Composed regex for input parsing. * - * @var string|null + * @var non-empty-string|null */ - private $regex; + private string|null $regex = null; /** * Sets the input data to be tokenized. @@ -86,7 +77,7 @@ abstract class AbstractLexer * * @return void */ - public function setInput($input) + public function setInput(string $input) { $this->input = $input; $this->tokens = []; @@ -125,7 +116,7 @@ public function resetPeek() * * @return void */ - public function resetPosition($position = 0) + public function resetPosition(int $position = 0) { $this->position = $position; } @@ -133,11 +124,9 @@ public function resetPosition($position = 0) /** * Retrieve the original lexer's input until a given position. * - * @param int $position - * * @return string */ - public function getInputUntilPosition($position) + public function getInputUntilPosition(int $position) { return substr($this->input, 0, $position); } @@ -151,7 +140,7 @@ public function getInputUntilPosition($position) * * @psalm-assert-if-true !=null $this->lookahead */ - public function isNextToken($type) + public function isNextToken(int|string|UnitEnum $type) { return $this->lookahead !== null && $this->lookahead->isA($type); } @@ -194,7 +183,7 @@ public function moveNext() * * @return void */ - public function skipUntil($type) + public function skipUntil(int|string|UnitEnum $type) { while ($this->lookahead !== null && ! $this->lookahead->isA($type)) { $this->moveNext(); @@ -204,12 +193,9 @@ public function skipUntil($type) /** * Checks if given value is identical to the given token. * - * @param string $value - * @param int|string $token - * * @return bool */ - public function isA($value, $token) + public function isA(string $value, int|string|UnitEnum $token) { return $this->getType($value) === $token; } @@ -217,8 +203,7 @@ public function isA($value, $token) /** * Moves the lookahead token forward. * - * @return mixed[]|null The next token or NULL if there are no more tokens ahead. - * @psalm-return Token|null + * @return Token|null The next token or NULL if there are no more tokens ahead. */ public function peek() { @@ -232,8 +217,7 @@ public function peek() /** * Peeks at the next token, returns it and immediately resets the peek. * - * @return mixed[]|null The next token or NULL if there are no more tokens ahead. - * @psalm-return Token|null + * @return Token|null The next token or NULL if there are no more tokens ahead. */ public function glimpse() { @@ -250,14 +234,14 @@ public function glimpse() * * @return void */ - protected function scan($input) + protected function scan(string $input) { if (! isset($this->regex)) { $this->regex = sprintf( '/(%s)|%s/%s', implode(')|(', $this->getCatchablePatterns()), implode('|', $this->getNonCatchablePatterns()), - $this->getModifiers() + $this->getModifiers(), ); } @@ -277,7 +261,7 @@ protected function scan($input) $this->tokens[] = new Token( $firstMatch, $type, - $match[1] + $match[1], ); } } @@ -289,10 +273,10 @@ protected function scan($input) * * @return int|string */ - public function getLiteral($token) + public function getLiteral(int|string|UnitEnum $token) { if ($token instanceof UnitEnum) { - return get_class($token) . '::' . $token->name; + return $token::class . '::' . $token->name; } $className = static::class; @@ -336,11 +320,9 @@ abstract protected function getNonCatchablePatterns(); /** * Retrieve token type. Also processes the token value if necessary. * - * @param string $value - * * @return T|null * * @param-out V $value */ - abstract protected function getType(&$value); + abstract protected function getType(string &$value); } diff --git a/doctrine/lexer/src/Token.php b/doctrine/lexer/src/Token.php index 4fbbf4e40..b6df69465 100644 --- a/doctrine/lexer/src/Token.php +++ b/doctrine/lexer/src/Token.php @@ -4,9 +4,6 @@ namespace Doctrine\Common\Lexer; -use ArrayAccess; -use Doctrine\Deprecations\Deprecation; -use ReturnTypeWillChange; use UnitEnum; use function in_array; @@ -14,9 +11,8 @@ /** * @template T of UnitEnum|string|int * @template V of string|int - * @implements ArrayAccess */ -final class Token implements ArrayAccess +final class Token { /** * The string value of the token in the input string @@ -24,7 +20,7 @@ final class Token implements ArrayAccess * @readonly * @var V */ - public $value; + public string|int $value; /** * The type of the token (identifier, numeric, string, input parameter, none) @@ -38,15 +34,14 @@ final class Token implements ArrayAccess * The position of the token in the input string * * @readonly - * @var int */ - public $position; + public int $position; /** * @param V $value * @param T|null $type */ - public function __construct($value, $type, int $position) + public function __construct(string|int $value, $type, int $position) { $this->value = $value; $this->type = $type; @@ -58,88 +53,4 @@ public function isA(...$types): bool { return in_array($this->type, $types, true); } - - /** - * @deprecated Use the value, type or position property instead - * {@inheritDoc} - */ - public function offsetExists($offset): bool - { - Deprecation::trigger( - 'doctrine/lexer', - 'https://github.com/doctrine/lexer/pull/79', - 'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead', - self::class - ); - - return in_array($offset, ['value', 'type', 'position'], true); - } - - /** - * @deprecated Use the value, type or position property instead - * {@inheritDoc} - * - * @param O $offset - * - * @return mixed - * @psalm-return ( - * O is 'value' - * ? V - * : ( - * O is 'type' - * ? T|null - * : ( - * O is 'position' - * ? int - * : mixed - * ) - * ) - * ) - * - * @template O of array-key - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - Deprecation::trigger( - 'doctrine/lexer', - 'https://github.com/doctrine/lexer/pull/79', - 'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead', - self::class - ); - - return $this->$offset; - } - - /** - * @deprecated no replacement planned - * {@inheritDoc} - */ - public function offsetSet($offset, $value): void - { - Deprecation::trigger( - 'doctrine/lexer', - 'https://github.com/doctrine/lexer/pull/79', - 'Setting %s properties via ArrayAccess is deprecated', - self::class - ); - - $this->$offset = $value; - } - - /** - * @deprecated no replacement planned - * {@inheritDoc} - */ - public function offsetUnset($offset): void - { - Deprecation::trigger( - 'doctrine/lexer', - 'https://github.com/doctrine/lexer/pull/79', - 'Setting %s properties via ArrayAccess is deprecated', - self::class - ); - - $this->$offset = null; - } } diff --git a/egulias/email-validator/LICENSE b/egulias/email-validator/LICENSE index 307440d45..b1902a4e9 100644 --- a/egulias/email-validator/LICENSE +++ b/egulias/email-validator/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2022 Eduardo Gulias Davis +Copyright (c) 2013-2023 Eduardo Gulias Davis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/egulias/email-validator/src/EmailLexer.php b/egulias/email-validator/src/EmailLexer.php index 4099758ce..969c049f8 100644 --- a/egulias/email-validator/src/EmailLexer.php +++ b/egulias/email-validator/src/EmailLexer.php @@ -5,13 +5,11 @@ 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,21 @@ 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 */ - public $lookahead; - - /** @psalm-var array{value:'', type:null, position:0} */ - private static $nullToken = [ - 'value' => '', - 'type' => null, - 'position' => 0, - ]; + private Token $nullToken; /** @var string */ private $accumulator = ''; @@ -176,15 +157,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 +179,7 @@ public function reset() : void * * @psalm-suppress InvalidScalarArgument */ - public function find($type) : bool + public function find($type): bool { $search = clone $this; $search->skipUntil($type); @@ -210,22 +195,23 @@ public function find($type) : bool * * @return boolean */ - public function moveNext() : bool + public function moveNext(): bool { - if ($this->hasToRecord && $this->previous === self::$nullToken) { - $this->accumulator .= ((array) $this->token)['value']; + if ($this->hasToRecord && $this->previous === $this->nullToken) { + $this->accumulator .= $this->current->value; } - $this->previous = (array) $this->token; + $this->previous = $this->current; - if($this->lookahead === null) { - $this->lookahead = self::$nullToken; + if ($this->lookahead === null) { + $this->lookahead = $this->nullToken; } $hasNext = parent::moveNext(); + $this->current = $this->token ?? $this->nullToken; if ($this->hasToRecord) { - $this->accumulator .= ((array) $this->token)['value']; + $this->accumulator .= $this->current->value; } return $hasNext; @@ -238,7 +224,7 @@ public function moveNext() : bool * @throws \InvalidArgumentException * @return integer */ - protected function getType(&$value) + protected function getType(&$value): int { $encoded = $value; @@ -259,31 +245,30 @@ protected function getType(&$value) 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; } @@ -291,9 +276,9 @@ public function hasInvalidTokens() : bool /** * getPrevious * - * @return array + * @return Token */ - public function getPrevious() : array + public function getPrevious(): Token { return $this->previous; } @@ -303,7 +288,7 @@ public function getPrevious() : array * * @return string[] */ - protected function getCatchablePatterns() : array + protected function getCatchablePatterns(): array { return self::CATCHABLE_PATTERNS; } @@ -313,32 +298,32 @@ protected function getCatchablePatterns() : array * * @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 = ''; } diff --git a/egulias/email-validator/src/EmailParser.php b/egulias/email-validator/src/EmailParser.php index 352eae4a0..fc449c76f 100644 --- a/egulias/email-validator/src/EmailParser.php +++ b/egulias/email-validator/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 @@ public function parse(string $str) : Result 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,37 +51,37 @@ protected function parseRightFromAt(): Result return $this->processDomainPart(); } - private function processLocalPart() : Result + private function processLocalPart(): Result { $localPartParser = new LocalPart($this->lexer); $localPartResult = $localPartParser->parse(); $this->localPart = $localPartParser->localPart(); - $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); + $this->warnings = [...$localPartParser->getWarnings(), ...$this->warnings]; 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); - + $this->warnings = [...$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/egulias/email-validator/src/MessageIDParser.php b/egulias/email-validator/src/MessageIDParser.php index b0b6720f8..35bd0a7f1 100644 --- a/egulias/email-validator/src/MessageIDParser.php +++ b/egulias/email-validator/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 @@ public function parse(string $str) : Result 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,37 +52,37 @@ protected function parseRightFromAt(): Result return $this->processIDRight(); } - private function processIDLeft() : Result + private function processIDLeft(): Result { $localPartParser = new IDLeftPart($this->lexer); $localPartResult = $localPartParser->parse(); $this->idLeft = $localPartParser->localPart(); - $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); + $this->warnings = [...$localPartParser->getWarnings(), ...$this->warnings]; 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); - + $this->warnings = [...$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/egulias/email-validator/src/Parser.php b/egulias/email-validator/src/Parser.php index 4e5ac7d1f..d577e3eae 100644 --- a/egulias/email-validator/src/Parser.php +++ b/egulias/email-validator/src/Parser.php @@ -22,9 +22,9 @@ 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) @@ -32,12 +32,12 @@ public function __construct(EmailLexer $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(); @@ -63,16 +63,16 @@ public function parse(string $str) : Result /** * @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 ((array) $this->lexer->token)['type'] !== EmailLexer::S_AT; + return !$this->lexer->current->isA(EmailLexer::S_AT); } } diff --git a/egulias/email-validator/src/Parser/Comment.php b/egulias/email-validator/src/Parser/Comment.php index 34ef97263..7b5b47e29 100644 --- a/egulias/email-validator/src/Parser/Comment.php +++ b/egulias/email-validator/src/Parser/Comment.php @@ -29,70 +29,68 @@ public function __construct(EmailLexer $lexer, CommentStrategy $commentStrategy) $this->commentStrategy = $commentStrategy; } - public function parse() : Result + public function parse(): Result { - if (((array) $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(), ((array) $this->lexer->token)['value']); + if ($this->noClosingParenthesis()) { + return new InvalidEmail(new UnclosedComment(), $this->lexer->current->value); } } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_CLOSEPARENTHESIS) { - return new InvalidEmail(new UnOpenedComment(), ((array) $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(), ((array) $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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new UnOpenedComment(), $this->lexer->current->value); } $finalValidations = $this->commentStrategy->endOfLoopValidations($this->lexer); - $this->warnings = array_merge($this->warnings, $this->commentStrategy->getWarnings()); + $this->warnings = [...$this->warnings, ...$this->commentStrategy->getWarnings()]; return $finalValidations; } /** - * @return bool + * @return void */ - private function warnEscaping() : bool + private function warnEscaping(): void { //Backslash found - if (((array) $this->lexer->token)['type'] !== EmailLexer::S_BACKSLASH) { - return false; + if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { + return; } if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { - return false; + return; } $this->warnings[QuotedPart::CODE] = - new QuotedPart($this->lexer->getPrevious()['type'], ((array) $this->lexer->token)['type']); - return true; - + new QuotedPart($this->lexer->getPrevious()->type, $this->lexer->current->type); } - private function noClosingParenthesis() : bool + private function noClosingParenthesis(): bool { try { $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); diff --git a/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php b/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php index 410032fea..8834db04c 100644 --- a/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php +++ b/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php @@ -4,15 +4,19 @@ 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/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php b/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php index 17b686be1..80d6d104f 100644 --- a/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php +++ b/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php @@ -10,20 +10,16 @@ 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()) { - return false; - } - - return true; + return !($openedParenthesis === 0 && $lexer->isNextToken(EmailLexer::S_DOT)); } - 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'), ((array) $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/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php b/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php index 179802b83..5c18b440b 100644 --- a/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php +++ b/egulias/email-validator/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'), ((array) $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/egulias/email-validator/src/Parser/DomainLiteral.php b/egulias/email-validator/src/Parser/DomainLiteral.php index 10486346a..5093e5083 100644 --- a/egulias/email-validator/src/Parser/DomainLiteral.php +++ b/egulias/email-validator/src/Parser/DomainLiteral.php @@ -1,4 +1,5 @@ addTagWarnings(); @@ -39,14 +40,14 @@ public function parse() : Result $addressLiteral = ''; do { - if (((array) $this->lexer->token)['type'] === EmailLexer::C_NUL) { - return new InvalidEmail(new ExpectingDTEXT(), ((array) $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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value); } if ($this->lexer->isNextTokenAny( @@ -57,22 +58,21 @@ public function parse() : Result } if ($this->lexer->isNextToken(EmailLexer::S_CR)) { - return new InvalidEmail(new CRNoLF(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new CRNoLF(), $this->lexer->current->value); } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_BACKSLASH) { - return new InvalidEmail(new UnusualElements(((array) $this->lexer->token)['value']), ((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_IPV6TAG) { + if ($this->lexer->current->isA(EmailLexer::S_IPV6TAG)) { $IPv6TAG = true; } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_CLOSEBRACKET) { + if ($this->lexer->current->isA(EmailLexer::S_CLOSEBRACKET)) { break; } - $addressLiteral .= ((array) $this->lexer->token)['value']; - + $addressLiteral .= $this->lexer->current->value; } while ($this->lexer->moveNext()); @@ -82,10 +82,10 @@ public function parse() : Result if (!$isAddressLiteralIPv4) { return new ValidEmail(); - } else { - $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral); } + $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral); + if (!$IPv6TAG) { $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral(); return new ValidEmail(); @@ -102,10 +102,10 @@ public function parse() : Result * @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(); } @@ -145,7 +145,7 @@ public function checkIPV6Tag($addressLiteral, $maxGroups = 8) : void } } - 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 @@ public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string * * @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 @@ protected function checkIPV4Tag($addressLiteral) : bool return true; } - private function addObsoleteWarnings() : void + private function addObsoleteWarnings(): void { - if(in_array(((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 @@ private function addTagWarnings() : void } } } - } diff --git a/egulias/email-validator/src/Parser/DomainPart.php b/egulias/email-validator/src/Parser/DomainPart.php index 84a4180f3..a1a56cf3d 100644 --- a/egulias/email-validator/src/Parser/DomainPart.php +++ b/egulias/email-validator/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 @@ public function parse() : Result return $domainChecks; } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_AT) { - return new InvalidEmail(new ConsecutiveAt(), ((array) $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,30 +69,29 @@ public function parse() : Result $length = strlen($this->domainPart); if ($length > self::DOMAIN_MAX_LENGTH) { - return new InvalidEmail(new DomainTooLong(), ((array) $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(), ((array) $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 (((array) $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()) { @@ -104,32 +103,32 @@ private function performDomainStartChecks() : Result return $missingDomain; } - if (((array) $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 = ((array) $this->lexer->token)['type'] === EmailLexer::S_EMPTY || - (((array) $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(), ((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT) { - return new InvalidEmail(new DotAtStart(), ((array) $this->lexer->token)['value']); + if ($this->lexer->current->isA(EmailLexer::S_DOT)) { + return new InvalidEmail(new DotAtStart(), $this->lexer->current->value); } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_HYPHEN) { - return new InvalidEmail(new DomainHyphened('After AT'), ((array) $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(); } @@ -138,12 +137,12 @@ protected function parseComments(): Result { $commentParser = new Comment($this->lexer, new DomainComment()); $result = $commentParser->parse(); - $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); + $this->warnings = [...$this->warnings, ...$commentParser->getWarnings()]; return $result; } - protected function doParseDomainPart() : Result + protected function doParseDomainPart(): Result { $tldMissing = true; $hasComments = false; @@ -151,18 +150,20 @@ protected function doParseDomainPart() : Result do { $prev = $this->lexer->getPrevious(); - $notAllowedChars = $this->checkNotAllowedChars($this->lexer->token); + $notAllowedChars = $this->checkNotAllowedChars($this->lexer->current); if ($notAllowedChars->isInvalid()) { return $notAllowedChars; } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENPARENTHESIS || - ((array) $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 @@ protected function doParseDomainPart() : Result return $dotsResult; } - if (((array) $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 .= ((array) $this->lexer->token)['value']; + $domain .= $this->lexer->current->value; - if (((array) $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 @@ protected function doParseDomainPart() : Result return $exceptionsResult; } $this->lexer->moveNext(); - - } while (null !== ((array) $this->lexer->token)['type']); + } while (!$this->lexer->current->isA(EmailLexer::S_EMPTY)); $labelCheck = $this->checkLabelLength(true); if ($labelCheck->isInvalid()) { @@ -213,14 +213,16 @@ protected function doParseDomainPart() : Result 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[((array) $token)['type']])) { - return new InvalidEmail(new CharNotAllowed(), ((array) $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,39 +230,47 @@ private function checkNotAllowedChars($token) : Result /** * @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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new ExpectingDomainLiteralClose(), $this->lexer->current->value); } $domainLiteralParser = new DomainLiteralParser($this->lexer); $result = $domainLiteralParser->parse(); - $this->warnings = array_merge($this->warnings, $domainLiteralParser->getWarnings()); + $this->warnings = [...$this->warnings, ...$domainLiteralParser->getWarnings()]; 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 (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENBRACKET && $prev['type'] !== EmailLexer::S_AT) { - return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), ((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), ((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_BACKSLASH - && $this->lexer->isNextToken(EmailLexer::GENERIC)) { - return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), ((array) $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 @@ protected function validateTokens(bool $hasComments) : Result $validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true; } - if (!isset($validDomainTokens[((array) $this->lexer->token)['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . ((array) $this->lexer->token)['value']), ((array) $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 (((array) $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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new LabelTooLong(), $this->lexer->current->value); } $this->label = ''; } - $this->label .= ((array) $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,14 +312,14 @@ private function isLabelTooLong(string $label) : bool 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; } diff --git a/egulias/email-validator/src/Parser/DoubleQuote.php b/egulias/email-validator/src/Parser/DoubleQuote.php index d722292d4..b5335d300 100644 --- a/egulias/email-validator/src/Parser/DoubleQuote.php +++ b/egulias/email-validator/src/Parser/DoubleQuote.php @@ -1,4 +1,5 @@ checkDQUOTE(); - if($validQuotedString->isInvalid()) return $validQuotedString; + if ($validQuotedString->isInvalid()) { + return $validQuotedString; + } $special = [ EmailLexer::S_CR => true, @@ -35,53 +38,54 @@ public function parse() : Result $this->lexer->moveNext(); - while (((array) $this->lexer->token)['type'] !== EmailLexer::S_DQUOTE && null !== ((array) $this->lexer->token)['type']) { - if (isset($special[((array) $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 (((array) $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[((array) $this->lexer->token)['type']])) { - return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), ((array) $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"), ((array) $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), ((array) $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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->current->value); } - $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], ((array) $this->lexer->token)['value']); + $this->warnings[QuotedString::CODE] = new QuotedString($previous->value, $this->lexer->current->value); return new ValidEmail(); } - } diff --git a/egulias/email-validator/src/Parser/FoldingWhiteSpace.php b/egulias/email-validator/src/Parser/FoldingWhiteSpace.php index be4b05b82..348a7af44 100644 --- a/egulias/email-validator/src/Parser/FoldingWhiteSpace.php +++ b/egulias/email-validator/src/Parser/FoldingWhiteSpace.php @@ -1,4 +1,5 @@ isFWS()) { return new ValidEmail(); @@ -36,19 +37,19 @@ public function parse() : Result return $resultCRLF; } - if (((array) $this->lexer->token)['type'] === EmailLexer::S_CR) { - return new InvalidEmail(new CRNoLF(), ((array) $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(), ((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_LF || ((array) $this->lexer->token)['type'] === EmailLexer::C_NUL) { - return new InvalidEmail(new ExpectingCTEXT(), ((array) $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 @@ public function parse() : Result return new ValidEmail(); } - protected function checkCRLFInFWS() : Result + protected function checkCRLFInFWS(): Result { - if (((array) $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(), ((array) $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(), ((array) $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(((array) $this->lexer->token)['type'], self::FWS_TYPES); + return in_array($this->lexer->current->type, self::FWS_TYPES); } } diff --git a/egulias/email-validator/src/Parser/IDLeftPart.php b/egulias/email-validator/src/Parser/IDLeftPart.php index 3b01ae290..bedcf7b20 100644 --- a/egulias/email-validator/src/Parser/IDLeftPart.php +++ b/egulias/email-validator/src/Parser/IDLeftPart.php @@ -10,6 +10,6 @@ class IDLeftPart extends LocalPart { protected function parseComments(): Result { - return new InvalidEmail(new CommentsInIDRight(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new CommentsInIDRight(), $this->lexer->current->value); } } diff --git a/egulias/email-validator/src/Parser/IDRightPart.php b/egulias/email-validator/src/Parser/IDRightPart.php index d19e05ab6..d2fc1d748 100644 --- a/egulias/email-validator/src/Parser/IDRightPart.php +++ b/egulias/email-validator/src/Parser/IDRightPart.php @@ -10,7 +10,7 @@ class IDRightPart extends DomainPart { - protected function validateTokens(bool $hasComments) : Result + protected function validateTokens(bool $hasComments): Result { $invalidDomainTokens = [ EmailLexer::S_DQUOTE => true, @@ -21,8 +21,8 @@ protected function validateTokens(bool $hasComments) : Result EmailLexer::S_LOWERTHAN => true, ]; - if (isset($invalidDomainTokens[((array) $this->lexer->token)['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . ((array) $this->lexer->token)['value']), ((array) $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/egulias/email-validator/src/Parser/LocalPart.php b/egulias/email-validator/src/Parser/LocalPart.php index 3f2ef7d8e..5ed29d606 100644 --- a/egulias/email-validator/src/Parser/LocalPart.php +++ b/egulias/email-validator/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 (((array) $this->lexer->token)['type'] !== EmailLexer::S_AT && null !== ((array) $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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new DotAtStart(), $this->lexer->current->value); } - if (((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENPARENTHESIS || - ((array) $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 (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new ConsecutiveDot(), ((array) $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 (((array) $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(), ((array) $this->lexer->token)['value']); + return new InvalidEmail(new DotAtEnd(), $this->lexer->current->value); } $resultEscaping = $this->validateEscaping(); @@ -81,7 +84,7 @@ public function parse() : Result } $resultFWS = $this->parseLocalFWS(); - if($resultFWS->isInvalid()) { + if ($resultFWS->isInvalid()) { return $resultFWS; } @@ -97,39 +100,39 @@ public function parse() : Result return new ValidEmail(); } - protected function validateTokens(bool $hasComments) : Result + protected function validateTokens(bool $hasComments): Result { - if (isset(self::INVALID_TOKENS[((array) $this->lexer->token)['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token found'), ((array) $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(); if ($resultFWS->isValid()) { - $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings()); + $this->warnings = [...$this->warnings, ...$foldingWS->getWarnings()]; } return $resultFWS; } - private function hasDotAtStart() : bool + private function hasDotAtStart(): bool { - return ((array) $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(); - $this->warnings = array_merge($this->warnings, $dquoteParser->getWarnings()); + $this->warnings = [...$this->warnings, ...$dquoteParser->getWarnings()]; return $parseAgain; } @@ -138,26 +141,20 @@ protected function parseComments(): Result { $commentParser = new Comment($this->lexer, new LocalComment()); $result = $commentParser->parse(); - $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); - if($result->isInvalid()) { - return $result; - } + $this->warnings = [...$this->warnings, ...$commentParser->getWarnings()]; + return $result; } - private function validateEscaping() : Result + private function validateEscaping(): Result { //Backslash found - if (((array) $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'), ((array) $this->lexer->token)['value']); - } - - if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { - return new ValidEmail(); + return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->current->value); } return new ValidEmail(); diff --git a/egulias/email-validator/src/Parser/PartParser.php b/egulias/email-validator/src/Parser/PartParser.php index 7fc6d7bf3..53afb2575 100644 --- a/egulias/email-validator/src/Parser/PartParser.php +++ b/egulias/email-validator/src/Parser/PartParser.php @@ -7,11 +7,12 @@ 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,39 +26,38 @@ public function __construct(EmailLexer $lexer) $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(); - $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings()); + $this->warnings = [...$this->warnings, ...$foldingWS->getWarnings()]; return $resultFWS; } - protected function checkConsecutiveDots() : Result + protected function checkConsecutiveDots(): Result { - if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { - return new InvalidEmail(new ConsecutiveDot(), ((array) $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 - && - ((array) $this->lexer->token)['type'] !== EmailLexer::GENERIC; + return $previous->isA(EmailLexer::S_BACKSLASH) + && !$this->lexer->current->isA(EmailLexer::GENERIC); } } diff --git a/egulias/email-validator/src/Result/InvalidEmail.php b/egulias/email-validator/src/Result/InvalidEmail.php index 180f4d890..82699acc6 100644 --- a/egulias/email-validator/src/Result/InvalidEmail.php +++ b/egulias/email-validator/src/Result/InvalidEmail.php @@ -6,11 +6,15 @@ 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 @@ public function code(): int return $this->reason->code(); } - public function reason() : Reason + public function reason(): Reason { return $this->reason; } - } diff --git a/egulias/email-validator/src/Result/Reason/UnusualElements.php b/egulias/email-validator/src/Result/Reason/UnusualElements.php index 861f3bcb8..18b6e6e1c 100644 --- a/egulias/email-validator/src/Result/Reason/UnusualElements.php +++ b/egulias/email-validator/src/Result/Reason/UnusualElements.php @@ -7,7 +7,7 @@ class UnusualElements implements Reason /** * @var string $element */ - private $element = ''; + private $element; public function __construct(string $element) { diff --git a/egulias/email-validator/src/Validation/DNSCheckValidation.php b/egulias/email-validator/src/Validation/DNSCheckValidation.php index 4882b8044..469e87dca 100644 --- a/egulias/email-validator/src/Validation/DNSCheckValidation.php +++ b/egulias/email-validator/src/Validation/DNSCheckValidation.php @@ -9,17 +9,16 @@ 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 { - /** - * @var int - */ - protected const DNS_RECORD_TYPES_TO_CHECK = DNS_MX + DNS_A + DNS_AAAA; /** * 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 +38,9 @@ class DNSCheckValidation implements EmailValidation 'home', 'lan', ]; - + /** - * @var array + * @var Warning[] */ private $warnings = []; @@ -73,7 +72,7 @@ public function __construct(?DNSGetRecordWrapper $dnsGetRecord = null) $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 +97,15 @@ public function isValid(string $email, EmailLexer $emailLexer) : bool 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; } @@ -117,9 +119,20 @@ protected function checkDns($host) { $variant = INTL_IDNA_VARIANT_UTS46; - $host = rtrim(idn_to_ascii($host, IDNA_DEFAULT, $variant), '.') . '.'; + $host = rtrim(idn_to_ascii($host, IDNA_DEFAULT, $variant), '.'); + + $hostParts = explode('.', $host); + $host = array_pop($hostParts); - return $this->validateDnsRecords($host); + while (count($hostParts) > 0) { + $host = array_pop($hostParts) . '.' . $host; + + if ($this->validateDnsRecords($host)) { + return true; + } + } + + return false; } @@ -130,9 +143,9 @@ protected function checkDns($host) * * @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); + $dnsRecordsResult = $this->dnsGetRecord->getRecords($host, DNS_A + DNS_MX); if ($dnsRecordsResult->withError()) { $this->error = new InvalidEmail(new UnableToGetDNSRecord(), ''); @@ -141,6 +154,13 @@ private function validateDnsRecords($host) : bool $dnsRecords = $dnsRecordsResult->getRecords(); + // Combined check for A+MX+AAAA can fail with SERVFAIL, even in the presence of valid A/MX records + $aaaaRecordsResult = $this->dnsGetRecord->getRecords($host, DNS_AAAA); + + if (! $aaaaRecordsResult->withError()) { + $dnsRecords = array_merge($dnsRecords, $aaaaRecordsResult->getRecords()); + } + // No MX, A or AAAA DNS records if ($dnsRecords === []) { $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); @@ -167,7 +187,7 @@ private function validateDnsRecords($host) : bool * * @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/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php b/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php index f493c5746..25e2fa06c 100644 --- a/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php +++ b/egulias/email-validator/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/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php b/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php index 4972dbcef..463cafd49 100644 --- a/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php +++ b/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php @@ -37,9 +37,6 @@ public function isValid(string $email, EmailLexer $emailLexer) : bool return $this->error === null; } - /** - * @return InvalidEmail - */ public function getError() : ?InvalidEmail { return $this->error; diff --git a/egulias/email-validator/src/Validation/MessageIDValidation.php b/egulias/email-validator/src/Validation/MessageIDValidation.php index 0e020433d..97d1ea7a7 100644 --- a/egulias/email-validator/src/Validation/MessageIDValidation.php +++ b/egulias/email-validator/src/Validation/MessageIDValidation.php @@ -6,12 +6,13 @@ 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 @@ public function isValid(string $email, EmailLexer $emailLexer): bool return true; } + /** + * @return Warning[] + */ public function getWarnings(): array { return $this->warnings; diff --git a/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php b/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php index abafe752a..c908053f3 100644 --- a/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php +++ b/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php @@ -6,6 +6,7 @@ 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 { @@ -22,12 +23,7 @@ class MultipleValidationWithAnd implements EmailValidation public const ALLOW_ALL_ERRORS = 1; /** - * @var EmailValidation[] - */ - private $validations = []; - - /** - * @var array + * @var Warning[] */ private $warnings = []; @@ -36,36 +32,28 @@ class MultipleValidationWithAnd implements EmailValidation */ private $error; - /** - * @var int - */ - private $mode; - /** * @param EmailValidation[] $validations The validations. * @param int $mode The validation mode (one of the constants). */ - public function __construct(array $validations, $mode = self::ALLOW_ALL_ERRORS) + public function __construct(private readonly array $validations, private readonly int $mode = self::ALLOW_ALL_ERRORS) { if (count($validations) == 0) { throw new EmptyValidationList(); } - - $this->validations = $validations; - $this->mode = $mode; } /** * {@inheritdoc} */ - public function isValid(string $email, EmailLexer $emailLexer) : bool + public function isValid(string $email, EmailLexer $emailLexer): bool { $result = true; foreach ($this->validations as $validation) { $emailLexer->reset(); $validationResult = $validation->isValid($email, $emailLexer); $result = $result && $validationResult; - $this->warnings = array_merge($this->warnings, $validation->getWarnings()); + $this->warnings = [...$this->warnings, ...$validation->getWarnings()]; if (!$validationResult) { $this->processError($validation); } @@ -78,14 +66,14 @@ public function isValid(string $email, EmailLexer $emailLexer) : bool 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 +82,7 @@ private function processError(EmailValidation $validation) : void } } - private function shouldStop(bool $result) : bool + private function shouldStop(bool $result): bool { return !$result && $this->mode === self::STOP_ON_ERROR; } @@ -102,15 +90,15 @@ private function shouldStop(bool $result) : bool /** * 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/egulias/email-validator/src/Validation/RFCValidation.php b/egulias/email-validator/src/Validation/RFCValidation.php index e2c27bacc..f59cbfc80 100644 --- a/egulias/email-validator/src/Validation/RFCValidation.php +++ b/egulias/email-validator/src/Validation/RFCValidation.php @@ -6,30 +6,26 @@ use Egulias\EmailValidator\EmailParser; use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\Reason\ExceptionFound; +use Egulias\EmailValidator\Warning\Warning; class RFCValidation implements EmailValidation { /** - * @var EmailParser|null + * @var Warning[] */ - private $parser; - - /** - * @var array - */ - 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); + $parser = new EmailParser($emailLexer); try { - $result = $this->parser->parse($email); - $this->warnings = $this->parser->getWarnings(); + $result = $parser->parse($email); + $this->warnings = $parser->getWarnings(); if ($result->isInvalid()) { /** @psalm-suppress PropertyTypeCoercion */ $this->error = $result; @@ -43,12 +39,15 @@ public function isValid(string $email, EmailLexer $emailLexer) : bool 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/egulias/email-validator/src/Warning/QuotedPart.php b/egulias/email-validator/src/Warning/QuotedPart.php index afa1f9ea2..c3e017d94 100644 --- a/egulias/email-validator/src/Warning/QuotedPart.php +++ b/egulias/email-validator/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/egulias/email-validator/src/Warning/Warning.php b/egulias/email-validator/src/Warning/Warning.php index 8b39d6448..7adb3b85c 100644 --- a/egulias/email-validator/src/Warning/Warning.php +++ b/egulias/email-validator/src/Warning/Warning.php @@ -4,6 +4,9 @@ abstract class Warning { + /** + * @var int CODE + */ public const CODE = 0; /** @@ -40,7 +43,10 @@ public function RFCNumber() return $this->rfcNumber; } - public function __toString() + /** + * @return string + */ + public function __toString(): string { return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE; }