LICENSE000064400000002055151743411410005554 0ustar00Copyright (c) 2013-2016 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 in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. composer.json000064400000001744151743411410007275 0ustar00{ "name": "egulias/email-validator", "description": "A library for validating emails against several RFCs", "homepage": "https://github.com/egulias/EmailValidator", "keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"], "license": "MIT", "authors": [ {"name": "Eduardo Gulias Davis"} ], "extra": { "branch-alias": { "dev-master": "2.1.x-dev" } }, "require": { "php": ">=5.5", "doctrine/lexer": "^1.0.1", "symfony/polyfill-intl-idn": "^1.10" }, "require-dev": { "dominicsayers/isemail": "^3.0.7", "phpunit/phpunit": "^4.8.36|^7.5.15", "satooshi/php-coveralls": "^1.0.1" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, "autoload": { "psr-4": { "Egulias\\EmailValidator\\": "src" } }, "autoload-dev": { "psr-4": { "Egulias\\EmailValidator\\Tests\\": "tests" } } } src/EmailLexer.php000064400000014165151743411410010103 0ustar00 self::S_OPENPARENTHESIS, ')' => self::S_CLOSEPARENTHESIS, '<' => self::S_LOWERTHAN, '>' => self::S_GREATERTHAN, '[' => self::S_OPENBRACKET, ']' => self::S_CLOSEBRACKET, ':' => self::S_COLON, ';' => self::S_SEMICOLON, '@' => self::S_AT, '\\' => self::S_BACKSLASH, '/' => self::S_SLASH, ',' => self::S_COMMA, '.' => self::S_DOT, '"' => self::S_DQUOTE, '-' => self::S_HYPHEN, '::' => self::S_DOUBLECOLON, ' ' => self::S_SP, "\t" => self::S_HTAB, "\r" => self::S_CR, "\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, ); /** * @var bool */ protected $hasInvalidTokens = false; /** * @var array * * @psalm-var array{value:string, type:null|int, position:int}|array */ protected $previous = []; /** * The last matched/seen token. * * @var array * * @psalm-var array{value:string, type:null|int, position:int} */ public $token; /** * The next token in the input. * * @var array|null */ public $lookahead; /** * @psalm-var array{value:'', type:null, position:0} */ private static $nullToken = [ 'value' => '', 'type' => null, 'position' => 0, ]; public function __construct() { $this->previous = $this->token = self::$nullToken; $this->lookahead = null; } /** * @return void */ public function reset() { $this->hasInvalidTokens = false; parent::reset(); $this->previous = $this->token = self::$nullToken; } /** * @return bool */ public function hasInvalidTokens() { return $this->hasInvalidTokens; } /** * @param int $type * @throws \UnexpectedValueException * @return boolean * * @psalm-suppress InvalidScalarArgument */ public function find($type) { $search = clone $this; $search->skipUntil($type); if (!$search->lookahead) { throw new \UnexpectedValueException($type . ' not found'); } return true; } /** * getPrevious * * @return array */ public function getPrevious() { return $this->previous; } /** * moveNext * * @return boolean */ public function moveNext() { $this->previous = $this->token; $hasNext = parent::moveNext(); $this->token = $this->token ?: self::$nullToken; 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. * * @param string $value * @throws \InvalidArgumentException * @return integer */ protected function getType(&$value) { if ($this->isNullType($value)) { return self::C_NUL; } if ($this->isValid($value)) { return $this->charValue[$value]; } if ($this->isUTF8Invalid($value)) { $this->hasInvalidTokens = true; return self::INVALID; } return self::GENERIC; } /** * @param string $value * * @return bool */ protected function isValid($value) { if (isset($this->charValue[$value])) { return true; } return false; } /** * @param string $value * @return bool */ protected function isNullType($value) { if ($value === "\0") { return true; } return false; } /** * @param string $value * @return bool */ protected function isUTF8Invalid($value) { if (preg_match('/\p{Cc}+/u', $value)) { return true; } return false; } /** * @return string */ protected function getModifiers() { return 'iu'; } } src/EmailParser.php000064400000005652151743411410010261 0ustar00 */ class EmailParser { const EMAIL_MAX_LENGTH = 254; /** * @var array */ protected $warnings = []; /** * @var string */ protected $domainPart = ''; /** * @var string */ protected $localPart = ''; /** * @var EmailLexer */ protected $lexer; /** * @var LocalPart */ protected $localPartParser; /** * @var DomainPart */ protected $domainPartParser; public function __construct(EmailLexer $lexer) { $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); $this->addLongEmailWarning($this->localPart, $this->domainPart); return $this->warnings; } /** * @return string */ public function getParsedDomainPart() { return $this->domainPart; } /** * @param string $email */ protected function setParts($email) { $parts = explode('@', $email); $this->domainPart = $this->domainPartParser->getDomainPart(); $this->localPart = $parts[0]; } /** * @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) { if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) { $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); } } } src/EmailValidator.php000064400000002330151743411410010740 0ustar00lexer = new EmailLexer(); } /** * @param string $email * @param EmailValidation $emailValidation * @return bool */ public function isValid($email, EmailValidation $emailValidation) { $isValid = $emailValidation->isValid($email, $this->lexer); $this->warnings = $emailValidation->getWarnings(); $this->error = $emailValidation->getError(); return $isValid; } /** * @return boolean */ public function hasWarnings() { return !empty($this->warnings); } /** * @return array */ public function getWarnings() { return $this->warnings; } /** * @return InvalidEmail|null */ public function getError() { return $this->error; } } src/Exception/AtextAfterCFWS.php000064400000000245151743411410012536 0ustar00lexer->moveNext(); $this->performDomainStartChecks(); $domain = $this->doParseDomainPart(); $prev = $this->lexer->getPrevious(); $length = strlen($domain); if ($prev['type'] === EmailLexer::S_DOT) { throw new DotAtEnd(); } if ($prev['type'] === EmailLexer::S_HYPHEN) { throw new DomainHyphened(); } if ($length > self::DOMAIN_MAX_LENGTH) { $this->warnings[DomainTooLong::CODE] = new DomainTooLong(); } if ($prev['type'] === EmailLexer::S_CR) { throw new CRLFAtTheEnd(); } $this->domainPart = $domain; } private function performDomainStartChecks() { $this->checkInvalidTokensAfterAT(); $this->checkEmptyDomain(); if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); $this->parseDomainComments(); } } private function checkEmptyDomain() { $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(); } } private function checkInvalidTokensAfterAT() { if ($this->lexer->token['type'] === EmailLexer::S_DOT) { throw new DotAtStart(); } if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) { throw new DomainHyphened(); } } /** * @return string */ public function getDomainPart() { return $this->domainPart; } /** * @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() { $domain = ''; $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--; } } if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { if ($openedParenthesis === 0) { throw new UnopenedComment(); } else { $openedParenthesis--; } } $this->checkConsecutiveDots(); $this->checkDomainPartExceptions($prev); if ($this->hasBrackets()) { $this->parseDomainLiteral(); } $this->checkLabelLength($prev); if ($this->isFWS()) { $this->parseFWS(); } $domain .= $this->lexer->token['value']; $this->lexer->moveNext(); } while (null !== $this->lexer->token['type']); return $domain; } private function checkNotAllowedChars(array $token) { $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; if (isset($notAllowed[$token['type']])) { throw new CharNotAllowed(); } } /** * @return string|false */ protected function parseDomainLiteral() { 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(); } } return $this->doParseDomainLiteral(); } /** * @return string|false */ protected function doParseDomainLiteral() { $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_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_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) { throw new DomainHyphened(); } if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::GENERIC)) { throw new ExpectingATEXT(); } } /** * @return bool */ protected function hasBrackets() { if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) { return false; } try { $this->lexer->find(EmailLexer::S_CLOSEBRACKET); } catch (\RuntimeException $e) { throw new ExpectingDomainLiteralClose(); } return true; } protected function checkLabelLength(array $prev) { if ($this->lexer->token['type'] === EmailLexer::S_DOT && $prev['type'] === EmailLexer::GENERIC && strlen($prev['value']) > 63 ) { $this->warnings[LabelTooLong::CODE] = new LabelTooLong(); } } protected function parseDomainComments() { $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]) { $this->warnings[TLD::CODE] = new TLD(); } } } src/Parser/LocalPart.php000064400000010731151743411410011164 0ustar00lexer->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(); } $closingQuote = $this->checkDQUOTE($closingQuote); if ($closingQuote && $parseDQuote) { $parseDQuote = $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(); } $openedParenthesis--; } $this->checkConsecutiveDots(); if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_AT) ) { throw new DotAtEnd(); } $this->warnEscaping(); $this->isInvalidToken($this->lexer->token, $closingQuote); if ($this->isFWS()) { $this->parseFWS(); } $totalLength += strlen($this->lexer->token['value']); $this->lexer->moveNext(); } if ($totalLength > LocalTooLong::LOCAL_PART_LENGTH) { $this->warnings[LocalTooLong::CODE] = new LocalTooLong(); } } /** * @return bool */ protected function parseDoubleQuote() { $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(); } } $prev = $this->lexer->getPrevious(); if ($prev['type'] === EmailLexer::S_BACKSLASH) { if (!$this->checkDQUOTE(false)) { throw new UnclosedQuotedString(); } } if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) { throw new ExpectingAT(); } return $parseAgain; } /** * @param bool $closingQuote */ protected function isInvalidToken(array $token, $closingQuote) { $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(); } } } src/Parser/Parser.php000064400000015335151743411410010544 0ustar00lexer = $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(); } } } src/Validation/DNSCheckValidation.php000064400000003672151743411410013544 0ustar00checkDNS($host); } public function getError() { return $this->error; } public function getWarnings() { return $this->warnings; } /** * @param string $host * * @return bool */ protected function checkDNS($host) { $variant = INTL_IDNA_VARIANT_2003; if ( defined('INTL_IDNA_VARIANT_UTS46') ) { $variant = INTL_IDNA_VARIANT_UTS46; } $host = rtrim(idn_to_ascii($host, IDNA_DEFAULT, $variant), '.') . '.'; $Aresult = true; $MXresult = checkdnsrr($host, 'MX'); if (!$MXresult) { $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord(); $Aresult = checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA'); if (!$Aresult) { $this->error = new NoDNSRecord(); } } return $MXresult || $Aresult; } } src/Validation/EmailValidation.php000064400000001357151743411410013207 0ustar00errors = $errors; parent::__construct(); } /** * @return InvalidEmail[] */ public function getErrors() { return $this->errors; } } src/Validation/MultipleValidationWithAnd.php000064400000005611151743411410015227 0ustar00validations = $validations; $this->mode = $mode; } /** * {@inheritdoc} */ public function isValid($email, EmailLexer $emailLexer) { $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 ($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) { if (null !== $possibleError) { $errors[] = $possibleError; } return $errors; } /** * @param bool $result * * @return bool */ private function shouldStop($result) { return !$result && $this->mode === self::STOP_ON_ERROR; } /** * Returns the validation errors. * * @return MultipleErrors|null */ public function getError() { return $this->error; } /** * {@inheritdoc} */ public function getWarnings() { return $this->warnings; } } src/Validation/NoRFCWarningsValidation.php000064400000001437151743411410014577 0ustar00getWarnings())) { return true; } $this->error = new RFCWarnings(); return false; } /** * {@inheritdoc} */ public function getError() { return $this->error ?: parent::getError(); } } src/Validation/RFCValidation.php000064400000001707151743411410012571 0ustar00parser = new EmailParser($emailLexer); try { $this->parser->parse((string)$email); } catch (InvalidEmail $invalid) { $this->error = $invalid; return false; } $this->warnings = $this->parser->getWarnings(); return true; } public function getError() { return $this->error; } public function getWarnings() { return $this->warnings; } } src/Validation/SpoofCheckValidation.php000064400000002113151743411410014173 0ustar00setChecks(Spoofchecker::SINGLE_SCRIPT); if ($checker->isSuspicious($email)) { $this->error = new SpoofEmail(); } return $this->error === null; } /** * @return InvalidEmail|null */ public function getError() { return $this->error; } public function getWarnings() { return []; } } src/Warning/AddressLiteral.php000064400000000373151743411410012357 0ustar00message = 'Address literal in domain part'; $this->rfcNumber = 5321; } } src/Warning/CFWSNearAt.php000064400000000335151743411410011310 0ustar00message = "Deprecated folding white space near @"; } } src/Warning/CFWSWithFWS.php000064400000000355151743411410011433 0ustar00message = 'Folding whites space followed by folding white space'; } } src/Warning/Comment.php000064400000000321151743411410011050 0ustar00message = "Comments found in this email"; } } src/Warning/DeprecatedComment.php000064400000000322151743411410013032 0ustar00message = 'Deprecated comments'; } } src/Warning/DomainLiteral.php000064400000000352151743411410012176 0ustar00message = 'Domain Literal'; $this->rfcNumber = 5322; } } src/Warning/DomainTooLong.php000064400000000402151743411410012157 0ustar00message = 'Domain is too long, exceeds 255 chars'; $this->rfcNumber = 5322; } } src/Warning/EmailTooLong.php000064400000000436151743411410012006 0ustar00message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH; } } src/Warning/IPV6BadChar.php000064400000000371151743411410011404 0ustar00message = 'Bad char in IPV6 domain literal'; $this->rfcNumber = 5322; } } src/Warning/IPV6ColonEnd.php000064400000000404151743411410011616 0ustar00message = ':: found at the end of the domain literal'; $this->rfcNumber = 5322; } } src/Warning/IPV6ColonStart.php000064400000000410151743411410012202 0ustar00message = ':: found at the start of the domain literal'; $this->rfcNumber = 5322; } } src/Warning/IPV6Deprecated.php000064400000000364151743411410012162 0ustar00message = 'Deprecated form of IPV6'; $this->rfcNumber = 5321; } } src/Warning/IPV6DoubleColon.php000064400000000377151743411410012333 0ustar00message = 'Double colon found after IPV6 tag'; $this->rfcNumber = 5322; } } src/Warning/IPV6GroupCount.php000064400000000372151743411410012226 0ustar00message = 'Group count is not IPV6 valid'; $this->rfcNumber = 5322; } } src/Warning/IPV6MaxGroups.php000064400000000415151743411410012044 0ustar00message = 'Reached the maximum number of IPV6 groups allowed'; $this->rfcNumber = 5321; } } src/Warning/LabelTooLong.php000064400000000351151743411410011772 0ustar00message = 'Label too long'; $this->rfcNumber = 5322; } } src/Warning/LocalTooLong.php000064400000000456151743411410012013 0ustar00message = 'Local part is too long, exceeds 64 chars (octets)'; $this->rfcNumber = 5322; } } src/Warning/NoDNSMXRecord.php000064400000000404151743411410011775 0ustar00message = 'No MX DSN record was found for this email'; $this->rfcNumber = 5321; } } src/Warning/ObsoleteDTEXT.php000064400000000374151743411410012043 0ustar00rfcNumber = 5322; $this->message = 'Obsolete DTEXT in domain literal'; } } src/Warning/QuotedPart.php000064400000000536151743411410011546 0ustar00message = "Deprecated Quoted String found between $prevToken and $postToken"; } } src/Warning/QuotedString.php000064400000000525151743411410012104 0ustar00message = "Quoted String found between $prevToken and $postToken"; } } src/Warning/TLD.php000064400000000274151743411410010100 0ustar00message = "RFC5321, TLD"; } } src/Warning/Warning.php000064400000001270151743411410011057 0ustar00message; } /** * @return int */ public function code() { return self::CODE; } /** * @return int */ public function RFCNumber() { return $this->rfcNumber; } public function __toString() { return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE; } }