mirror of
https://github.com/egulias/EmailValidator.git
synced 2026-08-28 02:58:29 +00:00
Improved EmailParser to remove leaked logic. User of lexer recorder within parsers.
This commit is contained in:
+24
-59
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user