123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- <?php
- namespace Egulias\EmailValidator\Parser;
- use Egulias\EmailValidator\EmailLexer;
- use Egulias\EmailValidator\Exception\AtextAfterCFWS;
- use Egulias\EmailValidator\Exception\ConsecutiveDot;
- use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
- use Egulias\EmailValidator\Exception\CRLFX2;
- use Egulias\EmailValidator\Exception\CRNoLF;
- use Egulias\EmailValidator\Exception\ExpectingQPair;
- use Egulias\EmailValidator\Exception\ExpectingATEXT;
- use Egulias\EmailValidator\Exception\ExpectingCTEXT;
- use Egulias\EmailValidator\Exception\UnclosedComment;
- use Egulias\EmailValidator\Exception\UnclosedQuotedString;
- use Egulias\EmailValidator\Warning\CFWSNearAt;
- use Egulias\EmailValidator\Warning\CFWSWithFWS;
- use Egulias\EmailValidator\Warning\Comment;
- use Egulias\EmailValidator\Warning\QuotedPart;
- use Egulias\EmailValidator\Warning\QuotedString;
- abstract class Parser
- {
- protected $warnings = [];
- protected $lexer;
- protected $openedParenthesis = 0;
- public function __construct(EmailLexer $lexer)
- {
- $this->lexer = $lexer;
- }
- public function getWarnings()
- {
- return $this->warnings;
- }
- 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();
- }
- }
- 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();
- }
- }
- 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;
- }
- protected function escaped()
- {
- $previous = $this->lexer->getPrevious();
- if ($previous['type'] === EmailLexer::S_BACKSLASH
- &&
- $this->lexer->token['type'] !== EmailLexer::GENERIC
- ) {
- return true;
- }
- return false;
- }
- 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;
- }
- 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();
- }
- }
- }
|