sonarrradarrplexorganizrnginxdashboardlandingpagestartpagelandinghtpcserverhomepagesabnzbdheimdallembycouchpotatonzbgetbookmarkapplication-dashboardmuximux
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							368 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							368 lines
						
					
					
						
							12 KiB
						
					
					
				| <?php | |
| 
 | |
| namespace Egulias\EmailValidator\Parser; | |
| 
 | |
| use Egulias\EmailValidator\EmailLexer; | |
| use Egulias\EmailValidator\Exception\CharNotAllowed; | |
| use Egulias\EmailValidator\Exception\CommaInDomain; | |
| use Egulias\EmailValidator\Exception\ConsecutiveAt; | |
| use Egulias\EmailValidator\Exception\CRLFAtTheEnd; | |
| use Egulias\EmailValidator\Exception\CRNoLF; | |
| use Egulias\EmailValidator\Exception\DomainHyphened; | |
| use Egulias\EmailValidator\Exception\DotAtEnd; | |
| use Egulias\EmailValidator\Exception\DotAtStart; | |
| use Egulias\EmailValidator\Exception\ExpectingATEXT; | |
| use Egulias\EmailValidator\Exception\ExpectingDomainLiteralClose; | |
| use Egulias\EmailValidator\Exception\ExpectingDTEXT; | |
| use Egulias\EmailValidator\Exception\NoDomainPart; | |
| use Egulias\EmailValidator\Exception\UnopenedComment; | |
| use Egulias\EmailValidator\Warning\AddressLiteral; | |
| use Egulias\EmailValidator\Warning\CFWSWithFWS; | |
| use Egulias\EmailValidator\Warning\DeprecatedComment; | |
| use Egulias\EmailValidator\Warning\DomainLiteral; | |
| use Egulias\EmailValidator\Warning\DomainTooLong; | |
| use Egulias\EmailValidator\Warning\IPV6BadChar; | |
| use Egulias\EmailValidator\Warning\IPV6ColonEnd; | |
| use Egulias\EmailValidator\Warning\IPV6ColonStart; | |
| use Egulias\EmailValidator\Warning\IPV6Deprecated; | |
| use Egulias\EmailValidator\Warning\IPV6DoubleColon; | |
| use Egulias\EmailValidator\Warning\IPV6GroupCount; | |
| use Egulias\EmailValidator\Warning\IPV6MaxGroups; | |
| use Egulias\EmailValidator\Warning\LabelTooLong; | |
| use Egulias\EmailValidator\Warning\ObsoleteDTEXT; | |
| use Egulias\EmailValidator\Warning\TLD; | |
| 
 | |
| class DomainPart extends Parser | |
| { | |
|     const DOMAIN_MAX_LENGTH = 254; | |
|     protected $domainPart = ''; | |
| 
 | |
|     public function parse($domainPart) | |
|     { | |
|         $this->lexer->moveNext(); | |
| 
 | |
|         if ($this->lexer->token['type'] === EmailLexer::S_DOT) { | |
|             throw new DotAtStart(); | |
|         } | |
| 
 | |
|         if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) { | |
|             throw new NoDomainPart(); | |
|         } | |
|         if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) { | |
|             throw new DomainHyphened(); | |
|         } | |
| 
 | |
|         if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { | |
|             $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); | |
|             $this->parseDomainComments(); | |
|         } | |
| 
 | |
|         $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; | |
|     } | |
| 
 | |
|     public function getDomainPart() | |
|     { | |
|         return $this->domainPart; | |
|     } | |
| 
 | |
|     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(); | |
|         } | |
|     } | |
| 
 | |
|     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 ($this->lexer->token); | |
| 
 | |
|         return $domain; | |
|     } | |
| 
 | |
|     private function checkNotAllowedChars($token) | |
|     { | |
|         $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; | |
|         if (isset($notAllowed[$token['type']])) { | |
|             throw new CharNotAllowed(); | |
|         } | |
|     } | |
| 
 | |
|     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(); | |
|     } | |
| 
 | |
|     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; | |
|     } | |
| 
 | |
|     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, $index) . '0:0'; | |
|         } | |
| 
 | |
|         return $addressLiteral; | |
|     } | |
| 
 | |
|     protected function checkDomainPartExceptions($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(); | |
|         } | |
|     } | |
| 
 | |
|     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($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(); | |
|         } | |
|     } | |
| }
 | |
| 
 |