radarrplexorganizrnginxsonarrdashboardheimdallembycouchpotatonzbgetbookmarkapplication-dashboardmuximuxlandingpagestartpagelandinghtpcserverhomepagesabnzbd
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.
215 lines
6.3 KiB
215 lines
6.3 KiB
<?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\ExpectedQPair;
|
|
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 ExpectedQPair();
|
|
}
|
|
|
|
$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();
|
|
}
|
|
}
|
|
}
|
|
|