radarrplexorganizrnginxsonarrdashboardembycouchpotatonzbgetbookmarkapplication-dashboardmuximuxlandingpagestartpagelandinghtpcserverhomepagesabnzbdheimdall
		
		
		
		
			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();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 |