Domain.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php
  2. /*
  3. * Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. declare(strict_types=1);
  7. namespace Respect\Validation\Rules;
  8. use Respect\Validation\Exceptions\DomainException;
  9. use Respect\Validation\Exceptions\NestedValidationException;
  10. use Respect\Validation\Exceptions\ValidationException;
  11. use Respect\Validation\Validatable;
  12. use function array_merge;
  13. use function array_pop;
  14. use function count;
  15. use function explode;
  16. use function iterator_to_array;
  17. use function mb_substr_count;
  18. /**
  19. * Validates whether the input is a valid domain name or not.
  20. *
  21. * @author Alexandre Gomes Gaigalas <alganet@gmail.com>
  22. * @author Henrique Moody <henriquemoody@gmail.com>
  23. * @author Mehmet Tolga Avcioglu <mehmet@activecom.net>
  24. * @author Nick Lombard <github@jigsoft.co.za>
  25. * @author Róbert Nagy <vrnagy@gmail.com>
  26. */
  27. final class Domain extends AbstractRule
  28. {
  29. /**
  30. * @var Validatable
  31. */
  32. private $genericRule;
  33. /**
  34. * @var Validatable
  35. */
  36. private $tldRule;
  37. /**
  38. * @var Validatable
  39. */
  40. private $partsRule;
  41. public function __construct(bool $tldCheck = true)
  42. {
  43. $this->genericRule = $this->createGenericRule();
  44. $this->tldRule = $this->createTldRule($tldCheck);
  45. $this->partsRule = $this->createPartsRule();
  46. }
  47. /**
  48. * {@inheritDoc}
  49. */
  50. public function assert($input): void
  51. {
  52. $exceptions = [];
  53. $this->collectAssertException($exceptions, $this->genericRule, $input);
  54. $this->throwExceptions($exceptions, $input);
  55. $parts = explode('.', (string) $input);
  56. if (count($parts) >= 2) {
  57. $this->collectAssertException($exceptions, $this->tldRule, array_pop($parts));
  58. }
  59. foreach ($parts as $part) {
  60. $this->collectAssertException($exceptions, $this->partsRule, $part);
  61. }
  62. $this->throwExceptions($exceptions, $input);
  63. }
  64. /**
  65. * {@inheritDoc}
  66. */
  67. public function validate($input): bool
  68. {
  69. try {
  70. $this->assert($input);
  71. } catch (ValidationException $exception) {
  72. return false;
  73. }
  74. return true;
  75. }
  76. /**
  77. * {@inheritDoc}
  78. */
  79. public function check($input): void
  80. {
  81. try {
  82. $this->assert($input);
  83. } catch (NestedValidationException $exception) {
  84. /** @var ValidationException $childException */
  85. foreach ($exception as $childException) {
  86. throw $childException;
  87. }
  88. throw $exception;
  89. }
  90. }
  91. /**
  92. * @param ValidationException[] $exceptions
  93. * @param mixed $input
  94. */
  95. private function collectAssertException(array &$exceptions, Validatable $validator, $input): void
  96. {
  97. try {
  98. $validator->assert($input);
  99. } catch (NestedValidationException $nestedValidationException) {
  100. $exceptions = array_merge(
  101. $exceptions,
  102. iterator_to_array($nestedValidationException)
  103. );
  104. } catch (ValidationException $validationException) {
  105. $exceptions[] = $validationException;
  106. }
  107. }
  108. private function createGenericRule(): Validatable
  109. {
  110. return new AllOf(
  111. new StringType(),
  112. new NoWhitespace(),
  113. new Contains('.'),
  114. new Length(3)
  115. );
  116. }
  117. private function createTldRule(bool $realTldCheck): Validatable
  118. {
  119. if ($realTldCheck) {
  120. return new Tld();
  121. }
  122. return new AllOf(
  123. new Not(new StartsWith('-')),
  124. new NoWhitespace(),
  125. new Length(2)
  126. );
  127. }
  128. private function createPartsRule(): Validatable
  129. {
  130. return new AllOf(
  131. new Alnum('-'),
  132. new Not(new StartsWith('-')),
  133. new AnyOf(
  134. new Not(new Contains('--')),
  135. new Callback(static function ($str) {
  136. return mb_substr_count($str, '--') == 1;
  137. })
  138. ),
  139. new Not(new EndsWith('-'))
  140. );
  141. }
  142. /**
  143. * @param ValidationException[] $exceptions
  144. * @param mixed $input
  145. */
  146. private function throwExceptions(array $exceptions, $input): void
  147. {
  148. if (count($exceptions)) {
  149. /** @var DomainException $domainException */
  150. $domainException = $this->reportError($input);
  151. $domainException->addChildren($exceptions);
  152. throw $domainException;
  153. }
  154. }
  155. }