Improved EmailParser to remove leaked logic. User of lexer recorder within parsers.

This commit is contained in:
Eduardo Gulias Davis
2021-02-21 22:06:38 +01:00
parent 03a062e9e4
commit b80f568f75
4 changed files with 115 additions and 68 deletions
+24 -59
View File
@@ -9,18 +9,12 @@ use Egulias\EmailValidator\Parser\DomainPart;
use Egulias\EmailValidator\Result\ValidEmail;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Warning\EmailTooLong;
use Egulias\EmailValidator\Result\Reason\ExpectingATEXT;
use Egulias\EmailValidator\Result\Reason\NoLocalPart;
class EmailParser
class EmailParser extends Parser
{
const EMAIL_MAX_LENGTH = 254;
/**
* @var array
*/
protected $warnings = [];
/**
* @var string
*/
@@ -30,10 +24,6 @@ class EmailParser
* @var string
*/
protected $localPart = '';
/**
* @var EmailLexer
*/
protected $lexer;
public function __construct(EmailLexer $lexer)
{
@@ -42,40 +32,36 @@ class EmailParser
public function parse(string $str) : Result
{
$this->lexer->setInput($str);
if (!$this->hasAtToken()) {
return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]);
}
$localPartResult = $this->processLocalPart();
if ($localPartResult->isInvalid()) {
return $localPartResult;
}
$domainPartResult = $this->processDomainPart();
if ($domainPartResult->isInvalid()) {
return $domainPartResult;
}
if ($this->lexer->hasInvalidTokens()) {
return new InvalidEmail(new ExpectingATEXT("Invalid tokens found"), $this->lexer->token["value"]);
}
$result = parent::parse($str);
$this->addLongEmailWarning($this->localPart, $this->domainPart);
return $result;
}
protected function preRightParsing(): Result
{
if (!$this->hasAtToken()) {
return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]);
}
return new ValidEmail();
}
protected function parseRightFromAt(): Result
{
return $this->processLocalPart();
}
protected function parseLeftFromAt(): Result
{
return $this->processDomainPart();
}
private function processLocalPart() : Result
{
$this->lexer->startRecording();
$localPartParser = new LocalPart($this->lexer);
$localPartResult = $localPartParser->parse();
$this->lexer->stopRecording();
$this->localPart = rtrim($this->lexer->getAccumulatedValues(), '@');
$this->localPart = $localPartParser->localPart();
$this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings);
return $localPartResult;
@@ -83,28 +69,14 @@ class EmailParser
private function processDomainPart() : Result
{
$this->lexer->clearRecorded();
$this->lexer->startRecording();
$domainPartParser = new DomainPart($this->lexer);
$domainPartResult = $domainPartParser->parse();
$this->lexer->stopRecording();
$this->domainPart = $this->lexer->getAccumulatedValues();
$this->domainPart = $domainPartParser->domainPart();
$this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings);
return $domainPartResult;
}
/**
* @return Warning\Warning[]
*/
public function getWarnings() : array
{
return $this->warnings;
}
/**
* @return string
*/
public function getDomainPart() : string
{
return $this->domainPart;
@@ -115,10 +87,7 @@ class EmailParser
return $this->localPart;
}
/**
* @return bool
*/
protected function hasAtToken() : bool
private function hasAtToken() : bool
{
$this->lexer->moveNext();
$this->lexer->moveNext();
@@ -129,11 +98,7 @@ class EmailParser
return true;
}
/**
* @param string $localPart
* @param string $parsedDomainPart
*/
protected function addLongEmailWarning($localPart, $parsedDomainPart) : void
private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void
{
if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) {
$this->warnings[EmailTooLong::CODE] = new EmailTooLong();
+62
View File
@@ -0,0 +1,62 @@
<?php
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Result\ValidEmail;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\ExpectingATEXT;
abstract class Parser
{
/**
* @var array
*/
protected $warnings = [];
/**
* @var EmailLexer
*/
protected $lexer;
abstract protected function parseRightFromAt() : Result;
abstract protected function parseLeftFromAt() : Result;
abstract protected function preRightParsing() : Result;
public function parse(string $str) : Result
{
$this->lexer->setInput($str);
if ($this->lexer->hasInvalidTokens()) {
return new InvalidEmail(new ExpectingATEXT("Invalid tokens found"), $this->lexer->token["value"]);
}
$preParsingResult = $this->preRightParsing();
if ($preParsingResult->isInvalid()) {
return $preParsingResult;
}
$localPartResult = $this->parseRightFromAt();
if ($localPartResult->isInvalid()) {
return $localPartResult;
}
$domainPartResult = $this->parseLeftFromAt();
if ($domainPartResult->isInvalid()) {
return $domainPartResult;
}
return new ValidEmail();
}
/**
* @return Warning\Warning[]
*/
public function getWarnings() : array
{
return $this->warnings;
}
}
+16 -6
View File
@@ -39,6 +39,9 @@ class DomainPart extends Parser
public function parse() : Result
{
$this->lexer->clearRecorded();
$this->lexer->startRecording();
$this->lexer->moveNext();
$domainChecks = $this->performDomainStartChecks();
@@ -49,20 +52,22 @@ class DomainPart extends Parser
if ($this->lexer->token['type'] === EmailLexer::S_AT) {
return new InvalidEmail(new ConsecutiveAt(), $this->lexer->token['value']);
}
$domain = $this->doParseDomainPart();
if ($domain->isInvalid()) {
return $domain;
}
$length = strlen($this->domainPart);
$result = $this->doParseDomainPart();
if ($result->isInvalid()) {
return $result;
}
$end = $this->checkEndOfDomain();
if ($end->isInvalid()) {
return $end;
}
$this->lexer->stopRecording();
$this->domainPart = $this->lexer->getAccumulatedValues();
$length = strlen($this->domainPart);
if ($length > self::DOMAIN_MAX_LENGTH) {
//$this->warnings[DomainTooLong::CODE] = new DomainTooLong();
return new InvalidEmail(new DomainTooLong(), $this->lexer->token['value']);
}
@@ -312,4 +317,9 @@ class DomainPart extends Parser
$this->warnings[TLD::CODE] = new TLD();
}
}
public function domainPart() : string
{
return $this->domainPart;
}
}
+13 -3
View File
@@ -15,6 +15,10 @@ use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment;
class LocalPart extends Parser
{
/**
* @var string
*/
private $localPart = '';
/**
* Invalid lexer tokens for local part
@@ -33,7 +37,7 @@ class LocalPart extends Parser
public function parse() : Result
{
$totalLength = 0;
$this->lexer->startRecording();
while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) {
if ($this->hasDotAtStart()) {
@@ -83,17 +87,23 @@ class LocalPart extends Parser
return $resultFWS;
}
$totalLength += strlen($this->lexer->token['value']);
$this->lexer->moveNext();
}
if ($totalLength > LocalTooLong::LOCAL_PART_LENGTH) {
$this->lexer->stopRecording();
$this->localPart = rtrim($this->lexer->getAccumulatedValues(), '@');
if (strlen($this->localPart) > LocalTooLong::LOCAL_PART_LENGTH) {
$this->warnings[LocalTooLong::CODE] = new LocalTooLong();
}
return new ValidEmail();
}
public function localPart() : string
{
return $this->localPart;
}
private function parseLocalFWS() : Result
{
$foldingWS = new FoldingWhiteSpace($this->lexer);