package and depencies
This commit is contained in:
		
							
								
								
									
										33
									
								
								vendor/egulias/email-validator/CHANGELOG.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/egulias/email-validator/CHANGELOG.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| # EmailValidator v3 Changelog | ||||
|  | ||||
| ## New Features | ||||
|  | ||||
| * Access to local part and domain part from EmailParser | ||||
| * Validations outside of the scope of the RFC will be considered "extra" validations, thus opening the door for adding new; will live in their own folder "extra" (as requested in #248, #195, #183).  | ||||
|  | ||||
| ## Breaking changes | ||||
|  | ||||
| * PHP version upgraded to match Symfony's (as of 12/2020). | ||||
| * DNSCheckValidation now fails for missing MX records. While the RFC argues that the existence of only A records to be valid, starting in v3 they will be considered invalid. | ||||
| * Emails domain part are now intenteded to be RFC 1035 compliant, rendering previous valid emails (e.g example@examp&) invalid. | ||||
|  | ||||
| ## PHP versions upgrade policy | ||||
| PHP version upgrade requirement will happen via MINOR (3.x) version upgrades of the library, following the adoption level by major frameworks. | ||||
|  | ||||
| ## Changes | ||||
| * #235 | ||||
| * #215 | ||||
| * #130 | ||||
| * #258 | ||||
| * #188 | ||||
| * #181 | ||||
| * #217 | ||||
| * #214 | ||||
| * #249 | ||||
| * #236 | ||||
| * #257 | ||||
| * #210 | ||||
|  | ||||
| ## Thanks | ||||
| To contributors, be it with PRs, reporting issues or supporting otherwise. | ||||
|  | ||||
							
								
								
									
										153
									
								
								vendor/egulias/email-validator/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								vendor/egulias/email-validator/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| # Contributing | ||||
|  | ||||
| When contributing to this repository make sure to follow the Pull request process below. | ||||
| Reduce to the minimum 3rd party dependencies. | ||||
|  | ||||
| Please note we have a [code of conduct](#Code of Conduct), please follow it in all your interactions with the project. | ||||
|  | ||||
| ## Pull Request Process | ||||
|  | ||||
| When doing a PR to v2 remember that you also have to do the PR port to v3, or tests confirming the bug is not reproducible. | ||||
|  | ||||
| 1. Supported version is v3. If you are fixing a bug in v2, please port to v3 | ||||
| 2. Use the title as a brief description of the changes | ||||
| 3. Describe the changes you are proposing | ||||
|     1. If adding an extra validation state the benefits of adding it and the problem is solving | ||||
|     2. Document in the readme, by adding it to the list | ||||
| 4. Provide appropriate tests for the code you are submitting: aim to keep the existing coverage percentage. | ||||
| 5. Add your Twitter handle (if you have) so we can thank you there. | ||||
|  | ||||
| ## License | ||||
| By contributing, you agree that your contributions will be licensed under its MIT License. | ||||
|  | ||||
| ## Code of Conduct | ||||
|  | ||||
| ### Our Pledge | ||||
|  | ||||
| We as members, contributors, and leaders pledge to make participation in our | ||||
| community a harassment-free experience for everyone, regardless of age, body | ||||
| size, visible or invisible disability, ethnicity, sex characteristics, gender | ||||
| identity and expression, level of experience, education, socio-economic status, | ||||
| nationality, personal appearance, race, religion, or sexual identity | ||||
| and orientation. | ||||
|  | ||||
| We pledge to act and interact in ways that contribute to an open, welcoming, | ||||
| diverse, inclusive, and healthy community. | ||||
|  | ||||
| ### Our Standards | ||||
|  | ||||
| Examples of behavior that contributes to a positive environment for our | ||||
| community include: | ||||
|  | ||||
| * Demonstrating empathy and kindness toward other people | ||||
| * Being respectful of differing opinions, viewpoints, and experiences | ||||
| * Giving and gracefully accepting constructive feedback | ||||
| * Accepting responsibility and apologizing to those affected by our mistakes, | ||||
|   and learning from the experience | ||||
| * Focusing on what is best not just for us as individuals, but for the | ||||
|   overall community | ||||
|  | ||||
| Examples of unacceptable behavior include: | ||||
|  | ||||
| * The use of sexualized language or imagery, and sexual attention or | ||||
|   advances of any kind | ||||
| * Trolling, insulting or derogatory comments, and personal or political attacks | ||||
| * Public or private harassment | ||||
| * Publishing others' private information, such as a physical or email | ||||
|   address, without their explicit permission | ||||
| * Other conduct which could reasonably be considered inappropriate in a | ||||
|   professional setting | ||||
|  | ||||
| ### Enforcement Responsibilities | ||||
|  | ||||
| Community leaders are responsible for clarifying and enforcing our standards of | ||||
| acceptable behavior and will take appropriate and fair corrective action in | ||||
| response to any behavior that they deem inappropriate, threatening, offensive, | ||||
| or harmful. | ||||
|  | ||||
| Community leaders have the right and responsibility to remove, edit, or reject | ||||
| comments, commits, code, wiki edits, issues, and other contributions that are | ||||
| not aligned to this Code of Conduct, and will communicate reasons for moderation | ||||
| decisions when appropriate. | ||||
|  | ||||
| ### Scope | ||||
|  | ||||
| This Code of Conduct applies within all community spaces, and also applies when | ||||
| an individual is officially representing the community in public spaces. | ||||
| Examples of representing our community include using an official e-mail address, | ||||
| posting via an official social media account, or acting as an appointed | ||||
| representative at an online or offline event. | ||||
|  | ||||
| ### Enforcement | ||||
|  | ||||
| Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||||
| reported to the community leaders responsible for enforcement at <emailvalidatorrfc.ccreport@gmail.com>. | ||||
| All complaints will be reviewed and investigated promptly and fairly. | ||||
|  | ||||
| All community leaders are obligated to respect the privacy and security of the | ||||
| reporter of any incident. | ||||
|  | ||||
| #### Enforcement Guidelines | ||||
|  | ||||
| Community leaders will follow these Community Impact Guidelines in determining | ||||
| the consequences for any action they deem in violation of this Code of Conduct: | ||||
|  | ||||
| #### 1. Correction | ||||
|  | ||||
| **Community Impact**: Use of inappropriate language or other behavior deemed | ||||
| unprofessional or unwelcome in the community. | ||||
|  | ||||
| **Consequence**: A private, written warning from community leaders, providing | ||||
| clarity around the nature of the violation and an explanation of why the | ||||
| behavior was inappropriate. A public apology may be requested. | ||||
|  | ||||
| #### 2. Warning | ||||
|  | ||||
| **Community Impact**: A violation through a single incident or series | ||||
| of actions. | ||||
|  | ||||
| **Consequence**: A warning with consequences for continued behavior. No | ||||
| interaction with the people involved, including unsolicited interaction with | ||||
| those enforcing the Code of Conduct, for a specified period of time. This | ||||
| includes avoiding interactions in community spaces as well as external channels | ||||
| like social media. Violating these terms may lead to a temporary or | ||||
| permanent ban. | ||||
|  | ||||
| #### 3. Temporary Ban | ||||
|  | ||||
| **Community Impact**: A serious violation of community standards, including | ||||
| sustained inappropriate behavior. | ||||
|  | ||||
| **Consequence**: A temporary ban from any sort of interaction or public | ||||
| communication with the community for a specified period of time. No public or | ||||
| private interaction with the people involved, including unsolicited interaction | ||||
| with those enforcing the Code of Conduct, is allowed during this period. | ||||
| Violating these terms may lead to a permanent ban. | ||||
|  | ||||
| #### 4. Permanent Ban | ||||
|  | ||||
| **Community Impact**: Demonstrating a pattern of violation of community | ||||
| standards, including sustained inappropriate behavior,  harassment of an | ||||
| individual, or aggression toward or disparagement of classes of individuals. | ||||
|  | ||||
| **Consequence**: A permanent ban from any sort of public interaction within | ||||
| the community. | ||||
|  | ||||
| ### Attribution | ||||
|  | ||||
| This Code of Conduct is adapted from the [Contributor Covenant][homepage], | ||||
| version 2.0, available at | ||||
| [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. | ||||
|  | ||||
| Community Impact Guidelines were inspired by | ||||
| [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. | ||||
|  | ||||
| For answers to common questions about this code of conduct, see the FAQ at | ||||
| [https://www.contributor-covenant.org/faq][FAQ]. Translations are available | ||||
| at [https://www.contributor-covenant.org/translations][translations]. | ||||
|  | ||||
| [homepage]: https://www.contributor-covenant.org | ||||
| [v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html | ||||
| [Mozilla CoC]: https://github.com/mozilla/diversity | ||||
| [FAQ]: https://www.contributor-covenant.org/faq | ||||
| [translations]: https://www.contributor-covenant.org/translations | ||||
							
								
								
									
										2
									
								
								vendor/egulias/email-validator/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/egulias/email-validator/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| Copyright (c) 2013-2016 Eduardo Gulias Davis | ||||
| Copyright (c) 2013-2022 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 | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/egulias/email-validator/composer.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/egulias/email-validator/composer.json
									
									
									
									
										vendored
									
									
								
							| @@ -9,18 +9,17 @@ | ||||
|   ], | ||||
|   "extra": { | ||||
|     "branch-alias": { | ||||
|       "dev-master": "2.1.x-dev" | ||||
|       "dev-master": "3.0.x-dev" | ||||
|     } | ||||
|   }, | ||||
|   "require": { | ||||
|     "php": ">=5.5", | ||||
|     "doctrine/lexer": "^1.0.1", | ||||
|     "symfony/polyfill-intl-idn": "^1.10" | ||||
|     "php": ">=7.2", | ||||
|     "doctrine/lexer": "^1.2|^2", | ||||
|     "symfony/polyfill-intl-idn": "^1.15" | ||||
|   }, | ||||
|   "require-dev": { | ||||
|     "dominicsayers/isemail": "^3.0.7", | ||||
|     "phpunit/phpunit": "^4.8.36|^7.5.15", | ||||
|     "satooshi/php-coveralls": "^1.0.1" | ||||
|     "phpunit/phpunit": "^8.5.8|^9.3.3", | ||||
|     "vimeo/psalm": "^4" | ||||
|   }, | ||||
|   "suggest": { | ||||
|     "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" | ||||
|   | ||||
							
								
								
									
										334
									
								
								vendor/egulias/email-validator/src/EmailLexer.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										334
									
								
								vendor/egulias/email-validator/src/EmailLexer.php
									
									
									
									
										vendored
									
									
								
							| @@ -3,50 +3,71 @@ | ||||
| namespace Egulias\EmailValidator; | ||||
|  | ||||
| use Doctrine\Common\Lexer\AbstractLexer; | ||||
| use Doctrine\Common\Lexer\Token; | ||||
|  | ||||
| /** | ||||
|  * @extends AbstractLexer<int, string> | ||||
|  */ | ||||
| class EmailLexer extends AbstractLexer | ||||
| { | ||||
|     //ASCII values | ||||
|     const C_DEL              = 127; | ||||
|     const C_NUL              = 0; | ||||
|     const S_AT               = 64; | ||||
|     const S_BACKSLASH        = 92; | ||||
|     const S_DOT              = 46; | ||||
|     const S_DQUOTE           = 34; | ||||
|     const S_SQUOTE           = 39; | ||||
|     const S_BACKTICK         = 96; | ||||
|     const S_OPENPARENTHESIS  = 49; | ||||
|     const S_CLOSEPARENTHESIS = 261; | ||||
|     const S_OPENBRACKET      = 262; | ||||
|     const S_CLOSEBRACKET     = 263; | ||||
|     const S_HYPHEN           = 264; | ||||
|     const S_COLON            = 265; | ||||
|     const S_DOUBLECOLON      = 266; | ||||
|     const S_SP               = 267; | ||||
|     const S_HTAB             = 268; | ||||
|     const S_CR               = 269; | ||||
|     const S_LF               = 270; | ||||
|     const S_IPV6TAG          = 271; | ||||
|     const S_LOWERTHAN        = 272; | ||||
|     const S_GREATERTHAN      = 273; | ||||
|     const S_COMMA            = 274; | ||||
|     const S_SEMICOLON        = 275; | ||||
|     const S_OPENQBRACKET     = 276; | ||||
|     const S_CLOSEQBRACKET    = 277; | ||||
|     const S_SLASH            = 278; | ||||
|     const S_EMPTY            = null; | ||||
|     const GENERIC            = 300; | ||||
|     const CRLF               = 301; | ||||
|     const INVALID            = 302; | ||||
|     const ASCII_INVALID_FROM = 127; | ||||
|     const ASCII_INVALID_TO   = 199; | ||||
|     public const S_EMPTY            = null; | ||||
|     public const C_NUL              = 0; | ||||
|     public const S_HTAB             = 9; | ||||
|     public const S_LF               = 10; | ||||
|     public const S_CR               = 13; | ||||
|     public const S_SP               = 32; | ||||
|     public const EXCLAMATION        = 33; | ||||
|     public const S_DQUOTE           = 34; | ||||
|     public const NUMBER_SIGN        = 35; | ||||
|     public const DOLLAR             = 36; | ||||
|     public const PERCENTAGE         = 37; | ||||
|     public const AMPERSAND          = 38; | ||||
|     public const S_SQUOTE           = 39; | ||||
|     public const S_OPENPARENTHESIS  = 40; | ||||
|     public const S_CLOSEPARENTHESIS = 41; | ||||
|     public const ASTERISK           = 42; | ||||
|     public const S_PLUS             = 43; | ||||
|     public const S_COMMA            = 44; | ||||
|     public const S_HYPHEN           = 45; | ||||
|     public const S_DOT              = 46; | ||||
|     public const S_SLASH            = 47; | ||||
|     public const S_COLON            = 58; | ||||
|     public const S_SEMICOLON        = 59; | ||||
|     public const S_LOWERTHAN        = 60; | ||||
|     public const S_EQUAL            = 61; | ||||
|     public const S_GREATERTHAN      = 62; | ||||
|     public const QUESTIONMARK       = 63; | ||||
|     public const S_AT               = 64; | ||||
|     public const S_OPENBRACKET      = 91; | ||||
|     public const S_BACKSLASH        = 92; | ||||
|     public const S_CLOSEBRACKET     = 93; | ||||
|     public const CARET              = 94; | ||||
|     public const S_UNDERSCORE       = 95; | ||||
|     public const S_BACKTICK         = 96; | ||||
|     public const S_OPENCURLYBRACES  = 123; | ||||
|     public const S_PIPE             = 124; | ||||
|     public const S_CLOSECURLYBRACES = 125; | ||||
|     public const S_TILDE            = 126; | ||||
|     public const C_DEL              = 127; | ||||
|     public const INVERT_QUESTIONMARK= 168; | ||||
|     public const INVERT_EXCLAMATION = 173; | ||||
|     public const GENERIC            = 300; | ||||
|     public const S_IPV6TAG          = 301; | ||||
|     public const INVALID            = 302; | ||||
|     public const CRLF               = 1310; | ||||
|     public const S_DOUBLECOLON      = 5858; | ||||
|     public const ASCII_INVALID_FROM = 127; | ||||
|     public const ASCII_INVALID_TO   = 199; | ||||
|  | ||||
|     /** | ||||
|      * US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3) | ||||
|      * | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $charValue = array( | ||||
|     protected $charValue = [ | ||||
|         '{'    => self::S_OPENCURLYBRACES, | ||||
|         '}'    => self::S_CLOSECURLYBRACES, | ||||
|         '('    => self::S_OPENPARENTHESIS, | ||||
|         ')'    => self::S_CLOSEPARENTHESIS, | ||||
|         '<'    => self::S_LOWERTHAN, | ||||
| @@ -71,15 +92,46 @@ class EmailLexer extends AbstractLexer | ||||
|         "\n"   => self::S_LF, | ||||
|         "\r\n" => self::CRLF, | ||||
|         'IPv6' => self::S_IPV6TAG, | ||||
|         '{'    => self::S_OPENQBRACKET, | ||||
|         '}'    => self::S_CLOSEQBRACKET, | ||||
|         ''     => self::S_EMPTY, | ||||
|         '\0'   => self::C_NUL, | ||||
|     ); | ||||
|         '*'    => self::ASTERISK, | ||||
|         '!'    => self::EXCLAMATION, | ||||
|         '&'    => self::AMPERSAND, | ||||
|         '^'    => self::CARET, | ||||
|         '$'    => self::DOLLAR, | ||||
|         '%'    => self::PERCENTAGE, | ||||
|         '~'    => self::S_TILDE, | ||||
|         '|'    => self::S_PIPE, | ||||
|         '_'    => self::S_UNDERSCORE, | ||||
|         '='    => self::S_EQUAL, | ||||
|         '+'    => self::S_PLUS, | ||||
|         '¿'    => self::INVERT_QUESTIONMARK, | ||||
|         '?'    => self::QUESTIONMARK, | ||||
|         '#'    => self::NUMBER_SIGN, | ||||
|         '¡'    => self::INVERT_EXCLAMATION, | ||||
|     ]; | ||||
|  | ||||
|     /** | ||||
|      * @var bool | ||||
|      */ | ||||
|     public const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu"; | ||||
|  | ||||
|     public const VALID_UTF8_REGEX = '/\p{Cc}+/u'; | ||||
|  | ||||
|     public const CATCHABLE_PATTERNS = [ | ||||
|         '[a-zA-Z]+[46]?', //ASCII and domain literal | ||||
|         '[^\x00-\x7F]',  //UTF-8 | ||||
|         '[0-9]+', | ||||
|         '\r\n', | ||||
|         '::', | ||||
|         '\s+?', | ||||
|         '.', | ||||
|     ]; | ||||
|  | ||||
|     public const NON_CATCHABLE_PATTERNS = [ | ||||
|         '[\xA0-\xff]+', | ||||
|     ]; | ||||
|  | ||||
|     public const MODIFIERS = 'iu'; | ||||
|  | ||||
|     /** @var bool */ | ||||
|     protected $hasInvalidTokens = false; | ||||
|  | ||||
|     /** | ||||
| @@ -92,52 +144,49 @@ class EmailLexer extends AbstractLexer | ||||
|     /** | ||||
|      * The last matched/seen token. | ||||
|      * | ||||
|      * @var array | ||||
|      * @var array|Token | ||||
|      * | ||||
|      * @psalm-var array{value:string, type:null|int, position:int} | ||||
|      * @psalm-suppress NonInvariantDocblockPropertyType | ||||
|      * @psalm-var array{value:string, type:null|int, position:int}|Token<int, string> | ||||
|      */ | ||||
|     public $token; | ||||
|  | ||||
|     /** | ||||
|      * The next token in the input. | ||||
|      * | ||||
|      * @var array|null | ||||
|      * @var array|Token|null | ||||
|      * | ||||
|      * @psalm-suppress NonInvariantDocblockPropertyType | ||||
|      * @psalm-var array{position: int, type: int|null|string, value: int|string}|Token<int, string>|null | ||||
|      */ | ||||
|     public $lookahead; | ||||
|  | ||||
|     /** | ||||
|      * @psalm-var array{value:'', type:null, position:0} | ||||
|      */ | ||||
|     /** @psalm-var array{value:'', type:null, position:0} */ | ||||
|     private static $nullToken = [ | ||||
|         'value' => '', | ||||
|         'type' => null, | ||||
|         'position' => 0, | ||||
|     ]; | ||||
|  | ||||
|     /** @var string */ | ||||
|     private $accumulator = ''; | ||||
|  | ||||
|     /** @var bool */ | ||||
|     private $hasToRecord = false; | ||||
|  | ||||
|     public function __construct() | ||||
|     { | ||||
|         $this->previous = $this->token = self::$nullToken; | ||||
|         $this->lookahead = null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return void | ||||
|      */ | ||||
|     public function reset() | ||||
|     public function reset() : void | ||||
|     { | ||||
|         $this->hasInvalidTokens = false; | ||||
|         parent::reset(); | ||||
|         $this->previous = $this->token = self::$nullToken; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function hasInvalidTokens() | ||||
|     { | ||||
|         return $this->hasInvalidTokens; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $type | ||||
|      * @throws \UnexpectedValueException | ||||
| @@ -145,7 +194,7 @@ class EmailLexer extends AbstractLexer | ||||
|      * | ||||
|      * @psalm-suppress InvalidScalarArgument | ||||
|      */ | ||||
|     public function find($type) | ||||
|     public function find($type) : bool | ||||
|     { | ||||
|         $search = clone $this; | ||||
|         $search->skipUntil($type); | ||||
| @@ -156,58 +205,34 @@ class EmailLexer extends AbstractLexer | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * getPrevious | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getPrevious() | ||||
|     { | ||||
|         return $this->previous; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * moveNext | ||||
|      * | ||||
|      * @return boolean | ||||
|      */ | ||||
|     public function moveNext() | ||||
|     public function moveNext() : bool | ||||
|     { | ||||
|         $this->previous = $this->token; | ||||
|         if ($this->hasToRecord && $this->previous === self::$nullToken) { | ||||
|             $this->accumulator .= $this->token['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; | ||||
|         } | ||||
|  | ||||
|         $hasNext = parent::moveNext(); | ||||
|         $this->token = $this->token ?: self::$nullToken; | ||||
|  | ||||
|         if ($this->hasToRecord) { | ||||
|             $this->accumulator .= $this->token['value']; | ||||
|         } | ||||
|  | ||||
|         return $hasNext; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Lexical catchable patterns. | ||||
|      * | ||||
|      * @return string[] | ||||
|      */ | ||||
|     protected function getCatchablePatterns() | ||||
|     { | ||||
|         return array( | ||||
|             '[a-zA-Z_]+[46]?', //ASCII and domain literal | ||||
|             '[^\x00-\x7F]',  //UTF-8 | ||||
|             '[0-9]+', | ||||
|             '\r\n', | ||||
|             '::', | ||||
|             '\s+?', | ||||
|             '.', | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Lexical non-catchable patterns. | ||||
|      * | ||||
|      * @return string[] | ||||
|      */ | ||||
|     protected function getNonCatchablePatterns() | ||||
|     { | ||||
|         return array('[\xA0-\xff]+'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Retrieve token type. Also processes the token value if necessary. | ||||
|      * | ||||
| @@ -217,67 +242,106 @@ class EmailLexer extends AbstractLexer | ||||
|      */ | ||||
|     protected function getType(&$value) | ||||
|     { | ||||
|         if ($this->isNullType($value)) { | ||||
|         $encoded = $value; | ||||
|  | ||||
|         if (mb_detect_encoding($value, 'auto', true) !== 'UTF-8') { | ||||
|             $encoded = mb_convert_encoding($value, 'UTF-8', 'Windows-1252'); | ||||
|         } | ||||
|  | ||||
|         if ($this->isValid($encoded)) { | ||||
|             return $this->charValue[$encoded]; | ||||
|         } | ||||
|  | ||||
|         if ($this->isNullType($encoded)) { | ||||
|             return self::C_NUL; | ||||
|         } | ||||
|  | ||||
|         if ($this->isValid($value)) { | ||||
|             return $this->charValue[$value]; | ||||
|         } | ||||
|  | ||||
|         if ($this->isUTF8Invalid($value)) { | ||||
|         if ($this->isInvalidChar($encoded)) { | ||||
|             $this->hasInvalidTokens = true; | ||||
|             return self::INVALID; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         return  self::GENERIC; | ||||
|     } | ||||
|  | ||||
|     protected function isValid(string $value) : bool | ||||
|     { | ||||
|         return isset($this->charValue[$value]); | ||||
|     } | ||||
|  | ||||
|     protected function isNullType(string $value) : bool | ||||
|     { | ||||
|         return $value === "\0"; | ||||
|     } | ||||
|  | ||||
|     protected function isInvalidChar(string $value) : bool | ||||
|     { | ||||
|         return !preg_match(self::INVALID_CHARS_REGEX, $value); | ||||
|     } | ||||
|  | ||||
|     protected function isUTF8Invalid(string $value) : bool | ||||
|     { | ||||
|         return preg_match(self::VALID_UTF8_REGEX, $value) !== false; | ||||
|     } | ||||
|  | ||||
|     public function hasInvalidTokens() : bool | ||||
|     { | ||||
|         return $this->hasInvalidTokens; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $value | ||||
|      * getPrevious | ||||
|      * | ||||
|      * @return bool | ||||
|      * @return array | ||||
|      */ | ||||
|     protected function isValid($value) | ||||
|     public function getPrevious() : array | ||||
|     { | ||||
|         if (isset($this->charValue[$value])) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|         return $this->previous; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $value | ||||
|      * @return bool | ||||
|      * Lexical catchable patterns. | ||||
|      * | ||||
|      * @return string[] | ||||
|      */ | ||||
|     protected function isNullType($value) | ||||
|     protected function getCatchablePatterns() : array | ||||
|     { | ||||
|         if ($value === "\0") { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|         return self::CATCHABLE_PATTERNS; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $value | ||||
|      * @return bool | ||||
|      * Lexical non-catchable patterns. | ||||
|      * | ||||
|      * @return string[] | ||||
|      */ | ||||
|     protected function isUTF8Invalid($value) | ||||
|     protected function getNonCatchablePatterns() : array | ||||
|     { | ||||
|         if (preg_match('/\p{Cc}+/u', $value)) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|         return self::NON_CATCHABLE_PATTERNS; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function getModifiers() | ||||
|     protected function getModifiers() : string | ||||
|     { | ||||
|         return 'iu'; | ||||
|         return self::MODIFIERS; | ||||
|     } | ||||
|  | ||||
|     public function getAccumulatedValues() : string | ||||
|     { | ||||
|         return $this->accumulator; | ||||
|     } | ||||
|  | ||||
|     public function startRecording() : void | ||||
|     { | ||||
|         $this->hasToRecord = true; | ||||
|     } | ||||
|  | ||||
|     public function stopRecording() : void | ||||
|     { | ||||
|         $this->hasToRecord = false; | ||||
|     } | ||||
|  | ||||
|     public function clearRecorded() : void | ||||
|     { | ||||
|         $this->accumulator = ''; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										151
									
								
								vendor/egulias/email-validator/src/EmailParser.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										151
									
								
								vendor/egulias/email-validator/src/EmailParser.php
									
									
									
									
										vendored
									
									
								
							| @@ -2,25 +2,17 @@ | ||||
|  | ||||
| namespace Egulias\EmailValidator; | ||||
|  | ||||
| use Egulias\EmailValidator\Exception\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Exception\NoLocalPart; | ||||
| use Egulias\EmailValidator\Parser\DomainPart; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Parser\LocalPart; | ||||
| use Egulias\EmailValidator\Parser\DomainPart; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\EmailTooLong; | ||||
| use Egulias\EmailValidator\Result\Reason\NoLocalPart; | ||||
|  | ||||
| /** | ||||
|  * EmailParser | ||||
|  * | ||||
|  * @author Eduardo Gulias Davis <me@egulias.com> | ||||
|  */ | ||||
| class EmailParser | ||||
| class EmailParser extends Parser | ||||
| { | ||||
|     const EMAIL_MAX_LENGTH = 254; | ||||
|  | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $warnings = []; | ||||
|     public const EMAIL_MAX_LENGTH = 254; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
| @@ -31,104 +23,65 @@ class EmailParser | ||||
|      * @var string | ||||
|      */ | ||||
|     protected $localPart = ''; | ||||
|     /** | ||||
|      * @var EmailLexer | ||||
|      */ | ||||
|     protected $lexer; | ||||
|  | ||||
|     /** | ||||
|      * @var LocalPart | ||||
|      */ | ||||
|     protected $localPartParser; | ||||
|  | ||||
|     /** | ||||
|      * @var DomainPart | ||||
|      */ | ||||
|     protected $domainPartParser; | ||||
|  | ||||
|     public function __construct(EmailLexer $lexer) | ||||
|     public function parse(string $str) : Result | ||||
|     { | ||||
|         $this->lexer = $lexer; | ||||
|         $this->localPartParser = new LocalPart($this->lexer); | ||||
|         $this->domainPartParser = new DomainPart($this->lexer); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $str | ||||
|      * @return array | ||||
|      */ | ||||
|     public function parse($str) | ||||
|     { | ||||
|         $this->lexer->setInput($str); | ||||
|  | ||||
|         if (!$this->hasAtToken()) { | ||||
|             throw new NoLocalPart(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         $this->localPartParser->parse($str); | ||||
|         $this->domainPartParser->parse($str); | ||||
|  | ||||
|         $this->setParts($str); | ||||
|  | ||||
|         if ($this->lexer->hasInvalidTokens()) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         } | ||||
|  | ||||
|         return array('local' => $this->localPart, 'domain' => $this->domainPart); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Warning\Warning[] | ||||
|      */ | ||||
|     public function getWarnings() | ||||
|     { | ||||
|         $localPartWarnings = $this->localPartParser->getWarnings(); | ||||
|         $domainPartWarnings = $this->domainPartParser->getWarnings(); | ||||
|         $this->warnings = array_merge($localPartWarnings, $domainPartWarnings); | ||||
|         $result = parent::parse($str); | ||||
|  | ||||
|         $this->addLongEmailWarning($this->localPart, $this->domainPart); | ||||
|  | ||||
|         return $this->warnings; | ||||
|         return $result; | ||||
|     } | ||||
|      | ||||
|     protected function preLeftParsing(): Result | ||||
|     { | ||||
|         if (!$this->hasAtToken()) { | ||||
|             return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getParsedDomainPart() | ||||
|     protected function parseLeftFromAt(): Result | ||||
|     { | ||||
|         return $this->processLocalPart(); | ||||
|     } | ||||
|  | ||||
|     protected function parseRightFromAt(): Result | ||||
|     { | ||||
|         return $this->processDomainPart(); | ||||
|     } | ||||
|  | ||||
|     private function processLocalPart() : Result | ||||
|     { | ||||
|         $localPartParser = new LocalPart($this->lexer); | ||||
|         $localPartResult = $localPartParser->parse(); | ||||
|         $this->localPart = $localPartParser->localPart(); | ||||
|         $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); | ||||
|  | ||||
|         return $localPartResult; | ||||
|     } | ||||
|  | ||||
|     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 | ||||
|     { | ||||
|         return $this->domainPart; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $email | ||||
|      */ | ||||
|     protected function setParts($email) | ||||
|     public function getLocalPart() : string | ||||
|     { | ||||
|         $parts = explode('@', $email); | ||||
|         $this->domainPart = $this->domainPartParser->getDomainPart(); | ||||
|         $this->localPart = $parts[0]; | ||||
|         return $this->localPart; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function hasAtToken() | ||||
|     { | ||||
|         $this->lexer->moveNext(); | ||||
|         $this->lexer->moveNext(); | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_AT) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $localPart | ||||
|      * @param string $parsedDomainPart | ||||
|      */ | ||||
|     protected function addLongEmailWarning($localPart, $parsedDomainPart) | ||||
|     private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void | ||||
|     { | ||||
|         if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) { | ||||
|             $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| namespace Egulias\EmailValidator; | ||||
|  | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Validation\EmailValidation; | ||||
|  | ||||
| class EmailValidator | ||||
| @@ -15,12 +15,12 @@ class EmailValidator | ||||
|     /** | ||||
|      * @var Warning\Warning[] | ||||
|      */ | ||||
|     protected $warnings = []; | ||||
|     private $warnings = []; | ||||
|  | ||||
|     /** | ||||
|      * @var InvalidEmail|null | ||||
|      * @var ?InvalidEmail | ||||
|      */ | ||||
|     protected $error; | ||||
|     private $error; | ||||
|  | ||||
|     public function __construct() | ||||
|     { | ||||
| @@ -32,7 +32,7 @@ class EmailValidator | ||||
|      * @param EmailValidation $emailValidation | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isValid($email, EmailValidation $emailValidation) | ||||
|     public function isValid(string $email, EmailValidation $emailValidation) | ||||
|     { | ||||
|         $isValid = $emailValidation->isValid($email, $this->lexer); | ||||
|         $this->warnings = $emailValidation->getWarnings(); | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class AtextAfterCFWS extends InvalidEmail | ||||
| { | ||||
|     const CODE = 133; | ||||
|     const REASON = "ATEXT found after CFWS"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class CRLFAtTheEnd extends InvalidEmail | ||||
| { | ||||
|     const CODE = 149; | ||||
|     const REASON = "CRLF at the end"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class CRLFX2 extends InvalidEmail | ||||
| { | ||||
|     const CODE = 148; | ||||
|     const REASON = "Folding whitespace CR LF found twice"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class CRNoLF extends InvalidEmail | ||||
| { | ||||
|     const CODE = 150; | ||||
|     const REASON = "Missing LF after CR"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class CharNotAllowed extends InvalidEmail | ||||
| { | ||||
|     const CODE = 201; | ||||
|     const REASON = "Non allowed character in domain"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class CommaInDomain extends InvalidEmail | ||||
| { | ||||
|     const CODE = 200; | ||||
|     const REASON = "Comma ',' is not allowed in domain part"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ConsecutiveAt extends InvalidEmail | ||||
| { | ||||
|     const CODE = 128; | ||||
|     const REASON = "Consecutive AT"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ConsecutiveDot extends InvalidEmail | ||||
| { | ||||
|     const CODE = 132; | ||||
|     const REASON = "Consecutive DOT"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class DomainAcceptsNoMail extends InvalidEmail | ||||
| { | ||||
|     const CODE = 154; | ||||
|     const REASON = 'Domain accepts no mail (Null MX, RFC7505)'; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class DomainHyphened extends InvalidEmail | ||||
| { | ||||
|     const CODE = 144; | ||||
|     const REASON = "Hyphen found in domain"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class DotAtEnd extends InvalidEmail | ||||
| { | ||||
|     const CODE = 142; | ||||
|     const REASON = "Dot at the end"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class DotAtStart extends InvalidEmail | ||||
| { | ||||
|     const CODE = 141; | ||||
|     const REASON = "Found DOT at start"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ExpectingAT extends InvalidEmail | ||||
| { | ||||
|     const CODE = 202; | ||||
|     const REASON = "Expecting AT '@' "; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ExpectingATEXT extends InvalidEmail | ||||
| { | ||||
|     const CODE = 137; | ||||
|     const REASON = "Expecting ATEXT"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ExpectingCTEXT extends InvalidEmail | ||||
| { | ||||
|     const CODE = 139; | ||||
|     const REASON = "Expecting CTEXT"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ExpectingDTEXT extends InvalidEmail | ||||
| { | ||||
|     const CODE = 129; | ||||
|     const REASON = "Expected DTEXT"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ExpectingDomainLiteralClose extends InvalidEmail | ||||
| { | ||||
|     const CODE = 137; | ||||
|     const REASON = "Closing bracket ']' for domain literal not found"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class ExpectingQPair extends InvalidEmail | ||||
| { | ||||
|     const CODE = 136; | ||||
|     const REASON = "Expecting QPAIR"; | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| abstract class InvalidEmail extends \InvalidArgumentException | ||||
| { | ||||
|     const REASON = "Invalid email"; | ||||
|     const CODE = 0; | ||||
|  | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(static::REASON, static::CODE); | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class LocalOrReservedDomain extends InvalidEmail | ||||
| { | ||||
|     const CODE = 153; | ||||
|     const REASON = 'Local, mDNS or reserved domain (RFC2606, RFC6762)'; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class NoDNSRecord extends InvalidEmail | ||||
| { | ||||
|     const CODE = 5; | ||||
|     const REASON = 'No MX or A DSN record was found for this email'; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class NoDomainPart extends InvalidEmail | ||||
| { | ||||
|     const CODE = 131; | ||||
|     const REASON = "No Domain part"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class NoLocalPart extends InvalidEmail | ||||
| { | ||||
|     const CODE = 130; | ||||
|     const REASON = "No local part"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class UnclosedComment extends InvalidEmail | ||||
| { | ||||
|     const CODE = 146; | ||||
|     const REASON = "No closing comment token found"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class UnclosedQuotedString extends InvalidEmail | ||||
| { | ||||
|     const CODE = 145; | ||||
|     const REASON = "Unclosed quoted string"; | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Exception; | ||||
|  | ||||
| class UnopenedComment extends InvalidEmail | ||||
| { | ||||
|     const CODE = 152; | ||||
|     const REASON = "No opening comment token found"; | ||||
| } | ||||
							
								
								
									
										91
									
								
								vendor/egulias/email-validator/src/MessageIDParser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/egulias/email-validator/src/MessageIDParser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator; | ||||
|  | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Parser\IDLeftPart; | ||||
| use Egulias\EmailValidator\Parser\IDRightPart; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\EmailTooLong; | ||||
| use Egulias\EmailValidator\Result\Reason\NoLocalPart; | ||||
|  | ||||
| class MessageIDParser extends Parser | ||||
| { | ||||
|  | ||||
|     public const EMAILID_MAX_LENGTH = 254; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     protected $idLeft = ''; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     protected $idRight = ''; | ||||
|  | ||||
|     public function parse(string $str) : Result | ||||
|     { | ||||
|         $result = parent::parse($str); | ||||
|  | ||||
|         $this->addLongEmailWarning($this->idLeft, $this->idRight); | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|      | ||||
|     protected function preLeftParsing(): Result | ||||
|     { | ||||
|         if (!$this->hasAtToken()) { | ||||
|             return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     protected function parseLeftFromAt(): Result | ||||
|     { | ||||
|         return $this->processIDLeft(); | ||||
|     } | ||||
|  | ||||
|     protected function parseRightFromAt(): Result | ||||
|     { | ||||
|         return $this->processIDRight(); | ||||
|     } | ||||
|  | ||||
|     private function processIDLeft() : Result | ||||
|     { | ||||
|         $localPartParser = new IDLeftPart($this->lexer); | ||||
|         $localPartResult = $localPartParser->parse(); | ||||
|         $this->idLeft = $localPartParser->localPart(); | ||||
|         $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); | ||||
|  | ||||
|         return $localPartResult; | ||||
|     } | ||||
|  | ||||
|     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 | ||||
|     { | ||||
|         return $this->idLeft; | ||||
|     } | ||||
|  | ||||
|     public function getRightPart() : string | ||||
|     { | ||||
|         return $this->idRight; | ||||
|     } | ||||
|  | ||||
|     private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void | ||||
|     { | ||||
|         if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAILID_MAX_LENGTH) { | ||||
|             $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										78
									
								
								vendor/egulias/email-validator/src/Parser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								vendor/egulias/email-validator/src/Parser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator; | ||||
|  | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
|  | ||||
| abstract class Parser | ||||
| { | ||||
|     /** | ||||
|      * @var Warning\Warning[] | ||||
|      */ | ||||
|     protected $warnings = []; | ||||
|  | ||||
|     /** | ||||
|      * @var EmailLexer | ||||
|      */ | ||||
|     protected $lexer; | ||||
|  | ||||
|     /** | ||||
|      * id-left "@" id-right | ||||
|      */ | ||||
|     abstract protected function parseRightFromAt() : Result; | ||||
|     abstract protected function parseLeftFromAt() : Result; | ||||
|     abstract protected function preLeftParsing() : Result; | ||||
|  | ||||
|  | ||||
|     public function __construct(EmailLexer $lexer) | ||||
|     { | ||||
|         $this->lexer = $lexer;    | ||||
|     } | ||||
|  | ||||
|     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"]); | ||||
|         } | ||||
|  | ||||
|         $preParsingResult = $this->preLeftParsing(); | ||||
|         if ($preParsingResult->isInvalid()) { | ||||
|             return $preParsingResult; | ||||
|         } | ||||
|  | ||||
|         $localPartResult = $this->parseLeftFromAt(); | ||||
|  | ||||
|         if ($localPartResult->isInvalid()) { | ||||
|             return $localPartResult; | ||||
|         } | ||||
|  | ||||
|         $domainPartResult = $this->parseRightFromAt();  | ||||
|  | ||||
|         if ($domainPartResult->isInvalid()) { | ||||
|             return $domainPartResult; | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Warning\Warning[] | ||||
|      */ | ||||
|     public function getWarnings() : array | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
|  | ||||
|     protected function hasAtToken() : bool | ||||
|     { | ||||
|         $this->lexer->moveNext(); | ||||
|         $this->lexer->moveNext(); | ||||
|  | ||||
|         return $this->lexer->token['type'] !== EmailLexer::S_AT; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										104
									
								
								vendor/egulias/email-validator/src/Parser/Comment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/egulias/email-validator/src/Parser/Comment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Warning\QuotedPart; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Parser\CommentStrategy\CommentStrategy; | ||||
| use Egulias\EmailValidator\Result\Reason\UnclosedComment; | ||||
| use Egulias\EmailValidator\Result\Reason\UnOpenedComment; | ||||
| use Egulias\EmailValidator\Warning\Comment as WarningComment; | ||||
|  | ||||
| class Comment extends PartParser | ||||
| { | ||||
|     /** | ||||
|      * @var int | ||||
|      */ | ||||
|     private $openedParenthesis = 0; | ||||
|  | ||||
|     /** | ||||
|      * @var CommentStrategy | ||||
|      */ | ||||
|     private $commentStrategy; | ||||
|  | ||||
|     public function __construct(EmailLexer $lexer, CommentStrategy $commentStrategy) | ||||
|     { | ||||
|         $this->lexer = $lexer; | ||||
|         $this->commentStrategy = $commentStrategy; | ||||
|     } | ||||
|  | ||||
|     public function parse() : Result | ||||
|     { | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { | ||||
|             $this->openedParenthesis++; | ||||
|             if($this->noClosingParenthesis()) { | ||||
|                 return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { | ||||
|             return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         $this->warnings[WarningComment::CODE] = new WarningComment(); | ||||
|  | ||||
|         $moreTokens = true; | ||||
|         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)) { | ||||
|                 $this->openedParenthesis--; | ||||
|             } | ||||
|             $moreTokens = $this->lexer->moveNext(); | ||||
|         } | ||||
|  | ||||
|         if($this->openedParenthesis >= 1) { | ||||
|             return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']); | ||||
|         } | ||||
|         if ($this->openedParenthesis < 0) { | ||||
|             return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         $finalValidations = $this->commentStrategy->endOfLoopValidations($this->lexer); | ||||
|  | ||||
|         $this->warnings = array_merge($this->warnings, $this->commentStrategy->getWarnings()); | ||||
|  | ||||
|         return $finalValidations; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     private function warnEscaping() : bool | ||||
|     { | ||||
|         //Backslash found | ||||
|         if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $this->warnings[QuotedPart::CODE] = | ||||
|             new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); | ||||
|         return true; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private function noClosingParenthesis() : bool  | ||||
|     { | ||||
|         try { | ||||
|             $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); | ||||
|             return false; | ||||
|         } catch (\RuntimeException $e) { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								vendor/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser\CommentStrategy; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
|  | ||||
| interface CommentStrategy | ||||
| { | ||||
|     /** | ||||
|      * Return "true" to continue, "false" to exit | ||||
|      */ | ||||
|     public function exitCondition(EmailLexer $lexer, int $openedParenthesis) : bool; | ||||
|  | ||||
|     public function endOfLoopValidations(EmailLexer $lexer) : Result; | ||||
|  | ||||
|     public function getWarnings() : array; | ||||
| } | ||||
							
								
								
									
										37
									
								
								vendor/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								vendor/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser\CommentStrategy; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
|  | ||||
| class DomainComment implements CommentStrategy | ||||
| { | ||||
|     public function exitCondition(EmailLexer $lexer, int $openedParenthesis) : bool | ||||
|     { | ||||
|         if (($openedParenthesis === 0 && $lexer->isNextToken(EmailLexer::S_DOT))){ // || !$internalLexer->moveNext()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     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']); | ||||
|         } | ||||
|         //add warning | ||||
|         //Address is valid within the message but cannot be used unmodified for the envelope | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     public function getWarnings(): array | ||||
|     { | ||||
|         return []; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										37
									
								
								vendor/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								vendor/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser\CommentStrategy; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Warning\CFWSNearAt; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
|  | ||||
| class LocalComment implements CommentStrategy | ||||
| { | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     private $warnings = []; | ||||
|  | ||||
|     public function exitCondition(EmailLexer $lexer, int $openedParenthesis) : bool | ||||
|     { | ||||
|         return !$lexer->isNextToken(EmailLexer::S_AT); | ||||
|     } | ||||
|  | ||||
|     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']); | ||||
|         } | ||||
|         $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     public function getWarnings(): array | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										211
									
								
								vendor/egulias/email-validator/src/Parser/DomainLiteral.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								vendor/egulias/email-validator/src/Parser/DomainLiteral.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | ||||
| <?php | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | ||||
| use Egulias\EmailValidator\Warning\IPV6BadChar; | ||||
| use Egulias\EmailValidator\Result\Reason\CRNoLF; | ||||
| use Egulias\EmailValidator\Warning\IPV6ColonEnd; | ||||
| use Egulias\EmailValidator\Warning\IPV6MaxGroups; | ||||
| use Egulias\EmailValidator\Warning\ObsoleteDTEXT; | ||||
| use Egulias\EmailValidator\Warning\AddressLiteral; | ||||
| use Egulias\EmailValidator\Warning\IPV6ColonStart; | ||||
| use Egulias\EmailValidator\Warning\IPV6Deprecated; | ||||
| use Egulias\EmailValidator\Warning\IPV6GroupCount; | ||||
| use Egulias\EmailValidator\Warning\IPV6DoubleColon; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingDTEXT; | ||||
| use Egulias\EmailValidator\Result\Reason\UnusualElements; | ||||
| use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral; | ||||
|  | ||||
| class DomainLiteral extends PartParser | ||||
| { | ||||
|     public const IPV4_REGEX = '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/'; | ||||
|  | ||||
|     public const OBSOLETE_WARNINGS = [ | ||||
|         EmailLexer::INVALID, | ||||
|         EmailLexer::C_DEL, | ||||
|         EmailLexer::S_LF, | ||||
|         EmailLexer::S_BACKSLASH | ||||
|     ]; | ||||
|  | ||||
|     public function parse() : Result | ||||
|     { | ||||
|         $this->addTagWarnings(); | ||||
|  | ||||
|         $IPv6TAG = false; | ||||
|         $addressLiteral = ''; | ||||
|  | ||||
|         do { | ||||
|             if ($this->lexer->token['type'] === EmailLexer::C_NUL) { | ||||
|                 return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']); | ||||
|             } | ||||
|  | ||||
|             $this->addObsoleteWarnings(); | ||||
|  | ||||
|             if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) { | ||||
|                 return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->isNextTokenAny( | ||||
|                 array(EmailLexer::S_HTAB, EmailLexer::S_SP, EmailLexer::CRLF) | ||||
|             )) { | ||||
|                 $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); | ||||
|                 $this->parseFWS(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->isNextToken(EmailLexer::S_CR)) { | ||||
|                 return new InvalidEmail(new CRNoLF(), $this->lexer->token['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->token['type'] === EmailLexer::S_IPV6TAG) { | ||||
|                 $IPv6TAG = true; | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             $addressLiteral .= $this->lexer->token['value']; | ||||
|  | ||||
|         } while ($this->lexer->moveNext()); | ||||
|  | ||||
|  | ||||
|         //Encapsulate | ||||
|         $addressLiteral = str_replace('[', '', $addressLiteral); | ||||
|         $isAddressLiteralIPv4 = $this->checkIPV4Tag($addressLiteral); | ||||
|  | ||||
|         if (!$isAddressLiteralIPv4) { | ||||
|             return new ValidEmail(); | ||||
|         } else { | ||||
|             $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral); | ||||
|         } | ||||
|  | ||||
|         if (!$IPv6TAG) { | ||||
|             $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral(); | ||||
|             return new ValidEmail(); | ||||
|         } | ||||
|  | ||||
|         $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); | ||||
|  | ||||
|         $this->checkIPV6Tag($addressLiteral); | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $addressLiteral | ||||
|      * @param int $maxGroups | ||||
|      */ | ||||
|     public function checkIPV6Tag($addressLiteral, $maxGroups = 8) : void | ||||
|     { | ||||
|         $prev = $this->lexer->getPrevious(); | ||||
|         if ($prev['type'] === EmailLexer::S_COLON) { | ||||
|             $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd(); | ||||
|         } | ||||
|  | ||||
|         $IPv6       = substr($addressLiteral, 5); | ||||
|         //Daniel Marschall's new IPv6 testing strategy | ||||
|         $matchesIP  = explode(':', $IPv6); | ||||
|         $groupCount = count($matchesIP); | ||||
|         $colons     = strpos($IPv6, '::'); | ||||
|  | ||||
|         if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) { | ||||
|             $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar(); | ||||
|         } | ||||
|  | ||||
|         if ($colons === false) { | ||||
|             // We need exactly the right number of groups | ||||
|             if ($groupCount !== $maxGroups) { | ||||
|                 $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount(); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($colons !== strrpos($IPv6, '::')) { | ||||
|             $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($colons === 0 || $colons === (strlen($IPv6) - 2)) { | ||||
|             // RFC 4291 allows :: at the start or end of an address | ||||
|             //with 7 other groups in addition | ||||
|             ++$maxGroups; | ||||
|         } | ||||
|  | ||||
|         if ($groupCount > $maxGroups) { | ||||
|             $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups(); | ||||
|         } elseif ($groupCount === $maxGroups) { | ||||
|             $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string | ||||
|     { | ||||
|         $matchesIP  = []; | ||||
|         $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP); | ||||
|  | ||||
|         // Extract IPv4 part from the end of the address-literal (if there is one) | ||||
|         if ($IPv4Match > 0) { | ||||
|             $index = (int) strrpos($addressLiteralIPv4, $matchesIP[0]); | ||||
|             //There's a match but it is at the start | ||||
|             if ($index > 0) { | ||||
|                 // Convert IPv4 part to IPv6 format for further testing | ||||
|                 return substr($addressLiteralIPv4, 0, $index) . '0:0'; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $addressLiteralIPv4; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $addressLiteral | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function checkIPV4Tag($addressLiteral) : bool | ||||
|     { | ||||
|         $matchesIP  = []; | ||||
|         $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP); | ||||
|  | ||||
|         // Extract IPv4 part from the end of the address-literal (if there is one) | ||||
|  | ||||
|         if ($IPv4Match > 0) { | ||||
|             $index = strrpos($addressLiteral, $matchesIP[0]); | ||||
|             //There's a match but it is at the start | ||||
|             if ($index === 0) { | ||||
|                 $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private function addObsoleteWarnings() : void | ||||
|     { | ||||
|         if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) { | ||||
|             $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private function addTagWarnings() : void | ||||
|     { | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_COLON)) { | ||||
|             $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); | ||||
|         } | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) { | ||||
|             $lexer = clone $this->lexer; | ||||
|             $lexer->moveNext(); | ||||
|             if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) { | ||||
|                 $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -2,442 +2,315 @@ | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Doctrine\Common\Lexer\Token; | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\CharNotAllowed; | ||||
| use Egulias\EmailValidator\Exception\CommaInDomain; | ||||
| use Egulias\EmailValidator\Exception\ConsecutiveAt; | ||||
| use Egulias\EmailValidator\Exception\CRLFAtTheEnd; | ||||
| use Egulias\EmailValidator\Exception\CRNoLF; | ||||
| use Egulias\EmailValidator\Exception\DomainHyphened; | ||||
| use Egulias\EmailValidator\Exception\DotAtEnd; | ||||
| use Egulias\EmailValidator\Exception\DotAtStart; | ||||
| use Egulias\EmailValidator\Exception\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Exception\ExpectingDomainLiteralClose; | ||||
| use Egulias\EmailValidator\Exception\ExpectingDTEXT; | ||||
| use Egulias\EmailValidator\Exception\NoDomainPart; | ||||
| use Egulias\EmailValidator\Exception\UnopenedComment; | ||||
| use Egulias\EmailValidator\Warning\AddressLiteral; | ||||
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | ||||
| use Egulias\EmailValidator\Warning\DeprecatedComment; | ||||
| use Egulias\EmailValidator\Warning\DomainLiteral; | ||||
| use Egulias\EmailValidator\Warning\DomainTooLong; | ||||
| use Egulias\EmailValidator\Warning\IPV6BadChar; | ||||
| use Egulias\EmailValidator\Warning\IPV6ColonEnd; | ||||
| use Egulias\EmailValidator\Warning\IPV6ColonStart; | ||||
| use Egulias\EmailValidator\Warning\IPV6Deprecated; | ||||
| use Egulias\EmailValidator\Warning\IPV6DoubleColon; | ||||
| use Egulias\EmailValidator\Warning\IPV6GroupCount; | ||||
| use Egulias\EmailValidator\Warning\IPV6MaxGroups; | ||||
| use Egulias\EmailValidator\Warning\LabelTooLong; | ||||
| use Egulias\EmailValidator\Warning\ObsoleteDTEXT; | ||||
| use Egulias\EmailValidator\Warning\TLD; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\DotAtEnd; | ||||
| use Egulias\EmailValidator\Result\Reason\DotAtStart; | ||||
| use Egulias\EmailValidator\Warning\DeprecatedComment; | ||||
| use Egulias\EmailValidator\Result\Reason\CRLFAtTheEnd; | ||||
| use Egulias\EmailValidator\Result\Reason\LabelTooLong; | ||||
| use Egulias\EmailValidator\Result\Reason\NoDomainPart; | ||||
| use Egulias\EmailValidator\Result\Reason\ConsecutiveAt; | ||||
| use Egulias\EmailValidator\Result\Reason\DomainTooLong; | ||||
| use Egulias\EmailValidator\Result\Reason\CharNotAllowed; | ||||
| use Egulias\EmailValidator\Result\Reason\DomainHyphened; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Parser\CommentStrategy\DomainComment; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingDomainLiteralClose; | ||||
| use Egulias\EmailValidator\Parser\DomainLiteral as DomainLiteralParser; | ||||
|  | ||||
| class DomainPart extends Parser | ||||
| class DomainPart extends PartParser | ||||
| { | ||||
|     const DOMAIN_MAX_LENGTH = 254; | ||||
|     const LABEL_MAX_LENGTH = 63; | ||||
|     public const DOMAIN_MAX_LENGTH = 253; | ||||
|     public const LABEL_MAX_LENGTH = 63; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     protected $domainPart = ''; | ||||
|  | ||||
|     public function parse($domainPart) | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     protected $label = ''; | ||||
|  | ||||
|     public function parse() : Result | ||||
|     { | ||||
|         $this->lexer->clearRecorded(); | ||||
|         $this->lexer->startRecording(); | ||||
|  | ||||
|         $this->lexer->moveNext(); | ||||
|  | ||||
|         $this->performDomainStartChecks(); | ||||
|  | ||||
|         $domain = $this->doParseDomainPart(); | ||||
|  | ||||
|         $prev = $this->lexer->getPrevious(); | ||||
|         $length = strlen($domain); | ||||
|  | ||||
|         if ($prev['type'] === EmailLexer::S_DOT) { | ||||
|             throw new DotAtEnd(); | ||||
|         $domainChecks = $this->performDomainStartChecks(); | ||||
|         if ($domainChecks->isInvalid()) { | ||||
|             return $domainChecks; | ||||
|         } | ||||
|         if ($prev['type'] === EmailLexer::S_HYPHEN) { | ||||
|             throw new DomainHyphened(); | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_AT) { | ||||
|             return new InvalidEmail(new ConsecutiveAt(), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         $result = $this->doParseDomainPart(); | ||||
|         if ($result->isInvalid()) { | ||||
|             return $result; | ||||
|         } | ||||
|  | ||||
|         $end = $this->checkEndOfDomain(); | ||||
|         if ($end->isInvalid()) { | ||||
|             return $end; | ||||
|         } | ||||
|  | ||||
|         $this->lexer->stopRecording(); | ||||
|         $this->domainPart = $this->lexer->getAccumulatedValues(); | ||||
|  | ||||
|         $length = strlen($this->domainPart); | ||||
|         if ($length > self::DOMAIN_MAX_LENGTH) { | ||||
|             $this->warnings[DomainTooLong::CODE] = new DomainTooLong(); | ||||
|             return new InvalidEmail(new DomainTooLong(), $this->lexer->token['value']); | ||||
|         } | ||||
|         if ($prev['type'] === EmailLexer::S_CR) { | ||||
|             throw new CRLFAtTheEnd(); | ||||
|         } | ||||
|         $this->domainPart = $domain; | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     private function performDomainStartChecks() | ||||
|     private function checkEndOfDomain() : Result | ||||
|     { | ||||
|         $this->checkInvalidTokensAfterAT(); | ||||
|         $this->checkEmptyDomain(); | ||||
|         $prev = $this->lexer->getPrevious(); | ||||
|         if ($prev['type'] === EmailLexer::S_DOT) { | ||||
|             return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']); | ||||
|         } | ||||
|         if ($prev['type'] === 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']); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     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) { | ||||
|             $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); | ||||
|             $this->parseDomainComments(); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     private function checkEmptyDomain() | ||||
|     private function checkEmptyDomain() : Result | ||||
|     { | ||||
|         $thereIsNoDomain = $this->lexer->token['type'] === EmailLexer::S_EMPTY || | ||||
|             ($this->lexer->token['type'] === EmailLexer::S_SP && | ||||
|             !$this->lexer->isNextToken(EmailLexer::GENERIC)); | ||||
|  | ||||
|         if ($thereIsNoDomain) { | ||||
|             throw new NoDomainPart(); | ||||
|             return new InvalidEmail(new NoDomainPart(), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     private function checkInvalidTokensAfterAT() | ||||
|     private function checkInvalidTokensAfterAT() : Result | ||||
|     { | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_DOT) { | ||||
|             throw new DotAtStart(); | ||||
|             return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']); | ||||
|         } | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) { | ||||
|             throw new DomainHyphened(); | ||||
|             return new InvalidEmail(new DomainHyphened('After AT'), $this->lexer->token['value']); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getDomainPart() | ||||
|     protected function parseComments(): Result | ||||
|     { | ||||
|         return $this->domainPart; | ||||
|         $commentParser = new Comment($this->lexer, new DomainComment()); | ||||
|         $result = $commentParser->parse(); | ||||
|         $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $addressLiteral | ||||
|      * @param int $maxGroups | ||||
|      */ | ||||
|     public function checkIPV6Tag($addressLiteral, $maxGroups = 8) | ||||
|     { | ||||
|         $prev = $this->lexer->getPrevious(); | ||||
|         if ($prev['type'] === EmailLexer::S_COLON) { | ||||
|             $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd(); | ||||
|         } | ||||
|  | ||||
|         $IPv6       = substr($addressLiteral, 5); | ||||
|         //Daniel Marschall's new IPv6 testing strategy | ||||
|         $matchesIP  = explode(':', $IPv6); | ||||
|         $groupCount = count($matchesIP); | ||||
|         $colons     = strpos($IPv6, '::'); | ||||
|  | ||||
|         if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) { | ||||
|             $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar(); | ||||
|         } | ||||
|  | ||||
|         if ($colons === false) { | ||||
|             // We need exactly the right number of groups | ||||
|             if ($groupCount !== $maxGroups) { | ||||
|                 $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount(); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($colons !== strrpos($IPv6, '::')) { | ||||
|             $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($colons === 0 || $colons === (strlen($IPv6) - 2)) { | ||||
|             // RFC 4291 allows :: at the start or end of an address | ||||
|             //with 7 other groups in addition | ||||
|             ++$maxGroups; | ||||
|         } | ||||
|  | ||||
|         if ($groupCount > $maxGroups) { | ||||
|             $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups(); | ||||
|         } elseif ($groupCount === $maxGroups) { | ||||
|             $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function doParseDomainPart() | ||||
|     protected function doParseDomainPart() : Result | ||||
|     { | ||||
|         $tldMissing = true; | ||||
|         $hasComments = false; | ||||
|         $domain = ''; | ||||
|         $label = ''; | ||||
|         $openedParenthesis = 0; | ||||
|         do { | ||||
|             $prev = $this->lexer->getPrevious(); | ||||
|  | ||||
|             $this->checkNotAllowedChars($this->lexer->token); | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { | ||||
|                 $this->parseComments(); | ||||
|                 $openedParenthesis += $this->getOpenedParenthesis(); | ||||
|                 $this->lexer->moveNext(); | ||||
|                 $tmpPrev = $this->lexer->getPrevious(); | ||||
|                 if ($tmpPrev['type'] === EmailLexer::S_CLOSEPARENTHESIS) { | ||||
|                     $openedParenthesis--; | ||||
|                 } | ||||
|             $notAllowedChars = $this->checkNotAllowedChars($this->lexer->token); | ||||
|             if ($notAllowedChars->isInvalid()) { | ||||
|                 return $notAllowedChars; | ||||
|             } | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { | ||||
|                 if ($openedParenthesis === 0) { | ||||
|                     throw new UnopenedComment(); | ||||
|                 } else { | ||||
|                     $openedParenthesis--; | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS ||  | ||||
|                 $this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) { | ||||
|                 $hasComments = true; | ||||
|                 $commentsResult = $this->parseComments(); | ||||
|  | ||||
|                 //Invalid comment parsing | ||||
|                 if($commentsResult->isInvalid()) { | ||||
|                     return $commentsResult; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             $this->checkConsecutiveDots(); | ||||
|             $this->checkDomainPartExceptions($prev); | ||||
|  | ||||
|             if ($this->hasBrackets()) { | ||||
|                 $this->parseDomainLiteral(); | ||||
|             $dotsResult = $this->checkConsecutiveDots(); | ||||
|             if ($dotsResult->isInvalid()) { | ||||
|                 return $dotsResult; | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_DOT) { | ||||
|                 $this->checkLabelLength($label); | ||||
|                 $label = ''; | ||||
|             } else { | ||||
|                 $label .= $this->lexer->token['value']; | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_OPENBRACKET) { | ||||
|                 $literalResult = $this->parseDomainLiteral(); | ||||
|  | ||||
|                 $this->addTLDWarnings($tldMissing); | ||||
|                 return $literalResult; | ||||
|             } | ||||
|  | ||||
|             if ($this->isFWS()) { | ||||
|                 $this->parseFWS(); | ||||
|                 $labelCheck = $this->checkLabelLength(); | ||||
|                 if ($labelCheck->isInvalid()) { | ||||
|                     return $labelCheck; | ||||
|                 } | ||||
|  | ||||
|             $FwsResult = $this->parseFWS(); | ||||
|             if($FwsResult->isInvalid()) { | ||||
|                 return $FwsResult; | ||||
|             } | ||||
|  | ||||
|             $domain .= $this->lexer->token['value']; | ||||
|             $this->lexer->moveNext(); | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_SP) { | ||||
|                 throw new CharNotAllowed(); | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::GENERIC)) { | ||||
|                 $tldMissing = false; | ||||
|             } | ||||
|  | ||||
|             $exceptionsResult = $this->checkDomainPartExceptions($prev, $hasComments); | ||||
|             if ($exceptionsResult->isInvalid()) { | ||||
|                 return $exceptionsResult; | ||||
|             } | ||||
|             $this->lexer->moveNext(); | ||||
|  | ||||
|         } while (null !== $this->lexer->token['type']); | ||||
|  | ||||
|         $this->checkLabelLength($label); | ||||
|         $labelCheck = $this->checkLabelLength(true); | ||||
|         if ($labelCheck->isInvalid()) { | ||||
|             return $labelCheck; | ||||
|         } | ||||
|         $this->addTLDWarnings($tldMissing); | ||||
|  | ||||
|         return $domain; | ||||
|         $this->domainPart = $domain; | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     private function checkNotAllowedChars(array $token) | ||||
|     /** | ||||
|      * @psalm-param array|Token<int, string> $token | ||||
|      */ | ||||
|     private function checkNotAllowedChars($token) : Result | ||||
|     { | ||||
|         $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; | ||||
|         if (isset($notAllowed[$token['type']])) { | ||||
|             throw new CharNotAllowed(); | ||||
|             return new InvalidEmail(new CharNotAllowed(), $token['value']); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string|false | ||||
|      * @return Result | ||||
|      */ | ||||
|     protected function parseDomainLiteral() | ||||
|     protected function parseDomainLiteral() : Result | ||||
|     { | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_COLON)) { | ||||
|             $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); | ||||
|         } | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) { | ||||
|             $lexer = clone $this->lexer; | ||||
|             $lexer->moveNext(); | ||||
|             if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) { | ||||
|                 $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); | ||||
|             } | ||||
|         try { | ||||
|             $this->lexer->find(EmailLexer::S_CLOSEBRACKET); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             return new InvalidEmail(new ExpectingDomainLiteralClose(), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         return $this->doParseDomainLiteral(); | ||||
|         $domainLiteralParser = new DomainLiteralParser($this->lexer); | ||||
|         $result = $domainLiteralParser->parse(); | ||||
|         $this->warnings = array_merge($this->warnings, $domainLiteralParser->getWarnings()); | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string|false | ||||
|      */ | ||||
|     protected function doParseDomainLiteral() | ||||
|     protected function checkDomainPartExceptions(array $prev, bool $hasComments) : Result | ||||
|     { | ||||
|         $IPv6TAG = false; | ||||
|         $addressLiteral = ''; | ||||
|         do { | ||||
|             if ($this->lexer->token['type'] === EmailLexer::C_NUL) { | ||||
|                 throw new ExpectingDTEXT(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::INVALID || | ||||
|                 $this->lexer->token['type'] === EmailLexer::C_DEL   || | ||||
|                 $this->lexer->token['type'] === EmailLexer::S_LF | ||||
|             ) { | ||||
|                 $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) { | ||||
|                 throw new ExpectingDTEXT(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->isNextTokenAny( | ||||
|                 array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF) | ||||
|             )) { | ||||
|                 $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); | ||||
|                 $this->parseFWS(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->isNextToken(EmailLexer::S_CR)) { | ||||
|                 throw new CRNoLF(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) { | ||||
|                 $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); | ||||
|                 $addressLiteral .= $this->lexer->token['value']; | ||||
|                 $this->lexer->moveNext(); | ||||
|                 $this->validateQuotedPair(); | ||||
|             } | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) { | ||||
|                 $IPv6TAG = true; | ||||
|             } | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             $addressLiteral .= $this->lexer->token['value']; | ||||
|  | ||||
|         } while ($this->lexer->moveNext()); | ||||
|  | ||||
|         $addressLiteral = str_replace('[', '', $addressLiteral); | ||||
|         $addressLiteral = $this->checkIPV4Tag($addressLiteral); | ||||
|  | ||||
|         if (false === $addressLiteral) { | ||||
|             return $addressLiteral; | ||||
|         } | ||||
|  | ||||
|         if (!$IPv6TAG) { | ||||
|             $this->warnings[DomainLiteral::CODE] = new DomainLiteral(); | ||||
|             return $addressLiteral; | ||||
|         } | ||||
|  | ||||
|         $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); | ||||
|  | ||||
|         $this->checkIPV6Tag($addressLiteral); | ||||
|  | ||||
|         return $addressLiteral; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $addressLiteral | ||||
|      * | ||||
|      * @return string|false | ||||
|      */ | ||||
|     protected function checkIPV4Tag($addressLiteral) | ||||
|     { | ||||
|         $matchesIP  = array(); | ||||
|  | ||||
|         // Extract IPv4 part from the end of the address-literal (if there is one) | ||||
|         if (preg_match( | ||||
|             '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', | ||||
|             $addressLiteral, | ||||
|             $matchesIP | ||||
|         ) > 0 | ||||
|         ) { | ||||
|             $index = strrpos($addressLiteral, $matchesIP[0]); | ||||
|             if ($index === 0) { | ||||
|                 $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); | ||||
|                 return false; | ||||
|             } | ||||
|             // Convert IPv4 part to IPv6 format for further testing | ||||
|             $addressLiteral = substr($addressLiteral, 0, (int) $index) . '0:0'; | ||||
|         } | ||||
|  | ||||
|         return $addressLiteral; | ||||
|     } | ||||
|  | ||||
|     protected function checkDomainPartExceptions(array $prev) | ||||
|     { | ||||
|         $invalidDomainTokens = array( | ||||
|             EmailLexer::S_DQUOTE => true, | ||||
|             EmailLexer::S_SQUOTE => true, | ||||
|             EmailLexer::S_BACKTICK => true, | ||||
|             EmailLexer::S_SEMICOLON => true, | ||||
|             EmailLexer::S_GREATERTHAN => true, | ||||
|             EmailLexer::S_LOWERTHAN => true, | ||||
|         ); | ||||
|  | ||||
|         if (isset($invalidDomainTokens[$this->lexer->token['type']])) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_COMMA) { | ||||
|             throw new CommaInDomain(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_AT) { | ||||
|             throw new ConsecutiveAt(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         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->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) { | ||||
|             throw new DomainHyphened(); | ||||
|             return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH | ||||
|             && $this->lexer->isNextToken(EmailLexer::GENERIC)) { | ||||
|             throw new ExpectingATEXT(); | ||||
|             return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         return $this->validateTokens($hasComments); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function hasBrackets() | ||||
|     protected function validateTokens(bool $hasComments) : Result | ||||
|     { | ||||
|         if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) { | ||||
|             return false; | ||||
|         $validDomainTokens = array( | ||||
|             EmailLexer::GENERIC => true, | ||||
|             EmailLexer::S_HYPHEN => true, | ||||
|             EmailLexer::S_DOT => true, | ||||
|         ); | ||||
|  | ||||
|         if ($hasComments) { | ||||
|             $validDomainTokens[EmailLexer::S_OPENPARENTHESIS] = true; | ||||
|             $validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true; | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             $this->lexer->find(EmailLexer::S_CLOSEBRACKET); | ||||
|         } catch (\RuntimeException $e) { | ||||
|             throw new ExpectingDomainLiteralClose(); | ||||
|         if (!isset($validDomainTokens[$this->lexer->token['type']])) { | ||||
|             return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $label | ||||
|      */ | ||||
|     protected function checkLabelLength($label) | ||||
|     private function checkLabelLength(bool $isEndOfDomain = false) : Result | ||||
|     { | ||||
|         if ($this->isLabelTooLong($label)) { | ||||
|             $this->warnings[LabelTooLong::CODE] = new LabelTooLong(); | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_DOT || $isEndOfDomain) { | ||||
|             if ($this->isLabelTooLong($this->label)) { | ||||
|                 return new InvalidEmail(new LabelTooLong(), $this->lexer->token['value']); | ||||
|             } | ||||
|             $this->label = ''; | ||||
|         } | ||||
|         $this->label .= $this->lexer->token['value']; | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $label | ||||
|      * @return bool | ||||
|      */ | ||||
|     private function isLabelTooLong($label) | ||||
|  | ||||
|     private function isLabelTooLong(string $label) : bool | ||||
|     { | ||||
|         if (preg_match('/[^\x00-\x7F]/', $label)) { | ||||
|             idn_to_ascii($label, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo); | ||||
|  | ||||
|             return (bool) ($idnaInfo['errors'] & IDNA_ERROR_LABEL_TOO_LONG); | ||||
|         } | ||||
|  | ||||
|         return strlen($label) > self::LABEL_MAX_LENGTH; | ||||
|     } | ||||
|  | ||||
|     protected function parseDomainComments() | ||||
|     private function addTLDWarnings(bool $isTLDMissing) : void | ||||
|     { | ||||
|         $this->isUnclosedComment(); | ||||
|         while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { | ||||
|             $this->warnEscaping(); | ||||
|             $this->lexer->moveNext(); | ||||
|         } | ||||
|  | ||||
|         $this->lexer->moveNext(); | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_DOT)) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected function addTLDWarnings() | ||||
|     { | ||||
|         if ($this->warnings[DomainLiteral::CODE]) { | ||||
|         if ($isTLDMissing) { | ||||
|             $this->warnings[TLD::CODE] = new TLD(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function domainPart() : string | ||||
|     { | ||||
|         return $this->domainPart; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										87
									
								
								vendor/egulias/email-validator/src/Parser/DoubleQuote.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								vendor/egulias/email-validator/src/Parser/DoubleQuote.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| <?php | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | ||||
| use Egulias\EmailValidator\Warning\QuotedString; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Result\Reason\UnclosedQuotedString; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
|  | ||||
| class DoubleQuote extends PartParser | ||||
| { | ||||
|     public function parse() : Result | ||||
|     { | ||||
|  | ||||
|         $validQuotedString = $this->checkDQUOTE(); | ||||
|         if($validQuotedString->isInvalid()) return $validQuotedString; | ||||
|  | ||||
|         $special = [ | ||||
|             EmailLexer::S_CR => true, | ||||
|             EmailLexer::S_HTAB => true, | ||||
|             EmailLexer::S_LF => true | ||||
|         ]; | ||||
|  | ||||
|         $invalid = [ | ||||
|             EmailLexer::C_NUL => true, | ||||
|             EmailLexer::S_HTAB => true, | ||||
|             EmailLexer::S_CR => true, | ||||
|             EmailLexer::S_LF => true | ||||
|         ]; | ||||
|          | ||||
|         $setSpecialsWarning = true; | ||||
|  | ||||
|         $this->lexer->moveNext(); | ||||
|  | ||||
|         while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) { | ||||
|             if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) { | ||||
|                 $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); | ||||
|                 $setSpecialsWarning = false; | ||||
|             } | ||||
|             if ($this->lexer->token['type'] === 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']); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $prev = $this->lexer->getPrevious(); | ||||
|  | ||||
|         if ($prev['type'] === EmailLexer::S_BACKSLASH) { | ||||
|             $validQuotedString = $this->checkDQUOTE(); | ||||
|             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']); | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     protected function checkDQUOTE() : Result | ||||
|     { | ||||
|         $previous = $this->lexer->getPrevious(); | ||||
|  | ||||
|         if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === 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']); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             $this->lexer->find(EmailLexer::S_DQUOTE); | ||||
|         } catch (\Exception $e) { | ||||
|             return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->token['value']); | ||||
|         } | ||||
|         $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']); | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										86
									
								
								vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| <?php | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Warning\CFWSNearAt; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | ||||
| use Egulias\EmailValidator\Result\Reason\CRNoLF; | ||||
| use Egulias\EmailValidator\Result\Reason\AtextAfterCFWS; | ||||
| use Egulias\EmailValidator\Result\Reason\CRLFAtTheEnd; | ||||
| use Egulias\EmailValidator\Result\Reason\CRLFX2; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingCTEXT; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
|  | ||||
| class  FoldingWhiteSpace extends PartParser | ||||
| { | ||||
|     public const FWS_TYPES = [ | ||||
|         EmailLexer::S_SP, | ||||
|         EmailLexer::S_HTAB, | ||||
|         EmailLexer::S_CR, | ||||
|         EmailLexer::S_LF, | ||||
|         EmailLexer::CRLF | ||||
|     ]; | ||||
|  | ||||
|     public function parse() : Result | ||||
|     { | ||||
|         if (!$this->isFWS()) { | ||||
|             return new ValidEmail(); | ||||
|         } | ||||
|  | ||||
|         $previous = $this->lexer->getPrevious(); | ||||
|  | ||||
|         $resultCRLF = $this->checkCRLFInFWS(); | ||||
|         if ($resultCRLF->isInvalid()) { | ||||
|             return $resultCRLF; | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_CR) { | ||||
|             return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type']  !== EmailLexer::S_AT) { | ||||
|             return new InvalidEmail(new AtextAfterCFWS(), $this->lexer->token['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->isNextToken(EmailLexer::S_AT) || $previous['type']  === EmailLexer::S_AT) { | ||||
|             $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); | ||||
|         } else { | ||||
|             $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     protected function checkCRLFInFWS() : Result | ||||
|     { | ||||
|         if ($this->lexer->token['type'] !== 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']); | ||||
|         } | ||||
|  | ||||
|         //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 ValidEmail(); | ||||
|     } | ||||
|       | ||||
|     protected function isFWS() : bool | ||||
|     { | ||||
|         if ($this->escaped()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return in_array($this->lexer->token['type'], self::FWS_TYPES); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										15
									
								
								vendor/egulias/email-validator/src/Parser/IDLeftPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/egulias/email-validator/src/Parser/IDLeftPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\CommentsInIDRight; | ||||
|  | ||||
| class IDLeftPart extends LocalPart | ||||
| { | ||||
|     protected function parseComments(): Result | ||||
|     { | ||||
|        return new InvalidEmail(new CommentsInIDRight(), $this->lexer->token['value']); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								vendor/egulias/email-validator/src/Parser/IDRightPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/egulias/email-validator/src/Parser/IDRightPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
|  | ||||
| class IDRightPart extends DomainPart | ||||
| { | ||||
|     protected function validateTokens(bool $hasComments) : Result | ||||
|     { | ||||
|         $invalidDomainTokens = [ | ||||
|             EmailLexer::S_DQUOTE => true, | ||||
|             EmailLexer::S_SQUOTE => true, | ||||
|             EmailLexer::S_BACKTICK => true, | ||||
|             EmailLexer::S_SEMICOLON => true, | ||||
|             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']); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
| } | ||||
| @@ -2,144 +2,164 @@ | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\Exception\DotAtEnd; | ||||
| use Egulias\EmailValidator\Exception\DotAtStart; | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\ExpectingAT; | ||||
| use Egulias\EmailValidator\Exception\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Exception\UnclosedQuotedString; | ||||
| use Egulias\EmailValidator\Exception\UnopenedComment; | ||||
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\LocalTooLong; | ||||
| use Egulias\EmailValidator\Result\Reason\DotAtEnd; | ||||
| use Egulias\EmailValidator\Result\Reason\DotAtStart; | ||||
| use Egulias\EmailValidator\Result\Reason\ConsecutiveDot; | ||||
| use Egulias\EmailValidator\Result\Reason\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment; | ||||
|  | ||||
| class LocalPart extends Parser | ||||
| class LocalPart extends PartParser | ||||
| { | ||||
|     public function parse($localPart) | ||||
|     public const INVALID_TOKENS = [ | ||||
|         EmailLexer::S_COMMA => EmailLexer::S_COMMA, | ||||
|         EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, | ||||
|         EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, | ||||
|         EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN, | ||||
|         EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN, | ||||
|         EmailLexer::S_COLON => EmailLexer::S_COLON, | ||||
|         EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON, | ||||
|         EmailLexer::INVALID => EmailLexer::INVALID | ||||
|     ]; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     private $localPart = ''; | ||||
|  | ||||
|  | ||||
|     public function parse() : Result | ||||
|     { | ||||
|         $parseDQuote = true; | ||||
|         $closingQuote = false; | ||||
|         $openedParenthesis = 0; | ||||
|         $totalLength = 0; | ||||
|         $this->lexer->startRecording(); | ||||
|  | ||||
|         while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) { | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type']) { | ||||
|                 throw new DotAtStart(); | ||||
|             if ($this->hasDotAtStart()) { | ||||
|                 return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']); | ||||
|             } | ||||
|  | ||||
|             $closingQuote = $this->checkDQUOTE($closingQuote); | ||||
|             if ($closingQuote && $parseDQuote) { | ||||
|                 $parseDQuote = $this->parseDoubleQuote(); | ||||
|             } | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_DQUOTE) { | ||||
|                 $dquoteParsingResult = $this->parseDoubleQuote(); | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { | ||||
|                 $this->parseComments(); | ||||
|                 $openedParenthesis += $this->getOpenedParenthesis(); | ||||
|             } | ||||
|  | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { | ||||
|                 if ($openedParenthesis === 0) { | ||||
|                     throw new UnopenedComment(); | ||||
|                 //Invalid double quote parsing | ||||
|                 if($dquoteParsingResult->isInvalid()) { | ||||
|                     return $dquoteParsingResult; | ||||
|                 } | ||||
|  | ||||
|                 $openedParenthesis--; | ||||
|             } | ||||
|  | ||||
|             $this->checkConsecutiveDots(); | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS ||  | ||||
|                 $this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) { | ||||
|                 $commentsResult = $this->parseComments(); | ||||
|  | ||||
|                 //Invalid comment parsing | ||||
|                 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->token['type'] === EmailLexer::S_DOT && | ||||
|                 $this->lexer->isNextToken(EmailLexer::S_AT) | ||||
|             ) { | ||||
|                 throw new DotAtEnd(); | ||||
|                 return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']); | ||||
|             } | ||||
|  | ||||
|             $this->warnEscaping(); | ||||
|             $this->isInvalidToken($this->lexer->token, $closingQuote); | ||||
|  | ||||
|             if ($this->isFWS()) { | ||||
|                 $this->parseFWS(); | ||||
|             $resultEscaping = $this->validateEscaping(); | ||||
|             if ($resultEscaping->isInvalid()) { | ||||
|                 return $resultEscaping; | ||||
|             } | ||||
|  | ||||
|             $resultToken = $this->validateTokens(false); | ||||
|             if ($resultToken->isInvalid()) { | ||||
|                 return $resultToken; | ||||
|             } | ||||
|  | ||||
|             $resultFWS = $this->parseLocalFWS(); | ||||
|             if($resultFWS->isInvalid()) { | ||||
|                 return $resultFWS; | ||||
|             } | ||||
|  | ||||
|             $totalLength += strlen($this->lexer->token['value']); | ||||
|             $this->lexer->moveNext(); | ||||
|         } | ||||
|  | ||||
|         if ($totalLength > LocalTooLong::LOCAL_PART_LENGTH) { | ||||
|         $this->lexer->stopRecording(); | ||||
|         $this->localPart = rtrim($this->lexer->getAccumulatedValues(), '@'); | ||||
|         if (strlen($this->localPart) > LocalTooLong::LOCAL_PART_LENGTH) { | ||||
|             $this->warnings[LocalTooLong::CODE] = new LocalTooLong(); | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function parseDoubleQuote() | ||||
|     protected function validateTokens(bool $hasComments) : Result | ||||
|     { | ||||
|         $parseAgain = true; | ||||
|         $special = array( | ||||
|             EmailLexer::S_CR => true, | ||||
|             EmailLexer::S_HTAB => true, | ||||
|             EmailLexer::S_LF => true | ||||
|         ); | ||||
|  | ||||
|         $invalid = array( | ||||
|             EmailLexer::C_NUL => true, | ||||
|             EmailLexer::S_HTAB => true, | ||||
|             EmailLexer::S_CR => true, | ||||
|             EmailLexer::S_LF => true | ||||
|         ); | ||||
|         $setSpecialsWarning = true; | ||||
|  | ||||
|         $this->lexer->moveNext(); | ||||
|  | ||||
|         while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) { | ||||
|             $parseAgain = false; | ||||
|             if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) { | ||||
|                 $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); | ||||
|                 $setSpecialsWarning = false; | ||||
|             } | ||||
|             if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) { | ||||
|                 $this->lexer->moveNext(); | ||||
|             } | ||||
|  | ||||
|             $this->lexer->moveNext(); | ||||
|  | ||||
|             if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) { | ||||
|                 throw new ExpectingATEXT(); | ||||
|             } | ||||
|         if (isset(self::INVALID_TOKENS[$this->lexer->token['type']])) { | ||||
|             return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']); | ||||
|         } | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|         $prev = $this->lexer->getPrevious(); | ||||
|     public function localPart() : string | ||||
|     { | ||||
|         return $this->localPart; | ||||
|     } | ||||
|  | ||||
|         if ($prev['type'] === EmailLexer::S_BACKSLASH) { | ||||
|             if (!$this->checkDQUOTE(false)) { | ||||
|                 throw new UnclosedQuotedString(); | ||||
|             } | ||||
|     private function parseLocalFWS() : Result  | ||||
|     { | ||||
|         $foldingWS = new FoldingWhiteSpace($this->lexer); | ||||
|         $resultFWS = $foldingWS->parse(); | ||||
|         if ($resultFWS->isValid()) { | ||||
|             $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings()); | ||||
|         } | ||||
|         return $resultFWS; | ||||
|     } | ||||
|  | ||||
|         if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) { | ||||
|             throw new ExpectingAT(); | ||||
|         } | ||||
|     private function hasDotAtStart() : bool | ||||
|     { | ||||
|             return $this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type']; | ||||
|     } | ||||
|  | ||||
|     private function parseDoubleQuote() : Result | ||||
|     { | ||||
|         $dquoteParser = new DoubleQuote($this->lexer); | ||||
|         $parseAgain = $dquoteParser->parse(); | ||||
|         $this->warnings = array_merge($this->warnings, $dquoteParser->getWarnings()); | ||||
|  | ||||
|         return $parseAgain; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param bool $closingQuote | ||||
|      */ | ||||
|     protected function isInvalidToken(array $token, $closingQuote) | ||||
|     protected function parseComments(): Result | ||||
|     { | ||||
|         $forbidden = array( | ||||
|             EmailLexer::S_COMMA, | ||||
|             EmailLexer::S_CLOSEBRACKET, | ||||
|             EmailLexer::S_OPENBRACKET, | ||||
|             EmailLexer::S_GREATERTHAN, | ||||
|             EmailLexer::S_LOWERTHAN, | ||||
|             EmailLexer::S_COLON, | ||||
|             EmailLexer::S_SEMICOLON, | ||||
|             EmailLexer::INVALID | ||||
|         ); | ||||
|  | ||||
|         if (in_array($token['type'], $forbidden) && !$closingQuote) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         $commentParser = new Comment($this->lexer, new LocalComment()); | ||||
|         $result = $commentParser->parse(); | ||||
|         $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); | ||||
|         if($result->isInvalid()) { | ||||
|             return $result; | ||||
|         } | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     private function validateEscaping() : Result | ||||
|     { | ||||
|         //Backslash found | ||||
|         if ($this->lexer->token['type'] !== 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']); | ||||
|         } | ||||
|  | ||||
|         if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { | ||||
|             return new ValidEmail(); | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										249
									
								
								vendor/egulias/email-validator/src/Parser/Parser.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										249
									
								
								vendor/egulias/email-validator/src/Parser/Parser.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,249 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\AtextAfterCFWS; | ||||
| use Egulias\EmailValidator\Exception\ConsecutiveDot; | ||||
| use Egulias\EmailValidator\Exception\CRLFAtTheEnd; | ||||
| use Egulias\EmailValidator\Exception\CRLFX2; | ||||
| use Egulias\EmailValidator\Exception\CRNoLF; | ||||
| use Egulias\EmailValidator\Exception\ExpectingQPair; | ||||
| use Egulias\EmailValidator\Exception\ExpectingATEXT; | ||||
| use Egulias\EmailValidator\Exception\ExpectingCTEXT; | ||||
| use Egulias\EmailValidator\Exception\UnclosedComment; | ||||
| use Egulias\EmailValidator\Exception\UnclosedQuotedString; | ||||
| use Egulias\EmailValidator\Warning\CFWSNearAt; | ||||
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | ||||
| use Egulias\EmailValidator\Warning\Comment; | ||||
| use Egulias\EmailValidator\Warning\QuotedPart; | ||||
| use Egulias\EmailValidator\Warning\QuotedString; | ||||
|  | ||||
| abstract class Parser | ||||
| { | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $warnings = []; | ||||
|  | ||||
|     /** | ||||
|      * @var EmailLexer | ||||
|      */ | ||||
|     protected $lexer; | ||||
|  | ||||
|     /** | ||||
|      * @var int | ||||
|      */ | ||||
|     protected $openedParenthesis = 0; | ||||
|  | ||||
|     public function __construct(EmailLexer $lexer) | ||||
|     { | ||||
|         $this->lexer = $lexer; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return \Egulias\EmailValidator\Warning\Warning[] | ||||
|      */ | ||||
|     public function getWarnings() | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $str | ||||
|      */ | ||||
|     abstract public function parse($str); | ||||
|  | ||||
|     /** @return int */ | ||||
|     public function getOpenedParenthesis() | ||||
|     { | ||||
|         return $this->openedParenthesis; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * validateQuotedPair | ||||
|      */ | ||||
|     protected function validateQuotedPair() | ||||
|     { | ||||
|         if (!($this->lexer->token['type'] === EmailLexer::INVALID | ||||
|             || $this->lexer->token['type'] === EmailLexer::C_DEL)) { | ||||
|             throw new ExpectingQPair(); | ||||
|         } | ||||
|  | ||||
|         $this->warnings[QuotedPart::CODE] = | ||||
|             new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); | ||||
|     } | ||||
|  | ||||
|     protected function parseComments() | ||||
|     { | ||||
|         $this->openedParenthesis = 1; | ||||
|         $this->isUnclosedComment(); | ||||
|         $this->warnings[Comment::CODE] = new Comment(); | ||||
|         while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { | ||||
|             if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) { | ||||
|                 $this->openedParenthesis++; | ||||
|             } | ||||
|             $this->warnEscaping(); | ||||
|             $this->lexer->moveNext(); | ||||
|         } | ||||
|  | ||||
|         $this->lexer->moveNext(); | ||||
|         if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_AT)) { | ||||
|             $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function isUnclosedComment() | ||||
|     { | ||||
|         try { | ||||
|             $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); | ||||
|             return true; | ||||
|         } catch (\RuntimeException $e) { | ||||
|             throw new UnclosedComment(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected function parseFWS() | ||||
|     { | ||||
|         $previous = $this->lexer->getPrevious(); | ||||
|  | ||||
|         $this->checkCRLFInFWS(); | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_CR) { | ||||
|             throw new CRNoLF(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type']  !== EmailLexer::S_AT) { | ||||
|             throw new AtextAfterCFWS(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) { | ||||
|             throw new ExpectingCTEXT(); | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type']  === EmailLexer::S_AT) { | ||||
|             $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); | ||||
|         } else { | ||||
|             $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected function checkConsecutiveDots() | ||||
|     { | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { | ||||
|             throw new ConsecutiveDot(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function isFWS() | ||||
|     { | ||||
|         if ($this->escaped()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->token['type'] === EmailLexer::S_SP || | ||||
|             $this->lexer->token['type'] === EmailLexer::S_HTAB || | ||||
|             $this->lexer->token['type'] === EmailLexer::S_CR || | ||||
|             $this->lexer->token['type'] === EmailLexer::S_LF || | ||||
|             $this->lexer->token['type'] === EmailLexer::CRLF | ||||
|         ) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function escaped() | ||||
|     { | ||||
|         $previous = $this->lexer->getPrevious(); | ||||
|  | ||||
|         if ($previous && $previous['type'] === EmailLexer::S_BACKSLASH | ||||
|             && | ||||
|             $this->lexer->token['type'] !== EmailLexer::GENERIC | ||||
|         ) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function warnEscaping() | ||||
|     { | ||||
|         if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if ($this->lexer->isNextToken(EmailLexer::GENERIC)) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         } | ||||
|  | ||||
|         if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $this->warnings[QuotedPart::CODE] = | ||||
|             new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); | ||||
|         return true; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param bool $hasClosingQuote | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function checkDQUOTE($hasClosingQuote) | ||||
|     { | ||||
|         if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) { | ||||
|             return $hasClosingQuote; | ||||
|         } | ||||
|         if ($hasClosingQuote) { | ||||
|             return $hasClosingQuote; | ||||
|         } | ||||
|         $previous = $this->lexer->getPrevious(); | ||||
|         if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) { | ||||
|             throw new ExpectingATEXT(); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             $this->lexer->find(EmailLexer::S_DQUOTE); | ||||
|             $hasClosingQuote = true; | ||||
|         } catch (\Exception $e) { | ||||
|             throw new UnclosedQuotedString(); | ||||
|         } | ||||
|         $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']); | ||||
|  | ||||
|         return $hasClosingQuote; | ||||
|     } | ||||
|  | ||||
|     protected function checkCRLFInFWS() | ||||
|     { | ||||
|         if ($this->lexer->token['type'] !== EmailLexer::CRLF) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { | ||||
|             throw new CRLFX2(); | ||||
|         } | ||||
|  | ||||
|         if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { | ||||
|             throw new CRLFAtTheEnd(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										63
									
								
								vendor/egulias/email-validator/src/Parser/PartParser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/egulias/email-validator/src/Parser/PartParser.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Parser; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ConsecutiveDot; | ||||
| use Egulias\EmailValidator\Result\Result; | ||||
| use Egulias\EmailValidator\Result\ValidEmail; | ||||
|  | ||||
| abstract class PartParser | ||||
| { | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $warnings = []; | ||||
|  | ||||
|     /** | ||||
|      * @var EmailLexer | ||||
|      */ | ||||
|     protected $lexer; | ||||
|  | ||||
|     public function __construct(EmailLexer $lexer) | ||||
|     { | ||||
|         $this->lexer = $lexer; | ||||
|     } | ||||
|  | ||||
|     abstract public function parse() : Result; | ||||
|  | ||||
|     /** | ||||
|      * @return \Egulias\EmailValidator\Warning\Warning[] | ||||
|      */ | ||||
|     public function getWarnings() | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
|  | ||||
|     protected function parseFWS() : Result | ||||
|     { | ||||
|         $foldingWS = new FoldingWhiteSpace($this->lexer); | ||||
|         $resultFWS = $foldingWS->parse(); | ||||
|         $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings()); | ||||
|         return $resultFWS; | ||||
|     } | ||||
|  | ||||
|     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']); | ||||
|         } | ||||
|  | ||||
|         return new ValidEmail(); | ||||
|     } | ||||
|  | ||||
|     protected function escaped() : bool | ||||
|     { | ||||
|         $previous = $this->lexer->getPrevious(); | ||||
|  | ||||
|         return $previous && $previous['type'] === EmailLexer::S_BACKSLASH | ||||
|             && | ||||
|             $this->lexer->token['type'] !== EmailLexer::GENERIC; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										46
									
								
								vendor/egulias/email-validator/src/Result/InvalidEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								vendor/egulias/email-validator/src/Result/InvalidEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result; | ||||
|  | ||||
| use Egulias\EmailValidator\Result\Reason\Reason; | ||||
|  | ||||
| class InvalidEmail implements Result | ||||
| { | ||||
|     private $token; | ||||
|     /** | ||||
|      * @var Reason | ||||
|      */ | ||||
|     protected $reason; | ||||
|  | ||||
|     public function __construct(Reason $reason, string $token) | ||||
|     { | ||||
|         $this->token = $token; | ||||
|         $this->reason = $reason; | ||||
|     } | ||||
|  | ||||
|     public function isValid(): bool | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public function isInvalid(): bool | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function description(): string | ||||
|     { | ||||
|         return $this->reason->description() . " in char " . $this->token; | ||||
|     } | ||||
|  | ||||
|     public function code(): int | ||||
|     { | ||||
|         return $this->reason->code(); | ||||
|     } | ||||
|  | ||||
|     public function reason() : Reason | ||||
|     { | ||||
|         return $this->reason; | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										56
									
								
								vendor/egulias/email-validator/src/Result/MultipleErrors.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/egulias/email-validator/src/Result/MultipleErrors.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result; | ||||
|  | ||||
| use Egulias\EmailValidator\Result\Reason\EmptyReason; | ||||
| use Egulias\EmailValidator\Result\Reason\Reason; | ||||
|  | ||||
| /** | ||||
|  * @psalm-suppress PropertyNotSetInConstructor | ||||
|  */ | ||||
| class MultipleErrors extends InvalidEmail | ||||
| { | ||||
|     /** | ||||
|      * @var Reason[] | ||||
|      */ | ||||
|     private $reasons = []; | ||||
|  | ||||
|     public function __construct() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public function addReason(Reason $reason) : void | ||||
|     { | ||||
|         $this->reasons[$reason->code()] = $reason; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Reason[] | ||||
|      */ | ||||
|     public function getReasons() : array | ||||
|     { | ||||
|         return $this->reasons; | ||||
|     } | ||||
|  | ||||
|     public function reason() : Reason | ||||
|     { | ||||
|         return 0 !== count($this->reasons) | ||||
|             ? current($this->reasons) | ||||
|             : new EmptyReason(); | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         $description = ''; | ||||
|         foreach($this->reasons as $reason) { | ||||
|             $description .= $reason->description() . PHP_EOL; | ||||
|         } | ||||
|  | ||||
|         return $description; | ||||
|     } | ||||
|  | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class AtextAfterCFWS implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 133; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'ATEXT found after CFWS'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/egulias/email-validator/src/Result/Reason/CRLFAtTheEnd.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/egulias/email-validator/src/Result/Reason/CRLFAtTheEnd.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class CRLFAtTheEnd implements Reason | ||||
| { | ||||
|     public const CODE = 149; | ||||
|     public const REASON = "CRLF at the end"; | ||||
|  | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 149; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'CRLF at the end'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CRLFX2.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CRLFX2.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class CRLFX2 implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 148; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'CR  LF tokens found twice'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CRNoLF.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CRNoLF.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class CRNoLF implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 150; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Missing LF after CR'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CharNotAllowed.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CharNotAllowed.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class CharNotAllowed implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "Character not allowed"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CommaInDomain.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CommaInDomain.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class CommaInDomain implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 200; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "Comma ',' is not allowed in domain part"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CommentsInIDRight.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/CommentsInIDRight.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class CommentsInIDRight implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 400; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Comments are not allowed in IDRight for message-id'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										17
									
								
								vendor/egulias/email-validator/src/Result/Reason/ConsecutiveAt.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/egulias/email-validator/src/Result/Reason/ConsecutiveAt.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ConsecutiveAt implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 128; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return '@ found after another @'; | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ConsecutiveDot.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ConsecutiveDot.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ConsecutiveDot implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 132; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Concecutive DOT found'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/egulias/email-validator/src/Result/Reason/DetailedReason.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/egulias/email-validator/src/Result/Reason/DetailedReason.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| abstract class DetailedReason implements Reason | ||||
| { | ||||
|     protected $detailedDescription; | ||||
|  | ||||
|     public function __construct(string $details) | ||||
|     { | ||||
|         $this->detailedDescription = $details; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class DomainAcceptsNoMail implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 154; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Domain accepts no mail (Null MX, RFC7505)'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DomainHyphened.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DomainHyphened.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class DomainHyphened extends DetailedReason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 144; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'S_HYPHEN found in domain'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DomainTooLong.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DomainTooLong.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class DomainTooLong implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 244; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Domain is longer than 253 characters'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DotAtEnd.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DotAtEnd.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class DotAtEnd implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 142; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Dot at the end'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DotAtStart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/DotAtStart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class DotAtStart implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 141; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "Starts with a DOT"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/EmptyReason.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/EmptyReason.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class EmptyReason implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Empty reason'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExceptionFound.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExceptionFound.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ExceptionFound implements Reason | ||||
| { | ||||
|     /** | ||||
|      * @var \Exception | ||||
|      */ | ||||
|     private $exception; | ||||
|  | ||||
|     public function __construct(\Exception $exception) | ||||
|     { | ||||
|         $this->exception = $exception; | ||||
|          | ||||
|     } | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 999; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return $this->exception->getMessage(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ExpectingATEXT extends DetailedReason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 137; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "Expecting ATEXT (Printable US-ASCII). Extended: " . $this->detailedDescription; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ExpectingCTEXT implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 139; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Expecting CTEXT'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingDTEXT.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingDTEXT.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ExpectingDTEXT implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 129; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Expecting DTEXT'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingDomainLiteralClose.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/ExpectingDomainLiteralClose.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class ExpectingDomainLiteralClose implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 137; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "Closing bracket ']' for domain literal not found"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/LabelTooLong.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/LabelTooLong.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class LabelTooLong implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 245; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Domain "label" is longer than 63 characters'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/LocalOrReservedDomain.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/LocalOrReservedDomain.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class LocalOrReservedDomain implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 153; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Local, mDNS or reserved domain (RFC2606, RFC6762)'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/NoDNSRecord.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/NoDNSRecord.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class NoDNSRecord implements Reason  | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 5; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'No MX or A DSN record was found for this email'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/NoDomainPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/NoDomainPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class NoDomainPart implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 131; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'No domain part found'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/NoLocalPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/NoLocalPart.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class NoLocalPart implements Reason  | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 130; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "No local part"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/RFCWarnings.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/RFCWarnings.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class RFCWarnings implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 997; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Warnings found after validating'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/Reason.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/Reason.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| interface Reason | ||||
| { | ||||
|     /** | ||||
|      * Code for user land to act upon; | ||||
|      */ | ||||
|     public function code() : int; | ||||
|  | ||||
|     /** | ||||
|      * Short description of the result, human readable. | ||||
|      */ | ||||
|     public function description() : string; | ||||
| } | ||||
							
								
								
									
										17
									
								
								vendor/egulias/email-validator/src/Result/Reason/SpoofEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/egulias/email-validator/src/Result/Reason/SpoofEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class SpoofEmail implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 298; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'The email contains mixed UTF8 chars that makes it suspicious';  | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class UnOpenedComment implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 152; | ||||
|     } | ||||
|  | ||||
|     public function description(): string | ||||
|     { | ||||
|         return 'Missing opening comment parentheses - https://tools.ietf.org/html/rfc5322#section-3.2.2'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnableToGetDNSRecord.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnableToGetDNSRecord.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| /** | ||||
|  * Used on SERVFAIL, TIMEOUT or other runtime and network errors | ||||
|  */ | ||||
| class UnableToGetDNSRecord extends NoDNSRecord | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 3; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Unable to get DNS records for the host'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnclosedComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnclosedComment.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class UnclosedComment implements Reason  | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 146; | ||||
|     } | ||||
|  | ||||
|     public function description(): string | ||||
|     { | ||||
|         return 'No closing comment token found'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnclosedQuotedString.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnclosedQuotedString.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class UnclosedQuotedString implements Reason | ||||
| { | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 145; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return "Unclosed quoted string"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnusualElements.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/egulias/email-validator/src/Result/Reason/UnusualElements.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result\Reason; | ||||
|  | ||||
| class UnusualElements implements Reason | ||||
| { | ||||
|     /** | ||||
|      * @var string $element | ||||
|      */ | ||||
|     private $element = ''; | ||||
|  | ||||
|     public function __construct(string $element) | ||||
|     { | ||||
|         $this->element = $element; | ||||
|     } | ||||
|  | ||||
|     public function code() : int | ||||
|     { | ||||
|         return 201; | ||||
|     } | ||||
|  | ||||
|     public function description() : string | ||||
|     { | ||||
|         return 'Unusual element found, wourld render invalid in majority of cases. Element found: ' . $this->element; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								vendor/egulias/email-validator/src/Result/Result.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/egulias/email-validator/src/Result/Result.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result; | ||||
|  | ||||
| interface Result | ||||
| { | ||||
|     /** | ||||
|      * Is validation result valid? | ||||
|      */ | ||||
|     public function isValid() : bool; | ||||
|  | ||||
|     /** | ||||
|      * Is validation result invalid? | ||||
|      * Usually the inverse of isValid() | ||||
|      */ | ||||
|     public function isInvalid() : bool; | ||||
|  | ||||
|     /** | ||||
|      * Short description of the result, human readable. | ||||
|      */ | ||||
|     public function description() : string; | ||||
|  | ||||
|     /** | ||||
|      * Code for user land to act upon. | ||||
|      */ | ||||
|     public function code() : int; | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/egulias/email-validator/src/Result/SpoofEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/egulias/email-validator/src/Result/SpoofEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <?php | ||||
| namespace Egulias\EmailValidator\Result; | ||||
|  | ||||
| use Egulias\EmailValidator\Result\Reason\SpoofEmail as ReasonSpoofEmail; | ||||
|  | ||||
| class SpoofEmail extends InvalidEmail | ||||
| { | ||||
|     public function __construct() | ||||
|     { | ||||
|         $this->reason = new ReasonSpoofEmail(); | ||||
|         parent::__construct($this->reason, ''); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								vendor/egulias/email-validator/src/Result/ValidEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/egulias/email-validator/src/Result/ValidEmail.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Result; | ||||
|  | ||||
| class ValidEmail implements Result | ||||
| { | ||||
|     public function isValid(): bool | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function isInvalid(): bool | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public function description(): string | ||||
|     { | ||||
|         return "Valid email"; | ||||
|     } | ||||
|  | ||||
|     public function code(): int | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -3,14 +3,43 @@ | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
| use Egulias\EmailValidator\Exception\LocalOrReservedDomain; | ||||
| use Egulias\EmailValidator\Exception\DomainAcceptsNoMail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\DomainAcceptsNoMail; | ||||
| 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\Exception\NoDNSRecord; | ||||
|  | ||||
| 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) | ||||
|      */ | ||||
|     public const RESERVED_DNS_TOP_LEVEL_NAMES = [ | ||||
|         // Reserved Top Level DNS Names | ||||
|         'test', | ||||
|         'example', | ||||
|         'invalid', | ||||
|         'localhost', | ||||
|  | ||||
|         // mDNS | ||||
|         'local', | ||||
|  | ||||
|         // Private DNS Namespaces | ||||
|         'intranet', | ||||
|         'internal', | ||||
|         'private', | ||||
|         'corp', | ||||
|         'home', | ||||
|         'lan', | ||||
|     ]; | ||||
|      | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
| @@ -26,15 +55,25 @@ class DNSCheckValidation implements EmailValidation | ||||
|      */ | ||||
|     private $mxRecords = []; | ||||
|  | ||||
|     /** | ||||
|      * @var DNSGetRecordWrapper | ||||
|      */ | ||||
|     private $dnsGetRecord; | ||||
|  | ||||
|     public function __construct() | ||||
|     public function __construct(?DNSGetRecordWrapper $dnsGetRecord = null) | ||||
|     { | ||||
|         if (!function_exists('idn_to_ascii')) { | ||||
|             throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__)); | ||||
|         } | ||||
|  | ||||
|         if ($dnsGetRecord == null) { | ||||
|             $dnsGetRecord = new DNSGetRecordWrapper(); | ||||
|         } | ||||
|  | ||||
|         $this->dnsGetRecord = $dnsGetRecord; | ||||
|     } | ||||
|  | ||||
|     public function isValid($email, EmailLexer $emailLexer) | ||||
|     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; | ||||
| @@ -47,45 +86,24 @@ class DNSCheckValidation implements EmailValidation | ||||
|         // Get the domain parts | ||||
|         $hostParts = explode('.', $host); | ||||
|  | ||||
|         // 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) | ||||
|         $reservedTopLevelDnsNames = [ | ||||
|             // Reserved Top Level DNS Names | ||||
|             'test', | ||||
|             'example', | ||||
|             'invalid', | ||||
|             'localhost', | ||||
|  | ||||
|             // mDNS | ||||
|             'local', | ||||
|  | ||||
|             // Private DNS Namespaces | ||||
|             'intranet', | ||||
|             'internal', | ||||
|             'private', | ||||
|             'corp', | ||||
|             'home', | ||||
|             'lan', | ||||
|         ]; | ||||
|  | ||||
|         $isLocalDomain = count($hostParts) <= 1; | ||||
|         $isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], $reservedTopLevelDnsNames, true); | ||||
|         $isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], self::RESERVED_DNS_TOP_LEVEL_NAMES, true); | ||||
|  | ||||
|         // Exclude reserved top level DNS names | ||||
|         if ($isLocalDomain || $isReservedTopLevel) { | ||||
|             $this->error = new LocalOrReservedDomain(); | ||||
|             $this->error = new InvalidEmail(new LocalOrReservedDomain(), $host); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return $this->checkDns($host); | ||||
|     } | ||||
|  | ||||
|     public function getError() | ||||
|     public function getError() : ?InvalidEmail | ||||
|     { | ||||
|         return $this->error; | ||||
|     } | ||||
|  | ||||
|     public function getWarnings() | ||||
|     public function getWarnings() : array | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
| @@ -112,31 +130,33 @@ class DNSCheckValidation implements EmailValidation | ||||
|      * | ||||
|      * @return bool True on success. | ||||
|      */ | ||||
|     private function validateDnsRecords($host) | ||||
|     private function validateDnsRecords($host) : bool | ||||
|     { | ||||
|         // Get all MX, A and AAAA DNS records for host | ||||
|         // Using @ as workaround to fix https://bugs.php.net/bug.php?id=73149 | ||||
|         $dnsRecords = @dns_get_record($host, DNS_MX + DNS_A + DNS_AAAA); | ||||
|         $dnsRecordsResult = $this->dnsGetRecord->getRecords($host, static::DNS_RECORD_TYPES_TO_CHECK); | ||||
|  | ||||
|         if ($dnsRecordsResult->withError()) { | ||||
|             $this->error = new InvalidEmail(new UnableToGetDNSRecord(), ''); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $dnsRecords = $dnsRecordsResult->getRecords(); | ||||
|  | ||||
|         // No MX, A or AAAA DNS records | ||||
|         if (empty($dnsRecords)) { | ||||
|             $this->error = new NoDNSRecord(); | ||||
|         if ($dnsRecords === []) { | ||||
|             $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // For each DNS record | ||||
|         foreach ($dnsRecords as $dnsRecord) { | ||||
|             if (!$this->validateMXRecord($dnsRecord)) { | ||||
|                 // No MX records (fallback to A or AAAA records) | ||||
|                 if (empty($this->mxRecords)) { | ||||
|                     $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord(); | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // No MX records (fallback to A or AAAA records) | ||||
|         if (empty($this->mxRecords)) { | ||||
|             $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord(); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -147,15 +167,20 @@ class DNSCheckValidation implements EmailValidation | ||||
|      * | ||||
|      * @return bool True if valid. | ||||
|      */ | ||||
|     private function validateMxRecord($dnsRecord) | ||||
|     private function validateMxRecord($dnsRecord) : bool | ||||
|     { | ||||
|         if (!isset($dnsRecord['type'])) { | ||||
|             $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if ($dnsRecord['type'] !== 'MX') { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         // "Null MX" record indicates the domain accepts no mail (https://tools.ietf.org/html/rfc7505) | ||||
|         if (empty($dnsRecord['target']) || $dnsRecord['target'] === '.') { | ||||
|             $this->error = new DomainAcceptsNoMail(); | ||||
|             $this->error = new InvalidEmail(new DomainAcceptsNoMail(), ""); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|   | ||||
							
								
								
									
										28
									
								
								vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| <?php | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| class DNSGetRecordWrapper | ||||
| { | ||||
|     /** | ||||
|      * @param string $host | ||||
|      * @param int $type | ||||
|      */ | ||||
|     public function getRecords(string $host, int $type) : DNSRecords | ||||
|     { | ||||
|         // A workaround to fix https://bugs.php.net/bug.php?id=73149 | ||||
|         /** @psalm-suppress InvalidArgument */ | ||||
|         set_error_handler( | ||||
|             static function (int $errorLevel, string $errorMessage): ?bool { | ||||
|                 throw new \RuntimeException("Unable to get DNS record for the host: $errorMessage"); | ||||
|             } | ||||
|         ); | ||||
|         try { | ||||
|             // Get all MX, A and AAAA DNS records for host | ||||
|             return new DNSRecords(dns_get_record($host, $type)); | ||||
|         } catch (\RuntimeException $exception) { | ||||
|             return new DNSRecords([], true); | ||||
|         } finally { | ||||
|             restore_error_handler(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								vendor/egulias/email-validator/src/Validation/DNSRecords.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/egulias/email-validator/src/Validation/DNSRecords.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| class DNSRecords | ||||
| { | ||||
|      | ||||
|     /** | ||||
|      * @var array $records | ||||
|      */ | ||||
|     private $records = []; | ||||
|  | ||||
|     /** | ||||
|      * @var bool $error | ||||
|      */ | ||||
|     private $error = false; | ||||
|  | ||||
|     public function __construct(array $records, bool $error = false) | ||||
|     { | ||||
|         $this->records = $records; | ||||
|         $this->error = $error; | ||||
|     } | ||||
|  | ||||
|     public function getRecords() : array | ||||
|     { | ||||
|         return $this->records; | ||||
|     } | ||||
|  | ||||
|     public function withError() : bool | ||||
|     { | ||||
|         return $this->error; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -3,7 +3,7 @@ | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Warning\Warning; | ||||
|  | ||||
| interface EmailValidation | ||||
| @@ -16,19 +16,19 @@ interface EmailValidation | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isValid($email, EmailLexer $emailLexer); | ||||
|     public function isValid(string $email, EmailLexer $emailLexer) : bool; | ||||
|  | ||||
|     /** | ||||
|      * Returns the validation error. | ||||
|      * | ||||
|      * @return InvalidEmail|null | ||||
|      */ | ||||
|     public function getError(); | ||||
|     public function getError() : ?InvalidEmail; | ||||
|  | ||||
|     /** | ||||
|      * Returns the validation warnings. | ||||
|      * | ||||
|      * @return Warning[] | ||||
|      */ | ||||
|     public function getWarnings(); | ||||
|     public function getWarnings() : array; | ||||
| } | ||||
|   | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Validation\Error; | ||||
|  | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
|  | ||||
| class RFCWarnings extends InvalidEmail | ||||
| { | ||||
|     const CODE = 997; | ||||
|     const REASON = 'Warnings were found.'; | ||||
| } | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Validation\Error; | ||||
|  | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
|  | ||||
| class SpoofEmail extends InvalidEmail | ||||
| { | ||||
|     const CODE = 998; | ||||
|     const REASON = "The email contains mixed UTF8 chars that makes it suspicious"; | ||||
| } | ||||
| @@ -9,7 +9,7 @@ class EmptyValidationList extends \InvalidArgumentException | ||||
|     /** | ||||
|     * @param int $code | ||||
|     */ | ||||
|     public function __construct($code = 0, Exception $previous = null) | ||||
|     public function __construct($code = 0, ?Exception $previous = null) | ||||
|     { | ||||
|         parent::__construct("Empty validation list is not allowed", $code, $previous); | ||||
|     } | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
| namespace Egulias\EmailValidator\Validation\Extra; | ||||
| 
 | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
| use Egulias\EmailValidator\Validation\Error\SpoofEmail; | ||||
| use \Spoofchecker; | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\SpoofEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Validation\EmailValidation; | ||||
| 
 | ||||
| class SpoofCheckValidation implements EmailValidation | ||||
| { | ||||
| @@ -24,7 +25,7 @@ class SpoofCheckValidation implements EmailValidation | ||||
|     /** | ||||
|      * @psalm-suppress InvalidArgument | ||||
|      */ | ||||
|     public function isValid($email, EmailLexer $emailLexer) | ||||
|     public function isValid(string $email, EmailLexer $emailLexer) : bool | ||||
|     { | ||||
|         $checker = new Spoofchecker(); | ||||
|         $checker->setChecks(Spoofchecker::SINGLE_SCRIPT); | ||||
| @@ -37,14 +38,14 @@ class SpoofCheckValidation implements EmailValidation | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return InvalidEmail|null | ||||
|      * @return InvalidEmail | ||||
|      */ | ||||
|     public function getError() | ||||
|     public function getError() : ?InvalidEmail | ||||
|     { | ||||
|         return $this->error; | ||||
|     } | ||||
| 
 | ||||
|     public function getWarnings() | ||||
|     public function getWarnings() : array | ||||
|     { | ||||
|         return []; | ||||
|     } | ||||
							
								
								
									
										51
									
								
								vendor/egulias/email-validator/src/Validation/MessageIDValidation.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/egulias/email-validator/src/Validation/MessageIDValidation.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\MessageIDParser; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ExceptionFound; | ||||
|  | ||||
| class MessageIDValidation implements EmailValidation | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     private $warnings = []; | ||||
|  | ||||
|     /** | ||||
|      * @var ?InvalidEmail | ||||
|      */ | ||||
|     private $error; | ||||
|  | ||||
|     public function isValid(string $email, EmailLexer $emailLexer): bool | ||||
|     { | ||||
|         $parser = new MessageIDParser($emailLexer); | ||||
|         try { | ||||
|             $result = $parser->parse($email); | ||||
|             $this->warnings = $parser->getWarnings(); | ||||
|             if ($result->isInvalid()) { | ||||
|                 /** @psalm-suppress PropertyTypeCoercion */ | ||||
|                 $this->error = $result; | ||||
|                 return false; | ||||
|             } | ||||
|         } catch (\Exception $invalid) { | ||||
|             $this->error = new InvalidEmail(new ExceptionFound($invalid), ''); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function getWarnings(): array | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
|  | ||||
|     public function getError(): ?InvalidEmail | ||||
|     { | ||||
|         return $this->error; | ||||
|     } | ||||
| } | ||||
| @@ -1,32 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
|  | ||||
| class MultipleErrors extends InvalidEmail | ||||
| { | ||||
|     const CODE = 999; | ||||
|     const REASON = "Accumulated errors for multiple validations"; | ||||
|     /** | ||||
|      * @var InvalidEmail[] | ||||
|      */ | ||||
|     private $errors = []; | ||||
|  | ||||
|     /** | ||||
|      * @param InvalidEmail[] $errors | ||||
|      */ | ||||
|     public function __construct(array $errors) | ||||
|     { | ||||
|         $this->errors = $errors; | ||||
|         parent::__construct(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return InvalidEmail[] | ||||
|      */ | ||||
|     public function getErrors() | ||||
|     { | ||||
|         return $this->errors; | ||||
|     } | ||||
| } | ||||
| @@ -3,21 +3,23 @@ | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Validation\Exception\EmptyValidationList; | ||||
| use Egulias\EmailValidator\Result\MultipleErrors; | ||||
|  | ||||
| class MultipleValidationWithAnd implements EmailValidation | ||||
| { | ||||
|     /** | ||||
|      * If one of validations gets failure skips all succeeding validation. | ||||
|      * This means MultipleErrors will only contain a single error which first found. | ||||
|      * If one of validations fails, the remaining validations will be skipped. | ||||
|      * This means MultipleErrors will only contain a single error, the first found. | ||||
|      */ | ||||
|     const STOP_ON_ERROR = 0; | ||||
|     public const STOP_ON_ERROR = 0; | ||||
|  | ||||
|     /** | ||||
|      * All of validations will be invoked even if one of them got failure. | ||||
|      * So MultipleErrors will contain all causes. | ||||
|      */ | ||||
|     const ALLOW_ALL_ERRORS = 1; | ||||
|     public const ALLOW_ALL_ERRORS = 1; | ||||
|  | ||||
|     /** | ||||
|      * @var EmailValidation[] | ||||
| @@ -56,60 +58,51 @@ class MultipleValidationWithAnd implements EmailValidation | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function isValid($email, EmailLexer $emailLexer) | ||||
|     public function isValid(string $email, EmailLexer $emailLexer) : bool | ||||
|     { | ||||
|         $result = true; | ||||
|         $errors = []; | ||||
|         foreach ($this->validations as $validation) { | ||||
|             $emailLexer->reset(); | ||||
|             $validationResult = $validation->isValid($email, $emailLexer); | ||||
|             $result = $result && $validationResult; | ||||
|             $this->warnings = array_merge($this->warnings, $validation->getWarnings()); | ||||
|             $errors = $this->addNewError($validation->getError(), $errors); | ||||
|             if (!$validationResult) { | ||||
|                 $this->processError($validation); | ||||
|             } | ||||
|  | ||||
|             if ($this->shouldStop($result)) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!empty($errors)) { | ||||
|             $this->error = new MultipleErrors($errors); | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Egulias\EmailValidator\Exception\InvalidEmail|null $possibleError | ||||
|      * @param \Egulias\EmailValidator\Exception\InvalidEmail[] $errors | ||||
|      * | ||||
|      * @return \Egulias\EmailValidator\Exception\InvalidEmail[] | ||||
|      */ | ||||
|     private function addNewError($possibleError, array $errors) | ||||
|     private function initErrorStorage() : void | ||||
|     { | ||||
|         if (null !== $possibleError) { | ||||
|             $errors[] = $possibleError; | ||||
|         if (null === $this->error) { | ||||
|             $this->error = new MultipleErrors(); | ||||
|         } | ||||
|  | ||||
|         return $errors; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param bool $result | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     private function shouldStop($result) | ||||
|     private function processError(EmailValidation $validation) : void | ||||
|     { | ||||
|         if (null !== $validation->getError()) { | ||||
|             $this->initErrorStorage(); | ||||
|             /** @psalm-suppress PossiblyNullReference */ | ||||
|             $this->error->addReason($validation->getError()->reason()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private function shouldStop(bool $result) : bool | ||||
|     { | ||||
|         return !$result && $this->mode === self::STOP_ON_ERROR; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the validation errors. | ||||
|      * | ||||
|      * @return MultipleErrors|null | ||||
|      */ | ||||
|     public function getError() | ||||
|     public function getError() : ?InvalidEmail | ||||
|     { | ||||
|         return $this->error; | ||||
|     } | ||||
| @@ -117,7 +110,7 @@ class MultipleValidationWithAnd implements EmailValidation | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function getWarnings() | ||||
|     public function getWarnings() : array | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
|   | ||||
| @@ -3,8 +3,8 @@ | ||||
| namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
| use Egulias\EmailValidator\Validation\Error\RFCWarnings; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\RFCWarnings; | ||||
|  | ||||
| class NoRFCWarningsValidation extends RFCValidation | ||||
| { | ||||
| @@ -16,7 +16,7 @@ class NoRFCWarningsValidation extends RFCValidation | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function isValid($email, EmailLexer $emailLexer) | ||||
|     public function isValid(string $email, EmailLexer $emailLexer) : bool | ||||
|     { | ||||
|         if (!parent::isValid($email, $emailLexer)) { | ||||
|             return false; | ||||
| @@ -26,7 +26,7 @@ class NoRFCWarningsValidation extends RFCValidation | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         $this->error = new RFCWarnings(); | ||||
|         $this->error = new InvalidEmail(new RFCWarnings(), ''); | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| @@ -34,7 +34,7 @@ class NoRFCWarningsValidation extends RFCValidation | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function getError() | ||||
|     public function getError() : ?InvalidEmail | ||||
|     { | ||||
|         return $this->error ?: parent::getError(); | ||||
|     } | ||||
|   | ||||
| @@ -4,7 +4,8 @@ namespace Egulias\EmailValidator\Validation; | ||||
|  | ||||
| use Egulias\EmailValidator\EmailLexer; | ||||
| use Egulias\EmailValidator\EmailParser; | ||||
| use Egulias\EmailValidator\Exception\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\InvalidEmail; | ||||
| use Egulias\EmailValidator\Result\Reason\ExceptionFound; | ||||
|  | ||||
| class RFCValidation implements EmailValidation | ||||
| { | ||||
| @@ -19,30 +20,35 @@ class RFCValidation implements EmailValidation | ||||
|     private $warnings = []; | ||||
|  | ||||
|     /** | ||||
|      * @var InvalidEmail|null | ||||
|      * @var ?InvalidEmail | ||||
|      */ | ||||
|     private $error; | ||||
|  | ||||
|     public function isValid($email, EmailLexer $emailLexer) | ||||
|     public function isValid(string $email, EmailLexer $emailLexer) : bool | ||||
|     { | ||||
|         $this->parser = new EmailParser($emailLexer); | ||||
|         try { | ||||
|             $this->parser->parse((string)$email); | ||||
|         } catch (InvalidEmail $invalid) { | ||||
|             $this->error = $invalid; | ||||
|             $result = $this->parser->parse($email); | ||||
|             $this->warnings = $this->parser->getWarnings(); | ||||
|             if ($result->isInvalid()) { | ||||
|                 /** @psalm-suppress PropertyTypeCoercion */ | ||||
|                 $this->error = $result; | ||||
|                 return false; | ||||
|             } | ||||
|         } catch (\Exception $invalid) { | ||||
|             $this->error = new InvalidEmail(new ExceptionFound($invalid), ''); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $this->warnings = $this->parser->getWarnings(); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function getError() | ||||
|     public function getError() : ?InvalidEmail | ||||
|     { | ||||
|         return $this->error; | ||||
|     } | ||||
|  | ||||
|     public function getWarnings() | ||||
|     public function getWarnings() : array | ||||
|     { | ||||
|         return $this->warnings; | ||||
|     } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 RafficMohammed
					RafficMohammed