pax_global_header00006660000000000000000000000064136216243350014517gustar00rootroot0000000000000052 comment=20bfb62d69a2d835493a295cc1c861dbac78c6fd php-email-validator-2.1.17/000077500000000000000000000000001362162433500154465ustar00rootroot00000000000000php-email-validator-2.1.17/.coveralls.yml000066400000000000000000000001141362162433500202350ustar00rootroot00000000000000service_name: travis-ci src_dir: . coverage_clover: build/logs/clover*.xml php-email-validator-2.1.17/.gitignore000066400000000000000000000000441362162433500174340ustar00rootroot00000000000000.idea composer.lock report/ vendor/ php-email-validator-2.1.17/.travis.yml000066400000000000000000000015211362162433500175560ustar00rootroot00000000000000language: php matrix: include: - php: 5.5.9 dist: trusty env: deps=low - php: 5.5 dist: trusty - php: 5.6 env: dist: xenial - php: 7.0 dist: xenial - php: 7.1 env: - psalm=yes dist: bionic - php: 7.2 env: - psalm=yes dist: bionic - php: 7.3 dist: bionic env: - psalm=yes - php: 7.4 env: - psalm=yes dist: bionic install: - if [ "$deps" = "low" ]; then composer update --prefer-lowest; else composer install; fi - if [ "$psalm" = "yes" ]; then composer require --dev vimeo/psalm; fi before_script: - mkdir -p build/logs script: - vendor/bin/phpunit --coverage-clover build/logs/clover.xml - if [ "$psalm" = "yes" ]; then vendor/bin/psalm; fi after_script: - php vendor/bin/coveralls php-email-validator-2.1.17/EmailValidator/000077500000000000000000000000001362162433500203435ustar00rootroot00000000000000php-email-validator-2.1.17/EmailValidator/EmailLexer.php000066400000000000000000000141651362162433500231120ustar00rootroot00000000000000 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'; } } php-email-validator-2.1.17/EmailValidator/EmailParser.php000066400000000000000000000056521362162433500232700ustar00rootroot00000000000000 */ 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(); } } } php-email-validator-2.1.17/EmailValidator/EmailValidator.php000066400000000000000000000023301362162433500237470ustar00rootroot00000000000000lexer = 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; } } php-email-validator-2.1.17/EmailValidator/Exception/000077500000000000000000000000001362162433500223015ustar00rootroot00000000000000php-email-validator-2.1.17/EmailValidator/Exception/AtextAfterCFWS.php000066400000000000000000000002451362162433500255450ustar00rootroot00000000000000lexer->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(); } } } php-email-validator-2.1.17/EmailValidator/Parser/LocalPart.php000066400000000000000000000107311362162433500241730ustar00rootroot00000000000000lexer->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(); } } } php-email-validator-2.1.17/EmailValidator/Parser/Parser.php000066400000000000000000000154011362162433500235450ustar00rootroot00000000000000lexer = $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(); } } } php-email-validator-2.1.17/EmailValidator/Validation/000077500000000000000000000000001362162433500224355ustar00rootroot00000000000000php-email-validator-2.1.17/EmailValidator/Validation/DNSCheckValidation.php000066400000000000000000000036721362162433500265530ustar00rootroot00000000000000checkDNS($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; } } php-email-validator-2.1.17/EmailValidator/Validation/EmailValidation.php000066400000000000000000000013571362162433500262160ustar00rootroot00000000000000errors = $errors; parent::__construct(); } /** * @return InvalidEmail[] */ public function getErrors() { return $this->errors; } } php-email-validator-2.1.17/EmailValidator/Validation/MultipleValidationWithAnd.php000066400000000000000000000056111362162433500302360ustar00rootroot00000000000000validations = $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; } } php-email-validator-2.1.17/EmailValidator/Validation/NoRFCWarningsValidation.php000066400000000000000000000014371362162433500276060ustar00rootroot00000000000000getWarnings())) { return true; } $this->error = new RFCWarnings(); return false; } /** * {@inheritdoc} */ public function getError() { return $this->error ?: parent::getError(); } } php-email-validator-2.1.17/EmailValidator/Validation/RFCValidation.php000066400000000000000000000017071362162433500256000ustar00rootroot00000000000000parser = 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; } } php-email-validator-2.1.17/EmailValidator/Validation/SpoofCheckValidation.php000066400000000000000000000021131362162433500272020ustar00rootroot00000000000000setChecks(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 []; } } php-email-validator-2.1.17/EmailValidator/Warning/000077500000000000000000000000001362162433500217505ustar00rootroot00000000000000php-email-validator-2.1.17/EmailValidator/Warning/AddressLiteral.php000066400000000000000000000003731362162433500253660ustar00rootroot00000000000000message = 'Address literal in domain part'; $this->rfcNumber = 5321; } } php-email-validator-2.1.17/EmailValidator/Warning/CFWSNearAt.php000066400000000000000000000003351362162433500243170ustar00rootroot00000000000000message = "Deprecated folding white space near @"; } } php-email-validator-2.1.17/EmailValidator/Warning/CFWSWithFWS.php000066400000000000000000000003551362162433500244420ustar00rootroot00000000000000message = 'Folding whites space followed by folding white space'; } } php-email-validator-2.1.17/EmailValidator/Warning/Comment.php000066400000000000000000000003211362162433500240570ustar00rootroot00000000000000message = "Comments found in this email"; } } php-email-validator-2.1.17/EmailValidator/Warning/DeprecatedComment.php000066400000000000000000000003221362162433500260410ustar00rootroot00000000000000message = 'Deprecated comments'; } } php-email-validator-2.1.17/EmailValidator/Warning/DomainLiteral.php000066400000000000000000000003521362162433500252050ustar00rootroot00000000000000message = 'Domain Literal'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/DomainTooLong.php000066400000000000000000000004021362162433500251660ustar00rootroot00000000000000message = 'Domain is too long, exceeds 255 chars'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/EmailTooLong.php000066400000000000000000000004361362162433500250150ustar00rootroot00000000000000message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6BadChar.php000066400000000000000000000003711362162433500244130ustar00rootroot00000000000000message = 'Bad char in IPV6 domain literal'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6ColonEnd.php000066400000000000000000000004041362162433500246250ustar00rootroot00000000000000message = ':: found at the end of the domain literal'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6ColonStart.php000066400000000000000000000004101362162433500252110ustar00rootroot00000000000000message = ':: found at the start of the domain literal'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6Deprecated.php000066400000000000000000000003641362162433500251710ustar00rootroot00000000000000message = 'Deprecated form of IPV6'; $this->rfcNumber = 5321; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6DoubleColon.php000066400000000000000000000003771362162433500253420ustar00rootroot00000000000000message = 'Double colon found after IPV6 tag'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6GroupCount.php000066400000000000000000000003721362162433500252350ustar00rootroot00000000000000message = 'Group count is not IPV6 valid'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/IPV6MaxGroups.php000066400000000000000000000004151362162433500250530ustar00rootroot00000000000000message = 'Reached the maximum number of IPV6 groups allowed'; $this->rfcNumber = 5321; } } php-email-validator-2.1.17/EmailValidator/Warning/LabelTooLong.php000066400000000000000000000003511362162433500250010ustar00rootroot00000000000000message = 'Label too long'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/LocalTooLong.php000066400000000000000000000004561362162433500250220ustar00rootroot00000000000000message = 'Local part is too long, exceeds 64 chars (octets)'; $this->rfcNumber = 5322; } } php-email-validator-2.1.17/EmailValidator/Warning/NoDNSMXRecord.php000066400000000000000000000004041362162433500250040ustar00rootroot00000000000000message = 'No MX DSN record was found for this email'; $this->rfcNumber = 5321; } } php-email-validator-2.1.17/EmailValidator/Warning/ObsoleteDTEXT.php000066400000000000000000000003741362162433500250520ustar00rootroot00000000000000rfcNumber = 5322; $this->message = 'Obsolete DTEXT in domain literal'; } } php-email-validator-2.1.17/EmailValidator/Warning/QuotedPart.php000066400000000000000000000005361362162433500245550ustar00rootroot00000000000000message = "Deprecated Quoted String found between $prevToken and $postToken"; } } php-email-validator-2.1.17/EmailValidator/Warning/QuotedString.php000066400000000000000000000005251362162433500251130ustar00rootroot00000000000000message = "Quoted String found between $prevToken and $postToken"; } } php-email-validator-2.1.17/EmailValidator/Warning/TLD.php000066400000000000000000000002741362162433500231070ustar00rootroot00000000000000message = "RFC5321, TLD"; } } php-email-validator-2.1.17/EmailValidator/Warning/Warning.php000066400000000000000000000012701362162433500240660ustar00rootroot00000000000000message; } /** * @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; } } php-email-validator-2.1.17/LICENSE000066400000000000000000000020551362162433500164550ustar00rootroot00000000000000Copyright (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. php-email-validator-2.1.17/README.md000066400000000000000000000077111362162433500167330ustar00rootroot00000000000000# EmailValidator [![Build Status](https://travis-ci.org/egulias/EmailValidator.svg?branch=master)](https://travis-ci.org/egulias/EmailValidator) [![Coverage Status](https://coveralls.io/repos/egulias/EmailValidator/badge.svg?branch=master)](https://coveralls.io/r/egulias/EmailValidator?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6/small.png)](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6) ============================= ## Suported RFCs ## This library aims to support: RFC 5321, 5322, 6530, 6531, 6532. ## Requirements ## * [Composer](https://getcomposer.org) is required for installation * [Spoofchecking](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) and [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/DNSCheckValidation.php) validation requires that your PHP system has the [PHP Internationalization Libraries](https://php.net/manual/en/book.intl.php) (also known as PHP Intl) ## Installation ## Run the command below to install via Composer ```shell composer require egulias/email-validator ``` ## Getting Started ## `EmailValidator`requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations). A basic example with the RFC validation ```php isValid("example@example.com", new RFCValidation()); //true ``` ### Available validations ### 1. [RFCValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/RFCValidation.php) 2. [NoRFCWarningsValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/NoRFCWarningsValidation.php) 3. [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/DNSCheckValidation.php) 4. [SpoofCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) 5. [MultipleValidationWithAnd](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/MultipleValidationWithAnd.php) 6. [Your own validation](#how-to-extend) `MultipleValidationWithAnd` It is a validation that operates over other validations performing a logical and (&&) over the result of each validation. ```php isValid("example@example.com", $multipleValidations); //true ``` ### How to extend ### It's easy! You just need to implement [EmailValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/EmailValidation.php) and you can use your own validation. ## Other Contributors ## (You can find current contributors [here](https://github.com/egulias/EmailValidator/graphs/contributors)) As this is a port from another library and work, here are other people related to the previous one: * Ricard Clau [@ricardclau](https://github.com/ricardclau): Performance against PHP built-in filter_var * Josepf Bielawski [@stloyd](https://github.com/stloyd): For its first re-work of Dominic's lib * Dominic Sayers [@dominicsayers](https://github.com/dominicsayers): The original isemail function ## License ## Released under the MIT License attached with this code. php-email-validator-2.1.17/Tests/000077500000000000000000000000001362162433500165505ustar00rootroot00000000000000php-email-validator-2.1.17/Tests/EmailValidator/000077500000000000000000000000001362162433500214455ustar00rootroot00000000000000php-email-validator-2.1.17/Tests/EmailValidator/EmailLexerTest.php000066400000000000000000000120741362162433500250510ustar00rootroot00000000000000assertInstanceOf('Doctrine\Common\Lexer\AbstractLexer', $lexer); } /** * @dataProvider getTokens * */ public function testLexerTokens($str, $token) { $lexer = new EmailLexer(); $lexer->setInput($str); $lexer->moveNext(); $lexer->moveNext(); $this->assertEquals($token, $lexer->token['type']); } public function testLexerParsesMultipleSpaces() { $lexer = new EmailLexer(); $lexer->setInput(' '); $lexer->moveNext(); $lexer->moveNext(); $this->assertEquals(EmailLexer::S_SP, $lexer->token['type']); $lexer->moveNext(); $this->assertEquals(EmailLexer::S_SP, $lexer->token['type']); } /** * @dataProvider invalidUTF8CharsProvider */ public function testLexerParsesInvalidUTF8($char) { $lexer = new EmailLexer(); $lexer->setInput($char); $lexer->moveNext(); $lexer->moveNext(); $this->assertEquals(EmailLexer::INVALID, $lexer->token['type']); } public function invalidUTF8CharsProvider() { $chars = array(); for ($i = 0; $i < 0x100; ++$i) { $c = $this->utf8Chr($i); if (preg_match('/(?=\p{Cc})(?=[^\t\n\n\r])/u', $c) && !preg_match('/\x{0000}/u', $c)) { $chars[] = array($c); } } return $chars; } protected function utf8Chr($code_point) { if ($code_point < 0 || 0x10FFFF < $code_point || (0xD800 <= $code_point && $code_point <= 0xDFFF)) { return ''; } if ($code_point < 0x80) { $hex[0] = $code_point; $ret = chr($hex[0]); } elseif ($code_point < 0x800) { $hex[0] = 0x1C0 | $code_point >> 6; $hex[1] = 0x80 | $code_point & 0x3F; $ret = chr($hex[0]).chr($hex[1]); } elseif ($code_point < 0x10000) { $hex[0] = 0xE0 | $code_point >> 12; $hex[1] = 0x80 | $code_point >> 6 & 0x3F; $hex[2] = 0x80 | $code_point & 0x3F; $ret = chr($hex[0]).chr($hex[1]).chr($hex[2]); } else { $hex[0] = 0xF0 | $code_point >> 18; $hex[1] = 0x80 | $code_point >> 12 & 0x3F; $hex[2] = 0x80 | $code_point >> 6 & 0x3F; $hex[3] = 0x80 | $code_point & 0x3F; $ret = chr($hex[0]).chr($hex[1]).chr($hex[2]).chr($hex[3]); } return $ret; } public function testLexerForTab() { $lexer = new EmailLexer(); $lexer->setInput("foo\tbar"); $lexer->moveNext(); $lexer->skipUntil(EmailLexer::S_HTAB); $lexer->moveNext(); $this->assertEquals(EmailLexer::S_HTAB, $lexer->token['type']); } public function testLexerForUTF8() { $lexer = new EmailLexer(); $lexer->setInput("áÇ@bar.com"); $lexer->moveNext(); $lexer->moveNext(); $this->assertEquals(EmailLexer::GENERIC, $lexer->token['type']); $lexer->moveNext(); $this->assertEquals(EmailLexer::GENERIC, $lexer->token['type']); } public function testLexerSearchToken() { $lexer = new EmailLexer(); $lexer->setInput("foo\tbar"); $lexer->moveNext(); $this->assertTrue($lexer->find(EmailLexer::S_HTAB)); } public function getTokens() { return array( array("foo", EmailLexer::GENERIC), array("\r", EmailLexer::S_CR), array("\t", EmailLexer::S_HTAB), array("\r\n", EmailLexer::CRLF), array("\n", EmailLexer::S_LF), array(" ", EmailLexer::S_SP), array("@", EmailLexer::S_AT), array("IPv6", EmailLexer::S_IPV6TAG), array("::", EmailLexer::S_DOUBLECOLON), array(":", EmailLexer::S_COLON), array(".", EmailLexer::S_DOT), array("\"", EmailLexer::S_DQUOTE), array("-", EmailLexer::S_HYPHEN), array("\\", EmailLexer::S_BACKSLASH), array("/", EmailLexer::S_SLASH), array("(", EmailLexer::S_OPENPARENTHESIS), array(")", EmailLexer::S_CLOSEPARENTHESIS), array('<', EmailLexer::S_LOWERTHAN), array('>', EmailLexer::S_GREATERTHAN), array('[', EmailLexer::S_OPENBRACKET), array(']', EmailLexer::S_CLOSEBRACKET), array(';', EmailLexer::S_SEMICOLON), array(',', EmailLexer::S_COMMA), array('<', EmailLexer::S_LOWERTHAN), array('>', EmailLexer::S_GREATERTHAN), array('{', EmailLexer::S_OPENQBRACKET), array('}', EmailLexer::S_CLOSEQBRACKET), array('', EmailLexer::S_EMPTY), array(chr(31), EmailLexer::INVALID), array(chr(226), EmailLexer::GENERIC), array(chr(0), EmailLexer::C_NUL) ); } } php-email-validator-2.1.17/Tests/EmailValidator/EmailValidatorTest.php000066400000000000000000000025451362162433500257210ustar00rootroot00000000000000getMockBuilder(EmailValidation::class)->getMock(); $validation->expects($this->once())->method("isValid")->willReturn(true); $validation->expects($this->once())->method("getWarnings")->willReturn([]); $validation->expects($this->once())->method("getError")->willReturn(null); $this->assertTrue($validator->isValid("example@example.com", $validation)); } public function testMultipleValidation() { $validator = new EmailValidator(); $validation = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation->expects($this->once())->method("isValid")->willReturn(true); $validation->expects($this->once())->method("getWarnings")->willReturn([]); $validation->expects($this->once())->method("getError")->willReturn(null); $multiple = new MultipleValidationWithAnd([$validation]); $this->assertTrue($validator->isValid("example@example.com", $multiple)); } } php-email-validator-2.1.17/Tests/EmailValidator/Validation/000077500000000000000000000000001362162433500235375ustar00rootroot00000000000000php-email-validator-2.1.17/Tests/EmailValidator/Validation/DNSCheckValidationTest.php000066400000000000000000000036231362162433500305110ustar00rootroot00000000000000assertTrue($validation->isValid($validEmail, new EmailLexer())); } public function testInvalidDNS() { $validation = new DNSCheckValidation(); $this->assertFalse($validation->isValid("example@invalid.example.com", new EmailLexer())); } public function testDNSWarnings() { $validation = new DNSCheckValidation(); $expectedWarnings = [NoDNSMXRecord::CODE => new NoDNSMXRecord()]; $validation->isValid("example@invalid.example.com", new EmailLexer()); $this->assertEquals($expectedWarnings, $validation->getWarnings()); } public function testNoDNSError() { $validation = new DNSCheckValidation(); $expectedError = new NoDNSRecord(); $validation->isValid("example@invalid.example.com", new EmailLexer()); $this->assertEquals($expectedError, $validation->getError()); } } php-email-validator-2.1.17/Tests/EmailValidator/Validation/IsEmailFunctionTests.php000066400000000000000000000023711362162433500303270ustar00rootroot00000000000000assertFalse($validator->isValid($email, $validations), "Tested email " . $email); } public function isEmailTestSuite() { $testSuite = dirname(__FILE__) . '/../../resources/is_email_tests.xml'; $document = new \DOMDocument(); $document->load($testSuite); $elements = $document->getElementsByTagName('test'); $tests = []; foreach($elements as $testElement) { $childNode = $testElement->childNodes; $tests[][] = ($childNode->item(1)->getAttribute('value')); } return $tests; } } php-email-validator-2.1.17/Tests/EmailValidator/Validation/MultipleValidationWithAndTest.php000066400000000000000000000164171362162433500322060ustar00rootroot00000000000000getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock(); $validationTrue->expects($this->any())->method("isValid")->willReturn(true); $validationTrue->expects($this->any())->method("getWarnings")->willReturn([]); $validationFalse = $this->getMockBuilder(EmailValidation::class)->getMock(); $validationFalse->expects($this->any())->method("isValid")->willReturn(false); $validationFalse->expects($this->any())->method("getWarnings")->willReturn([]); $multipleValidation = new MultipleValidationWithAnd([$validationTrue, $validationFalse]); $this->assertFalse($multipleValidation->isValid("exmpale@example.com", $lexer)); } /** * @expectedException \Egulias\EmailValidator\Validation\Exception\EmptyValidationList */ public function testEmptyListIsNotAllowed() { new MultipleValidationWithAnd([]); } public function testValidationIsValid() { $lexer = new EmailLexer(); $validation = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation->expects($this->any())->method("isValid")->willReturn(true); $validation->expects($this->once())->method("getWarnings")->willReturn([]); $multipleValidation = new MultipleValidationWithAnd([$validation]); $this->assertTrue($multipleValidation->isValid("example@example.com", $lexer)); $this->assertNull($multipleValidation->getError()); } public function testAccumulatesWarnings() { $warnings1 = [ AddressLiteral::CODE => new AddressLiteral() ]; $warnings2 = [ DomainLiteral::CODE => new DomainLiteral() ]; $expectedResult = array_merge($warnings1, $warnings2); $lexer = new EmailLexer(); $validation1 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock(); $validation1->expects($this->any())->method("isValid")->willReturn(true); $validation1->expects($this->once())->method("getWarnings")->willReturn($warnings1); $validation2 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation2->expects($this->any())->method("isValid")->willReturn(false); $validation2->expects($this->once())->method("getWarnings")->willReturn($warnings2); $multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2]); $multipleValidation->isValid("example@example.com", $lexer); $this->assertEquals($expectedResult, $multipleValidation->getWarnings()); } public function testGathersAllTheErrors() { $error1 = new CommaInDomain(); $error2 = new NoDomainPart(); $expectedResult = new MultipleErrors([$error1, $error2]); $lexer = new EmailLexer(); $validation1 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation1->expects($this->once())->method("isValid")->willReturn(false); $validation1->expects($this->once())->method("getWarnings")->willReturn([]); $validation1->expects($this->once())->method("getError")->willReturn($error1); $validation2 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation2->expects($this->once())->method("isValid")->willReturn(false); $validation2->expects($this->once())->method("getWarnings")->willReturn([]); $validation2->expects($this->once())->method("getError")->willReturn($error2); $multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2]); $multipleValidation->isValid("example@example.com", $lexer); $this->assertEquals($expectedResult, $multipleValidation->getError()); } public function testStopsAfterFirstError() { $error1 = new CommaInDomain(); $error2 = new NoDomainPart(); $expectedResult = new MultipleErrors([$error1]); $lexer = new EmailLexer(); $validation1 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation1->expects($this->any())->method("isValid")->willReturn(false); $validation1->expects($this->once())->method("getWarnings")->willReturn([]); $validation1->expects($this->once())->method("getError")->willReturn($error1); $validation2 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation2->expects($this->any())->method("isValid")->willReturn(false); $validation2->expects($this->never())->method("getWarnings")->willReturn([]); $validation2->expects($this->never())->method("getError")->willReturn($error2); $multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2], MultipleValidationWithAnd::STOP_ON_ERROR); $multipleValidation->isValid("example@example.com", $lexer); $this->assertEquals($expectedResult, $multipleValidation->getError()); } public function testBreakOutOfLoopWhenError() { $error = new CommaInDomain(); $expectedResult = new MultipleErrors([$error]); $lexer = new EmailLexer(); $validation1 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation1->expects($this->any())->method("isValid")->willReturn(false); $validation1->expects($this->once())->method("getWarnings")->willReturn([]); $validation1->expects($this->once())->method("getError")->willReturn($error); $validation2 = $this->getMockBuilder(EmailValidation::class)->getMock(); $validation2->expects($this->never())->method("isValid"); $validation2->expects($this->never())->method("getWarnings"); $validation2->expects($this->never())->method("getError"); $multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2], MultipleValidationWithAnd::STOP_ON_ERROR); $multipleValidation->isValid("example@example.com", $lexer); $this->assertEquals($expectedResult, $multipleValidation->getError()); } public function testBreakoutOnInvalidEmail() { $lexer = new EmailLexer(); $validationNotCalled = $this->getMockBuilder(EmailValidation::class)->getMock(); $validationNotCalled->expects($this->never())->method("isValid"); $validationNotCalled->expects($this->never())->method("getWarnings"); $validationNotCalled->expects($this->never())->method("getError"); $multipleValidation = new MultipleValidationWithAnd([new RFCValidation(), $validationNotCalled], MultipleValidationWithAnd::STOP_ON_ERROR); $this->assertFalse($multipleValidation->isValid("invalid-email", $lexer)); } } php-email-validator-2.1.17/Tests/EmailValidator/Validation/NoRFCWarningsValidationTest.php000066400000000000000000000023061362162433500315440ustar00rootroot00000000000000assertFalse($validation->isValid('non-email-string', new EmailLexer())); $this->assertInstanceOf(NoDomainPart::class, $validation->getError()); } public function testEmailWithWarningsIsInvalid() { $validation = new NoRFCWarningsValidation(); $this->assertFalse($validation->isValid(str_repeat('x', 254).'@example.com', new EmailLexer())); // too long email $this->assertInstanceOf(RFCWarnings::class, $validation->getError()); } public function testEmailWithoutWarningsIsValid() { $validation = new NoRFCWarningsValidation(); $this->assertTrue($validation->isValid('example@example.com', new EmailLexer())); $this->assertNull($validation->getError()); } } php-email-validator-2.1.17/Tests/EmailValidator/Validation/RFCValidationTest.php000066400000000000000000000265601362162433500275460ustar00rootroot00000000000000validator = new RFCValidation(); $this->lexer = new EmailLexer(); } protected function tearDown() { $this->validator = null; } /** * @dataProvider getValidEmails */ public function testValidEmails($email) { $this->assertTrue($this->validator->isValid($email, $this->lexer)); } public function getValidEmails() { return array( ['â@iana.org'], ['fabien@symfony.com'], ['example@example.co.uk'], ['fabien_potencier@example.fr'], ['example@localhost'], ['fab\'ien@symfony.com'], ['fab\ ien@symfony.com'], ['example((example))@fakedfake.co.uk'], ['example@faked(fake).co.uk'], ['fabien+@symfony.com'], ['инфо@письмо.рф'], ['"username"@example.com'], ['"user,name"@example.com'], ['"user name"@example.com'], ['"user@name"@example.com'], ['"user\"name"@example.com'], ['"\a"@iana.org'], ['"test\ test"@iana.org'], ['""@iana.org'], ['"\""@iana.org'], ['müller@möller.de'], ['test@email*'], ['test@email!'], ['test@email&'], ['test@email^'], ['test@email%'], ['test@email$'], ["1500111@профи-инвест.рф"], ); } public function testInvalidUTF8Email() { $email = "\x80\x81\x82@\x83\x84\x85.\x86\x87\x88"; $this->assertFalse($this->validator->isValid($email, $this->lexer)); } /** * @dataProvider getInvalidEmails */ public function testInvalidEmails($email) { $this->assertFalse($this->validator->isValid($email, $this->lexer)); } public function getInvalidEmails() { return [ ['test@example.com test'], ['user name@example.com'], ['user name@example.com'], ['example.@example.co.uk'], ['example@example@example.co.uk'], ['(test_exampel@example.fr]'], ['example(example]example@example.co.uk'], ['.example@localhost'], ['ex\ample@localhost'], ['example@local\host'], ['example@localhost\\'], ['example@localhost.'], ['user name@example.com'], ['username@ example . com'], ['example@(fake].com'], ['example@(fake.com'], ['username@example,com'], ['usern,ame@example.com'], ['user[na]me@example.com'], ['"""@iana.org'], ['"\"@iana.org'], ['"test"test@iana.org'], ['"test""test"@iana.org'], ['"test"."test"@iana.org'], ['"test".test@iana.org'], ['"test"' . chr(0) . '@iana.org'], ['"test\"@iana.org'], [chr(226) . '@iana.org'], ['test@' . chr(226) . '.org'], ['\r\ntest@iana.org'], ['\r\n test@iana.org'], ['\r\n \r\ntest@iana.org'], ['\r\n \r\ntest@iana.org'], ['\r\n \r\n test@iana.org'], ['test@iana.org \r\n'], ['test@iana.org \r\n '], ['test@iana.org \r\n \r\n'], ['test@iana.org \r\n\r\n'], ['test@iana.org \r\n\r\n '], ['test@iana/icann.org'], ['test@foo;bar.com'], ['test;123@foobar.com'], ['test@example..com'], ['email.email@email."'], ['test@email>'], ['test@email<'], ['test@email{'], ['test@ '], ]; } /** * @dataProvider getInvalidEmailsWithErrors */ public function testInvalidEmailsWithErrorsCheck($error, $email) { $this->assertFalse($this->validator->isValid($email, $this->lexer)); $this->assertEquals($error, $this->validator->getError()); } public function getInvalidEmailsWithErrors() { return [ [new NoLocalPart(), '@example.co.uk'], [new NoDomainPart(), 'example@'], [new DomainHyphened(), 'example@example-.co.uk'], [new DomainHyphened(), 'example@example-'], [new ConsecutiveAt(), 'example@@example.co.uk'], [new ConsecutiveDot(), 'example..example@example.co.uk'], [new ConsecutiveDot(), 'example@example..co.uk'], [new ExpectingATEXT(), '@example.fr'], [new DotAtStart(), '.example@localhost'], [new DotAtStart(), 'example@.localhost'], [new DotAtEnd(), 'example@localhost.'], [new DotAtEnd(), 'example.@example.co.uk'], [new UnclosedComment(), '(example@localhost'], [new UnclosedQuotedString(), '"example@localhost'], [new ExpectingATEXT(), 'exa"mple@localhost'], [new UnclosedComment(), '(example@localhost'], [new UnopenedComment(), 'comment)example@localhost'], [new UnopenedComment(), 'example(comment))@localhost'], [new UnopenedComment(), 'example@comment)localhost'], [new UnopenedComment(), 'example@localhost(comment))'], [new UnopenedComment(), 'example@(comment))example.com'], //This was the original. But atext is not allowed after \n //array(EmailValidator::ERR_EXPECTING_ATEXT, "exampl\ne@example.co.uk"), [new AtextAfterCFWS(), "exampl\ne@example.co.uk"], [new ExpectingDTEXT(), "example@[[]"], [new AtextAfterCFWS(), "exampl\te@example.co.uk"], [new CRNoLF(), "example@exa\rmple.co.uk"], [new CRNoLF(), "example@[\r]"], [new CRNoLF(), "exam\rple@example.co.uk"], ]; } /** * @dataProvider getInvalidEmailsWithWarnings */ public function testInvalidEmailsWithWarningsCheck($expectedWarnings, $email) { $this->assertTrue($this->validator->isValid($email, $this->lexer)); $warnings = $this->validator->getWarnings(); $this->assertCount( count($warnings), $expectedWarnings, "Expected: " . implode(",", $expectedWarnings) . " and got " . implode(",", $warnings) ); foreach ($warnings as $warning) { $this->assertArrayHasKey($warning->code(), $expectedWarnings); } } public function getInvalidEmailsWithWarnings() { return [ [[CFWSNearAt::CODE], 'example @invalid.example.com'], [[CFWSNearAt::CODE], 'example@ invalid.example.com'], [[Comment::CODE], 'example@invalid.example(examplecomment).com'], [[Comment::CODE,CFWSNearAt::CODE], 'example(examplecomment)@invalid.example.com'], [[QuotedString::CODE, CFWSWithFWS::CODE,], "\"\t\"@invalid.example.com"], [[QuotedString::CODE, CFWSWithFWS::CODE,], "\"\r\"@invalid.example.com"], [[AddressLiteral::CODE,], 'example@[127.0.0.1]'], [[AddressLiteral::CODE,], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]'], [[AddressLiteral::CODE, IPV6Deprecated::CODE], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370::]'], [[AddressLiteral::CODE, IPV6MaxGroups::CODE,], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334::]'], [[AddressLiteral::CODE, IPV6DoubleColon::CODE,], 'example@[IPv6:1::1::1]'], [[ObsoleteDTEXT::CODE, DomainLiteral::CODE,], "example@[\n]"], [[DomainLiteral::CODE,], 'example@[::1]'], [[DomainLiteral::CODE,], 'example@[::123.45.67.178]'], [ [IPV6ColonStart::CODE, AddressLiteral::CODE, IPV6GroupCount::CODE,], 'example@[IPv6::2001:0db8:85a3:0000:0000:8a2e:0370:7334]' ], [ [AddressLiteral::CODE, IPV6BadChar::CODE,], 'example@[IPv6:z001:0db8:85a3:0000:0000:8a2e:0370:7334]' ], [ [AddressLiteral::CODE, IPV6ColonEnd::CODE,], 'example@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:]' ], [[QuotedString::CODE,], '"example"@invalid.example.com'], [ [LocalTooLong::CODE,], 'too_long_localpart_too_long_localpart_too_long_localpart_too_long_localpart@invalid.example.com' ], [ [LocalTooLong::CODE], 'too_long_localpart_too_long_localpart_123_too_long_localpart_too_long_localpart@example.com' ], [ [LabelTooLong::CODE,], 'example@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart.co.uk' ], [ [DomainTooLong::CODE, LabelTooLong::CODE,], 'example2@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocal'. 'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'. 'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart' ], [ [DomainTooLong::CODE, LabelTooLong::CODE,], 'example@toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocal'. 'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'. 'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpar' ], ]; } } php-email-validator-2.1.17/Tests/EmailValidator/Validation/SpoofCheckValidationTest.php000066400000000000000000000024671362162433500311600ustar00rootroot00000000000000markTestSkipped("Skipped for Travis CI since it is failing on this test for unknown reasons."); $validation = new SpoofCheckValidation(); $this->assertTrue($validation->isValid($email, new EmailLexer())); } public function testEmailWithSpoofsIsInvalid() { $validation = new SpoofCheckValidation(); $this->assertFalse($validation->isValid("Кириллица"."latin漢字"."ひらがな"."カタカナ", new EmailLexer())); } public function validUTF8EmailsProvider() { return [ // Cyrillic ['Кириллица@Кириллица'], // Latin + Han + Hiragana + Katakana ["latin漢字"."ひらがな"."カタカナ"."@example.com"], // Latin + Han + Hangul ["latin"."漢字"."조선말"."@example.com"], // Latin + Han + Bopomofo ["latin"."漢字"."ㄅㄆㄇㄈ"."@example.com"] ]; } } php-email-validator-2.1.17/Tests/Performance/000077500000000000000000000000001362162433500210115ustar00rootroot00000000000000php-email-validator-2.1.17/Tests/Performance/AgainstFilterVar.php000066400000000000000000000020321362162433500247240ustar00rootroot00000000000000isValid($testingMail, new \Egulias\EmailValidator\Validation\RFCValidation()); } $b = microtime(true); echo ($b - $a) . ' seconds with EmailValidator + instantiation' . PHP_EOL; $a = microtime(true); $validator = new EmailValidator(); for ($i = 0; $i < $iterations; $i++) { $isValid = $validator->isValid($testingMail, new \Egulias\EmailValidator\Validation\RFCValidation()); } $b = microtime(true); echo ($b - $a) . ' seconds with EmailValidator once instanced' . PHP_EOL; php-email-validator-2.1.17/Tests/Performance/AgainstOldIsemail.php000066400000000000000000000017771362162433500250670ustar00rootroot00000000000000isValid($testingMail, new \Egulias\EmailValidator\Validation\RFCValidation()); } $b = microtime(true); echo ($b - $a) . ' seconds with EmailValidator + instantiation' . PHP_EOL; $a = microtime(true); $validator = new EmailValidator(); for ($i = 0; $i < $iterations; $i++) { $isValid = $validator->isValid($testingMail, new \Egulias\EmailValidator\Validation\RFCValidation()); } $b = microtime(true); echo ($b - $a) . ' seconds with EmailValidator once instanced' . PHP_EOL; php-email-validator-2.1.17/Tests/resources/000077500000000000000000000000001362162433500205625ustar00rootroot00000000000000php-email-validator-2.1.17/Tests/resources/is_email_tests.xml000066400000000000000000001342041362162433500243140ustar00rootroot00000000000000

New test set

This test set is designed to replace and extend the coverage of the original set but with fewer tests.

Thanks to Michael Rushton (michael@squiloople.com) for starting this work and contributing tests 1-100

ISEMAIL_ERR ISEMAIL_ERR_NODOMAIN Michael Rushton http://squiloople.com/tag/email/
test
ISEMAIL_ERR ISEMAIL_ERR_NODOMAIN Michael Rushton http://squiloople.com/tag/email/
@
ISEMAIL_ERR ISEMAIL_ERR_NOLOCALPART Michael Rushton http://squiloople.com/tag/email/
test@
ISEMAIL_ERR ISEMAIL_ERR_NODOMAIN Michael Rushton http://squiloople.com/tag/email/
test@io
io. currently has an MX-record (Feb 2011). Some DNS setups seem to find it, some don't. If you don't see the MX for io. then try setting your DNS server to 8.8.8.8 (the Google DNS server) ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
@io
io. currently has an MX-record (Feb 2011) ISEMAIL_ERR ISEMAIL_ERR_NOLOCALPART Michael Rushton http://squiloople.com/tag/email/
@iana.org
ISEMAIL_ERR ISEMAIL_ERR_NOLOCALPART Michael Rushton http://squiloople.com/tag/email/
test@iana.org
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@nominet.org.uk
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@about.museum
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
a@iana.org
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@e.com
ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Michael Rushton http://squiloople.com/tag/email/
test@iana.a
ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Michael Rushton http://squiloople.com/tag/email/
test.test@iana.org
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
.test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_DOT_START Michael Rushton http://squiloople.com/tag/email/
test.@iana.org
ISEMAIL_ERR ISEMAIL_ERR_DOT_END Michael Rushton http://squiloople.com/tag/email/
test..iana.org
ISEMAIL_ERR ISEMAIL_ERR_CONSECUTIVEDOTS Michael Rushton http://squiloople.com/tag/email/
test_exa-mple.com
ISEMAIL_ERR ISEMAIL_ERR_NODOMAIN Michael Rushton http://squiloople.com/tag/email/
!#$%&`*+/=?^`{|}~@iana.org
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test\@test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
123@iana.org
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@123.com
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@iana.123
ISEMAIL_RFC5321 ISEMAIL_RFC5321_TLDNUMERIC Michael Rushton http://squiloople.com/tag/email/
test@255.255.255.255
ISEMAIL_RFC5321 ISEMAIL_RFC5321_TLDNUMERIC Michael Rushton http://squiloople.com/tag/email/
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn@iana.org
ISEMAIL_RFC5322 ISEMAIL_RFC5322_LOCAL_TOOLONG Michael Rushton http://squiloople.com/tag/email/
test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com
ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Michael Rushton http://squiloople.com/tag/email/
test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.com
ISEMAIL_RFC5322 ISEMAIL_RFC5322_LABEL_TOOLONG Michael Rushton http://squiloople.com/tag/email/
test@mason-dixon.com
ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@-iana.org
ISEMAIL_ERR ISEMAIL_ERR_DOMAINHYPHENSTART Michael Rushton http://squiloople.com/tag/email/
test@iana-.com
ISEMAIL_ERR ISEMAIL_ERR_DOMAINHYPHENEND Michael Rushton http://squiloople.com/tag/email/
test@c--n.com
c--n.com currently has an MX-record (May 2011) ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
test@iana.co-uk
ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Michael Rushton http://squiloople.com/tag/email/
test@.iana.org
ISEMAIL_ERR ISEMAIL_ERR_DOT_START Michael Rushton http://squiloople.com/tag/email/
test@iana.org.
ISEMAIL_ERR ISEMAIL_ERR_DOT_END Michael Rushton http://squiloople.com/tag/email/
test@iana..com
ISEMAIL_ERR ISEMAIL_ERR_CONSECUTIVEDOTS Michael Rushton http://squiloople.com/tag/email/
a@a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v
ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Michael Rushton http://squiloople.com/tag/email/
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi
ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Michael Rushton http://squiloople.com/tag/email/
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij
ISEMAIL_RFC5322 ISEMAIL_RFC5322_TOOLONG Michael Rushton http://squiloople.com/tag/email/
a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hij
ISEMAIL_RFC5322 ISEMAIL_RFC5322_TOOLONG Michael Rushton http://squiloople.com/tag/email/
a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hijk
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAIN_TOOLONG Michael Rushton http://squiloople.com/tag/email/
"test"@iana.org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_QUOTEDSTRING Michael Rushton http://squiloople.com/tag/email/
""@iana.org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_QUOTEDSTRING Michael Rushton http://squiloople.com/tag/email/
"""@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
"\a"@iana.org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_QUOTEDSTRING Michael Rushton http://squiloople.com/tag/email/
"\""@iana.org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_QUOTEDSTRING Michael Rushton http://squiloople.com/tag/email/
"\"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDQUOTEDSTR Michael Rushton http://squiloople.com/tag/email/
"\\"@iana.org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_QUOTEDSTRING Michael Rushton http://squiloople.com/tag/email/
test"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
"test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDQUOTEDSTR Michael Rushton http://squiloople.com/tag/email/
"test"test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_ATEXT_AFTER_QS Michael Rushton http://squiloople.com/tag/email/
test"text"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
"test""test"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
"test"."test"@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_LOCALPART Michael Rushton http://squiloople.com/tag/email/
"test\ test"@iana.org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_QUOTEDSTRING Michael Rushton http://squiloople.com/tag/email/
"test".test@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_LOCALPART Michael Rushton http://squiloople.com/tag/email/
"test␀"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_QTEXT Michael Rushton http://squiloople.com/tag/email/
"test\␀"@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_QP Michael Rushton http://squiloople.com/tag/email/
"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj"@iana.org
Quotes are still part of the length restriction ISEMAIL_RFC5322 ISEMAIL_RFC5322_LOCAL_TOOLONG Dominic Sayers http://isemail.info
"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\h"@iana.org
Quoted pair is still part of the length restriction ISEMAIL_RFC5322 ISEMAIL_RFC5322_LOCAL_TOOLONG Dominic Sayers http://isemail.info
test@[255.255.255.255]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@a[255.255.255.255]
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
test@[255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[255.255.255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[255.255.255.256]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[1111:2222:3333:4444:5555:6666:7777:8888]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666:7777]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_GRPCOUNT Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_GRPCOUNT Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_BADCHAR Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666::8888]
ISEMAIL_DEPREC ISEMAIL_RFC5321_IPV6DEPRECATED Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555::8888]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_MAXGRPS Michael Rushton http://squiloople.com/tag/email/
test@[IPv6::3333:4444:5555:6666:7777:8888]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_COLONSTRT Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:::3333:4444:5555:6666:7777:8888]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111::4444:5555::8888]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_2X2XCOLON Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:::]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_GRPCOUNT Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_GRPCOUNT Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444::255.255.255.255]
ISEMAIL_RFC5321 ISEMAIL_RFC5321_ADDRESSLITERAL Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_MAXGRPS Michael Rushton http://squiloople.com/tag/email/
test@[IPv6:1111:2222:3333:4444:::255.255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_2X2XCOLON Michael Rushton http://squiloople.com/tag/email/
test@[IPv6::255.255.255.255]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_COLONSTRT Michael Rushton http://squiloople.com/tag/email/
test @iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_CFWS_NEAR_AT Michael Rushton http://squiloople.com/tag/email/
test@ iana .com
ISEMAIL_DEPREC ISEMAIL_DEPREC_CFWS_NEAR_AT Michael Rushton http://squiloople.com/tag/email/
test . test@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_FWS Michael Rushton http://squiloople.com/tag/email/
␍␊ test@iana.org
FWS ISEMAIL_CFWS ISEMAIL_CFWS_FWS Michael Rushton http://squiloople.com/tag/email/
␍␊ ␍␊ test@iana.org
FWS with one line composed entirely of WSP -- only allowed as obsolete FWS (someone might allow only non-obsolete FWS) ISEMAIL_DEPREC ISEMAIL_DEPREC_FWS Michael Rushton http://squiloople.com/tag/email/
(comment)test@iana.org
ISEMAIL_CFWS ISEMAIL_CFWS_COMMENT Michael Rushton http://squiloople.com/tag/email/
((comment)test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDCOMMENT Michael Rushton http://squiloople.com/tag/email/
(comment(comment))test@iana.org
ISEMAIL_CFWS ISEMAIL_CFWS_COMMENT Michael Rushton http://squiloople.com/tag/email/
test@(comment)iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_CFWS_NEAR_AT Michael Rushton http://squiloople.com/tag/email/
test(comment)test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_ATEXT_AFTER_CFWS Michael Rushton http://squiloople.com/tag/email/
test@(comment)[255.255.255.255]
ISEMAIL_DEPREC ISEMAIL_DEPREC_CFWS_NEAR_AT Michael Rushton http://squiloople.com/tag/email/
(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org
ISEMAIL_CFWS ISEMAIL_CFWS_COMMENT Michael Rushton http://squiloople.com/tag/email/
test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com
ISEMAIL_DEPREC ISEMAIL_DEPREC_CFWS_NEAR_AT Michael Rushton http://squiloople.com/tag/email/
(comment)test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstu
ISEMAIL_CFWS ISEMAIL_CFWS_COMMENT Michael Rushton http://squiloople.com/tag/email/
test@iana.org␊
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
test@xn--hxajbheg2az3al.xn--jxalpdlp
A valid IDN from ICANN's IDN TLD evaluation gateway ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Michael Rushton http://squiloople.com/tag/email/
xn--test@iana.org
RFC 3490: "unless the email standards are revised to invite the use of IDNA for local parts, a domain label that holds the local part of an email address SHOULD NOT begin with the ACE prefix, and even if it does, it is to be interpreted literally as a local part that happens to begin with the ACE prefix" ISEMAIL_VALID_CATEGORY ISEMAIL_VALID Dominic Sayers http://isemail.info
test@iana.org-
ISEMAIL_ERR ISEMAIL_ERR_DOMAINHYPHENEND Dominic Sayers http://isemail.info
"test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDQUOTEDSTR Dominic Sayers http://isemail.info
(test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDCOMMENT Dominic Sayers http://isemail.info
test@(iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDCOMMENT Dominic Sayers http://isemail.info
test@[1.2.3.4
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDDOMLIT Dominic Sayers http://isemail.info
"test\"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDQUOTEDSTR Dominic Sayers http://isemail.info
(comment\)test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDCOMMENT Dominic Sayers http://isemail.info
test@iana.org(comment\)
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDCOMMENT Dominic Sayers http://isemail.info
test@iana.org(comment\
ISEMAIL_ERR ISEMAIL_ERR_BACKSLASHEND Dominic Sayers http://isemail.info
test@[RFC-5322-domain-literal]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Dominic Sayers http://isemail.info
test@[RFC-5322]-domain-literal]
ISEMAIL_ERR ISEMAIL_ERR_ATEXT_AFTER_DOMLIT Dominic Sayers http://isemail.info
test@[RFC-5322-[domain-literal]
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_DTEXT Dominic Sayers http://isemail.info
test@[RFC-5322-\␇-domain-literal]
obs-dtext and obs-qp ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMLIT_OBSDTEXT Dominic Sayers http://isemail.info
test@[RFC-5322-\␉-domain-literal]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMLIT_OBSDTEXT Dominic Sayers http://isemail.info
test@[RFC-5322-\]-domain-literal]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMLIT_OBSDTEXT Dominic Sayers http://isemail.info
test@[RFC-5322-domain-literal\]
ISEMAIL_ERR ISEMAIL_ERR_UNCLOSEDDOMLIT Dominic Sayers http://isemail.info
test@[RFC-5322-domain-literal\
ISEMAIL_ERR ISEMAIL_ERR_BACKSLASHEND Dominic Sayers http://isemail.info
test@[RFC 5322 domain literal]
Spaces are FWS in a domain literal ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Dominic Sayers http://isemail.info
test@[RFC-5322-domain-literal] (comment)
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAINLITERAL Dominic Sayers http://isemail.info
@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Dominic Sayers http://isemail.info
test@.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Dominic Sayers http://isemail.info
""@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_QTEXT Dominic Sayers http://isemail.info
"\"@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_QP Dominic Sayers http://isemail.info
()test@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_CTEXT Dominic Sayers http://isemail.info
test@iana.org␍
No LF after the CR ISEMAIL_ERR ISEMAIL_ERR_CR_NO_LF Dominic Sayers http://isemail.info
␍test@iana.org
No LF after the CR ISEMAIL_ERR ISEMAIL_ERR_CR_NO_LF Dominic Sayers http://isemail.info
"␍test"@iana.org
No LF after the CR ISEMAIL_ERR ISEMAIL_ERR_CR_NO_LF Dominic Sayers http://isemail.info
(␍)test@iana.org
No LF after the CR ISEMAIL_ERR ISEMAIL_ERR_CR_NO_LF Dominic Sayers http://isemail.info
test@iana.org(␍)
No LF after the CR ISEMAIL_ERR ISEMAIL_ERR_CR_NO_LF Dominic Sayers http://isemail.info
␊test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Michael Rushton http://squiloople.com/tag/email/
"␊"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_QTEXT Dominic Sayers http://isemail.info
"\␊"@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_QP Dominic Sayers http://isemail.info
(␊)test@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_CTEXT Dominic Sayers http://isemail.info
␇@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Dominic Sayers http://isemail.info
test@␇.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_ATEXT Dominic Sayers http://isemail.info
"␇"@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_QTEXT Dominic Sayers http://isemail.info
"\␇"@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_QP Dominic Sayers http://isemail.info
(␇)test@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_CTEXT Dominic Sayers http://isemail.info
␍␊test@iana.org
Not FWS because no actual white space ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
␍␊ ␍␊test@iana.org
Not obs-FWS because there must be white space on each "fold" ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
␍␊test@iana.org
Not FWS because no white space after the fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
␍␊ test@iana.org
FWS ISEMAIL_CFWS ISEMAIL_CFWS_FWS Dominic Sayers http://isemail.info
␍␊ ␍␊test@iana.org
Not FWS because no white space after the second fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
␍␊␍␊test@iana.org
Not FWS because no white space after either fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_X2 Dominic Sayers http://isemail.info
␍␊␍␊ test@iana.org
Not FWS because no white space after the first fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_X2 Dominic Sayers http://isemail.info
test@iana.org␍␊
FWS ISEMAIL_CFWS ISEMAIL_CFWS_FWS Dominic Sayers http://isemail.info
test@iana.org␍␊ ␍␊
FWS with one line composed entirely of WSP -- only allowed as obsolete FWS (someone might allow only non-obsolete FWS) ISEMAIL_DEPREC ISEMAIL_DEPREC_FWS Dominic Sayers http://isemail.info
test@iana.org␍␊
Not FWS because no actual white space ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
test@iana.org␍␊ ␍␊
Not obs-FWS because there must be white space on each "fold" ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
test@iana.org ␍␊
Not FWS because no white space after the fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
test@iana.org ␍␊
FWS ISEMAIL_CFWS ISEMAIL_CFWS_FWS Dominic Sayers http://isemail.info
test@iana.org ␍␊ ␍␊
Not FWS because no white space after the second fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_END Dominic Sayers http://isemail.info
test@iana.org ␍␊␍␊
Not FWS because no white space after either fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_X2 Dominic Sayers http://isemail.info
test@iana.org ␍␊␍␊
Not FWS because no white space after the first fold ISEMAIL_ERR ISEMAIL_ERR_FWS_CRLF_X2 Dominic Sayers http://isemail.info
test@iana.org
ISEMAIL_CFWS ISEMAIL_CFWS_FWS Dominic Sayers http://isemail.info
test@iana.org
ISEMAIL_CFWS ISEMAIL_CFWS_FWS Dominic Sayers http://isemail.info
test@[IPv6:1::2:]
ISEMAIL_RFC5322 ISEMAIL_RFC5322_IPV6_COLONEND Dominic Sayers http://isemail.info
"test\©"@iana.org
ISEMAIL_ERR ISEMAIL_ERR_EXPECTING_QPAIR Dominic Sayers http://isemail.info
test@iana/icann.org
ISEMAIL_RFC5322 ISEMAIL_RFC5322_DOMAIN Dominic Sayers http://isemail.info
test.(comment)test@iana.org
ISEMAIL_DEPREC ISEMAIL_DEPREC_COMMENT Dominic Sayers http://isemail.info
test@org
ISEMAIL_RFC5321 ISEMAIL_RFC5321_TLD Dominic Sayers http://isemail.info
test@test.com
test.com has an A-record but not an MX-record ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_MX_RECORD Dominic Sayers http://isemail.info
test@nic.no
nic.no currently has no MX-records or A-records (Feb 2011). If you are seeing an A-record for nic.io then try setting your DNS server to 8.8.8.8 (the Google DNS server) - your DNS server may be faking an A-record (OpenDNS does this, for instance). ISEMAIL_DNSWARN ISEMAIL_DNSWARN_NO_RECORD Dominic Sayers http://isemail.info
php-email-validator-2.1.17/composer.json000066400000000000000000000017371362162433500202000ustar00rootroot00000000000000{ "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": { "satooshi/php-coveralls": "^1.0.1", "phpunit/phpunit": "^4.8.36|^7.5.15", "dominicsayers/isemail": "^3.0.7" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, "autoload": { "psr-4": { "Egulias\\EmailValidator\\": "EmailValidator" } }, "autoload-dev": { "psr-4": { "Egulias\\Tests\\": "Tests" } } } php-email-validator-2.1.17/documentation/000077500000000000000000000000001362162433500203175ustar00rootroot00000000000000php-email-validator-2.1.17/documentation/Other.md000066400000000000000000000056071362162433500217320ustar00rootroot00000000000000Email length ------------ https://tools.ietf.org/html/rfc5321#section-4.1.2 Forward-path = Path Path = "<" [ A-d-l ":" ] Mailbox ">" https://tools.ietf.org/html/rfc5321#section-4.5.3.1.3 https://tools.ietf.org/html/rfc1035#section-2.3.4 DNS --- https://tools.ietf.org/html/rfc5321#section-2.3.5 Names that can be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed in Section 5) are permitted, as are CNAME RRs whose targets can be resolved, in turn, to MX or address RRs. https://tools.ietf.org/html/rfc5321#section-5.1 The lookup first attempts to locate an MX record associated with the name. If a CNAME record is found, the resulting name is processed as if it were the initial name. ... If an empty list of MXs is returned, the address is treated as if it was associated with an implicit MX RR, with a preference of 0, pointing to that host. is_email() author's note: We will regard the existence of a CNAME to be sufficient evidence of the domain's existence. For performance reasons we will not repeat the DNS lookup for the CNAME's target, but we will raise a warning because we didn't immediately find an MX record. Check for TLD addresses ----------------------- TLD addresses are specifically allowed in RFC 5321 but they are unusual to say the least. We will allocate a separate status to these addresses on the basis that they are more likely to be typos than genuine addresses (unless we've already established that the domain does have an MX record) https://tools.ietf.org/html/rfc5321#section-2.3.5 In the case of a top-level domain used by itself in an email address, a single string is used without any dots. This makes the requirement, described in more detail below, that only fully-qualified domain names appear in SMTP transactions on the public Internet, particularly important where top-level domains are involved. TLD format ---------- The format of TLDs has changed a number of times. The standards used by IANA have been largely ignored by ICANN, leading to confusion over the standards being followed. These are not defined anywhere, except as a general component of a DNS host name (a label). However, this could potentially lead to 123.123.123.123 being a valid DNS name (rather than an IP address) and thereby creating an ambiguity. The most authoritative statement on TLD formats that the author can find is in a (rejected!) erratum to RFC 1123 submitted by John Klensin, the author of RFC 5321: https://www.rfc-editor.org/errata_search.php?rfc=1123&eid=1353 However, a valid host name can never have the dotted-decimal form #.#.#.#, since this change does not permit the highest-level component label to start with a digit even if it is not all-numeric. Comments -------- Comments at the start of the domain are deprecated in the text Comments at the start of a subdomain are obs-domain (https://tools.ietf.org/html/rfc5322#section-3.4.1) php-email-validator-2.1.17/documentation/RFC5321BNF.html000066400000000000000000000054731362162433500224710ustar00rootroot00000000000000 The BNF from RFC 5321 defining parts of a valid SMTP address
   Mailbox        = Local-part "@" ( Domain / address-literal )

   Local-part     = Dot-string / Quoted-string
                  ; MAY be case-sensitive


   Dot-string     = Atom *("."  Atom)

   Atom           = 1*atext

   Quoted-string  = DQUOTE *QcontentSMTP DQUOTE

   QcontentSMTP   = qtextSMTP / quoted-pairSMTP

   quoted-pairSMTP  = %d92 %d32-126
                    ; i.e., backslash followed by any ASCII
                    ; graphic (including itself) or SPace

   qtextSMTP      = %d32-33 / %d35-91 / %d93-126
                  ; i.e., within a quoted string, any
                  ; ASCII graphic or space is permitted
                  ; without blackslash-quoting except
                  ; double-quote and the backslash itself.

   Domain         = sub-domain *("." sub-domain)

   sub-domain     = Let-dig [Ldh-str]

   Let-dig        = ALPHA / DIGIT

   Ldh-str        = *( ALPHA / DIGIT / "-" ) Let-dig

   address-literal  = "[" ( IPv4-address-literal /
                    IPv6-address-literal /
                    General-address-literal ) "]"
                    ; See Section 4.1.3

   IPv4-address-literal  = Snum 3("."  Snum)

   IPv6-address-literal  = "IPv6:" IPv6-addr

   General-address-literal  = Standardized-tag ":" 1*dcontent

   Standardized-tag  = Ldh-str
                     ; Standardized-tag MUST be specified in a
                     ; Standards-Track RFC and registered with IANA

   dcontent       = %d33-90 / ; Printable US-ASCII
                  %d94-126 ; excl. "[", "\", "]"

   Snum           = 1*3DIGIT
                  ; representing a decimal integer
                  ; value in the range 0 through 255

   IPv6-addr      = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp

   IPv6-hex       = 1*4HEXDIG

   IPv6-full      = IPv6-hex 7(":" IPv6-hex)

   IPv6-comp      = [IPv6-hex *5(":" IPv6-hex)] "::"
                  [IPv6-hex *5(":" IPv6-hex)]
                  ; The "::" represents at least 2 16-bit groups of
                  ; zeros.  No more than 6 groups in addition to the
                  ; "::" may be present.

   IPv6v4-full    = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal

   IPv6v4-comp    = [IPv6-hex *3(":" IPv6-hex)] "::"
                  [IPv6-hex *3(":" IPv6-hex) ":"]
                  IPv4-address-literal
                  ; The "::" represents at least 2 16-bit groups of
                  ; zeros.  No more than 4 groups in addition to the
                  ; "::" and IPv4-address-literal may be present.

php-email-validator-2.1.17/documentation/RFC5322BNF.html000066400000000000000000000115051362162433500224630ustar00rootroot00000000000000 The BNF from RFC 5322 defining parts of a valid internet message address
   addr-spec       =   local-part "@" domain

   local-part      =   dot-atom / quoted-string / obs-local-part

   dot-atom        =   [CFWS] dot-atom-text [CFWS]

   CFWS            =   (1*([FWS] comment) [FWS]) / FWS

   FWS             =   ([*WSP CRLF] 1*WSP) /  obs-FWS
                                          ; Folding white space

   WSP             =   SP / HTAB          ; white space

   obs-FWS         =   1*([CRLF] WSP)     ; As amended in erratum #1908

   ctext           =   %d33-39 /          ; Printable US-ASCII
                       %d42-91 /          ;  characters not including
                       %d93-126 /         ;  "(", ")", or "\"
                       obs-ctext

   obs-ctext       =   obs-NO-WS-CTL
   ccontent        =   ctext / quoted-pair / comment

   comment         =   "(" *([FWS] ccontent) [FWS] ")"

   dot-atom-text   =   1*atext *("." 1*atext)

   atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
                       "!" / "#" /        ;  characters not including
                       "$" / "%" /        ;  specials.  Used for atoms.
                       "&" / "'" /
                       "*" / "+" /
                       "-" / "/" /
                       "=" / "?" /
                       "^" / "_" /
                       "`" / "{" /
                       "|" / "}" /
                       "~"

   specials        =   "(" / ")" /        ; Special characters that do
                       "<" / ">" /        ;  not appear in atext
                       "[" / "]" /
                       ":" / ";" /
                       "@" / "\" /
                       "," / "." /
                       DQUOTE

   quoted-string   =   [CFWS]
                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE
                       [CFWS]

   qcontent        =   qtext / quoted-pair

   qtext           =   %d33 /             ; Printable US-ASCII
                       %d35-91 /          ;  characters not including
                       %d93-126 /         ;  "\" or the quote character
                       obs-qtext

   obs-qtext       =   obs-NO-WS-CTL

   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control
                       %d11 /             ;  characters that do not
                       %d12 /             ;  include the carriage
                       %d14-31 /          ;  return, line feed, and
                       %d127              ;  white space characters

   quoted-pair     =   ("\" (VCHAR / WSP)) / obs-qp

   VCHAR           =   %x21-7E            ; visible (printing) characters

   obs-qp          =   "\" (%d0 / obs-NO-WS-CTL / LF / CR)

   obs-local-part  =   word *("." word)

   word            =   atom / quoted-string

   atom            =   [CFWS] 1*atext [CFWS]

   domain          =   dot-atom / domain-literal / obs-domain

   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]

   dtext           =   %d33-90 /          ; Printable US-ASCII
                       %d94-126 /         ;  characters not including
                       obs-dtext          ;  "[", "]", or "\"

   obs-dtext       =   obs-NO-WS-CTL / quoted-pair

   obs-domain      =   atom *("." atom)

NB For SMTP mail, the domain-literal is restricted by RFC5321 as follows:

   Mailbox        = Local-part "@" ( Domain / address-literal )

   address-literal  = "[" ( IPv4-address-literal /
                    IPv6-address-literal /
                    General-address-literal ) "]"

   IPv4-address-literal  = Snum 3("."  Snum)

   IPv6-address-literal  = "IPv6:" IPv6-addr

   Snum           = 1*3DIGIT
                  ; representing a decimal integer
                  ; value in the range 0 through 255

   IPv6-addr      = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp

   IPv6-hex       = 1*4HEXDIG

   IPv6-full      = IPv6-hex 7(":" IPv6-hex)

   IPv6-comp      = [IPv6-hex *5(":" IPv6-hex)] "::"
                  [IPv6-hex *5(":" IPv6-hex)]
                  ; The "::" represents at least 2 16-bit groups of
                  ; zeros.  No more than 6 groups in addition to the
                  ; "::" may be present.

   IPv6v4-full    = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal

   IPv6v4-comp    = [IPv6-hex *3(":" IPv6-hex)] "::"
                  [IPv6-hex *3(":" IPv6-hex) ":"]
                  IPv4-address-literal
                  ; The "::" represents at least 2 16-bit groups of
                  ; zeros.  No more than 4 groups in addition to the
                  ; "::" and IPv4-address-literal may be present.

php-email-validator-2.1.17/phpunit.xml.dist000066400000000000000000000012101362162433500206130ustar00rootroot00000000000000 ./Tests/EmailValidator ./vendor/ ./EmailValidator/ php-email-validator-2.1.17/psalm.baseline.xml000066400000000000000000000011761362162433500210720ustar00rootroot00000000000000 self::$nullToken parse Spoofchecker Spoofchecker php-email-validator-2.1.17/psalm.xml000066400000000000000000000010431362162433500173020ustar00rootroot00000000000000