PageRenderTime 64ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/laradock/vendor/egulias/email-validator/src/Parser/DomainLiteral.php

https://gitlab.com/hoangduys4k5/laravelproject
PHP | 212 lines | 157 code | 36 blank | 19 comment | 27 complexity | 6d3d09fa2b863cf3035010ad7b2b9f4a MD5 | raw file
  1. <?php
  2. namespace Egulias\EmailValidator\Parser;
  3. use Egulias\EmailValidator\EmailLexer;
  4. use Egulias\EmailValidator\Result\Result;
  5. use Egulias\EmailValidator\Result\ValidEmail;
  6. use Egulias\EmailValidator\Result\InvalidEmail;
  7. use Egulias\EmailValidator\Warning\CFWSWithFWS;
  8. use Egulias\EmailValidator\Warning\IPV6BadChar;
  9. use Egulias\EmailValidator\Result\Reason\CRNoLF;
  10. use Egulias\EmailValidator\Warning\IPV6ColonEnd;
  11. use Egulias\EmailValidator\Warning\IPV6MaxGroups;
  12. use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
  13. use Egulias\EmailValidator\Warning\AddressLiteral;
  14. use Egulias\EmailValidator\Warning\IPV6ColonStart;
  15. use Egulias\EmailValidator\Warning\IPV6Deprecated;
  16. use Egulias\EmailValidator\Warning\IPV6GroupCount;
  17. use Egulias\EmailValidator\Warning\IPV6DoubleColon;
  18. use Egulias\EmailValidator\Result\Reason\ExpectingDTEXT;
  19. use Egulias\EmailValidator\Result\Reason\UnusualElements;
  20. use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
  21. class DomainLiteral extends PartParser
  22. {
  23. public function parse() : Result
  24. {
  25. $this->addTagWarnings();
  26. $IPv6TAG = false;
  27. $addressLiteral = '';
  28. do {
  29. if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
  30. return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
  31. }
  32. $this->addObsoleteWarnings();
  33. if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
  34. return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
  35. }
  36. if ($this->lexer->isNextTokenAny(
  37. array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF)
  38. )) {
  39. $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
  40. $this->parseFWS();
  41. }
  42. if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
  43. return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
  44. }
  45. if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
  46. return new InvalidEmail(new UnusualElements($this->lexer->token['value']), $this->lexer->token['value']);
  47. }
  48. if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
  49. $IPv6TAG = true;
  50. }
  51. if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) {
  52. break;
  53. }
  54. $addressLiteral .= $this->lexer->token['value'];
  55. } while ($this->lexer->moveNext());
  56. //Encapsulate
  57. $addressLiteral = str_replace('[', '', $addressLiteral);
  58. $isAddressLiteralIPv4 = $this->checkIPV4Tag($addressLiteral);
  59. if (!$isAddressLiteralIPv4) {
  60. return new ValidEmail();
  61. } else {
  62. $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral);
  63. }
  64. if (!$IPv6TAG) {
  65. $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral();
  66. return new ValidEmail();
  67. }
  68. $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
  69. $this->checkIPV6Tag($addressLiteral);
  70. return new ValidEmail();
  71. }
  72. /**
  73. * @param string $addressLiteral
  74. * @param int $maxGroups
  75. */
  76. public function checkIPV6Tag($addressLiteral, $maxGroups = 8) : void
  77. {
  78. $prev = $this->lexer->getPrevious();
  79. if ($prev['type'] === EmailLexer::S_COLON) {
  80. $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd();
  81. }
  82. $IPv6 = substr($addressLiteral, 5);
  83. //Daniel Marschall's new IPv6 testing strategy
  84. $matchesIP = explode(':', $IPv6);
  85. $groupCount = count($matchesIP);
  86. $colons = strpos($IPv6, '::');
  87. if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) {
  88. $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar();
  89. }
  90. if ($colons === false) {
  91. // We need exactly the right number of groups
  92. if ($groupCount !== $maxGroups) {
  93. $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount();
  94. }
  95. return;
  96. }
  97. if ($colons !== strrpos($IPv6, '::')) {
  98. $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon();
  99. return;
  100. }
  101. if ($colons === 0 || $colons === (strlen($IPv6) - 2)) {
  102. // RFC 4291 allows :: at the start or end of an address
  103. //with 7 other groups in addition
  104. ++$maxGroups;
  105. }
  106. if ($groupCount > $maxGroups) {
  107. $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups();
  108. } elseif ($groupCount === $maxGroups) {
  109. $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
  110. }
  111. }
  112. public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
  113. {
  114. $matchesIP = array();
  115. $IPv4Match = preg_match(
  116. '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
  117. $addressLiteralIPv4,
  118. $matchesIP);
  119. // Extract IPv4 part from the end of the address-literal (if there is one)
  120. if ($IPv4Match > 0) {
  121. $index = (int) strrpos($addressLiteralIPv4, $matchesIP[0]);
  122. //There's a match but it is at the start
  123. if ($index > 0) {
  124. // Convert IPv4 part to IPv6 format for further testing
  125. return substr($addressLiteralIPv4, 0, $index) . '0:0';
  126. }
  127. }
  128. return $addressLiteralIPv4;
  129. }
  130. /**
  131. * @param string $addressLiteral
  132. *
  133. * @return bool
  134. */
  135. protected function checkIPV4Tag($addressLiteral) : bool
  136. {
  137. $matchesIP = array();
  138. $IPv4Match = preg_match(
  139. '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
  140. $addressLiteral,
  141. $matchesIP);
  142. // Extract IPv4 part from the end of the address-literal (if there is one)
  143. if ($IPv4Match > 0) {
  144. $index = strrpos($addressLiteral, $matchesIP[0]);
  145. //There's a match but it is at the start
  146. if ($index === 0) {
  147. $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
  148. return false;
  149. }
  150. }
  151. return true;
  152. }
  153. private function addObsoleteWarnings() : void
  154. {
  155. if ($this->lexer->token['type'] === EmailLexer::INVALID ||
  156. $this->lexer->token['type'] === EmailLexer::C_DEL ||
  157. $this->lexer->token['type'] === EmailLexer::S_LF ||
  158. $this->lexer->token['type'] === EmailLexer::S_BACKSLASH
  159. ) {
  160. $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
  161. }
  162. }
  163. private function addTagWarnings() : void
  164. {
  165. if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
  166. $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
  167. }
  168. if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) {
  169. $lexer = clone $this->lexer;
  170. $lexer->moveNext();
  171. if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) {
  172. $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
  173. }
  174. }
  175. }
  176. }