FoldingWhiteSpace.php 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. <?php
  2. namespace Egulias\EmailValidator\Parser;
  3. use Egulias\EmailValidator\EmailLexer;
  4. use Egulias\EmailValidator\Warning\CFWSNearAt;
  5. use Egulias\EmailValidator\Result\InvalidEmail;
  6. use Egulias\EmailValidator\Warning\CFWSWithFWS;
  7. use Egulias\EmailValidator\Result\Reason\CRNoLF;
  8. use Egulias\EmailValidator\Result\Reason\AtextAfterCFWS;
  9. use Egulias\EmailValidator\Result\Reason\CRLFAtTheEnd;
  10. use Egulias\EmailValidator\Result\Reason\CRLFX2;
  11. use Egulias\EmailValidator\Result\Reason\ExpectingCTEXT;
  12. use Egulias\EmailValidator\Result\Result;
  13. use Egulias\EmailValidator\Result\ValidEmail;
  14. class FoldingWhiteSpace extends PartParser
  15. {
  16. public const FWS_TYPES = [
  17. EmailLexer::S_SP,
  18. EmailLexer::S_HTAB,
  19. EmailLexer::S_CR,
  20. EmailLexer::S_LF,
  21. EmailLexer::CRLF
  22. ];
  23. public function parse(): Result
  24. {
  25. if (!$this->isFWS()) {
  26. return new ValidEmail();
  27. }
  28. $previous = $this->lexer->getPrevious();
  29. $resultCRLF = $this->checkCRLFInFWS();
  30. if ($resultCRLF->isInvalid()) {
  31. return $resultCRLF;
  32. }
  33. if ($this->lexer->current->isA(EmailLexer::S_CR)) {
  34. return new InvalidEmail(new CRNoLF(), $this->lexer->current->value);
  35. }
  36. if ($this->lexer->isNextToken(EmailLexer::GENERIC) && !$previous->isA(EmailLexer::S_AT)) {
  37. return new InvalidEmail(new AtextAfterCFWS(), $this->lexer->current->value);
  38. }
  39. if ($this->lexer->current->isA(EmailLexer::S_LF) || $this->lexer->current->isA(EmailLexer::C_NUL)) {
  40. return new InvalidEmail(new ExpectingCTEXT(), $this->lexer->current->value);
  41. }
  42. if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous->isA(EmailLexer::S_AT)) {
  43. $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
  44. } else {
  45. $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
  46. }
  47. return new ValidEmail();
  48. }
  49. protected function checkCRLFInFWS(): Result
  50. {
  51. if (!$this->lexer->current->isA(EmailLexer::CRLF)) {
  52. return new ValidEmail();
  53. }
  54. if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
  55. return new InvalidEmail(new CRLFX2(), $this->lexer->current->value);
  56. }
  57. //this has no coverage. Condition is repeated from above one
  58. if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
  59. return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->current->value);
  60. }
  61. return new ValidEmail();
  62. }
  63. protected function isFWS(): bool
  64. {
  65. if ($this->escaped()) {
  66. return false;
  67. }
  68. return in_array($this->lexer->current->type, self::FWS_TYPES);
  69. }
  70. }