From 2a683be66433cf517eba67642b9b3a4a373ce6fd Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Thu, 12 Dec 2024 00:42:06 +0100 Subject: [PATCH] Use PHP Domain Parser to validate domains --- composer.json | 2 + library/Rules/Domain.php | 81 +++++++++------------------------ tests/unit/Rules/DomainTest.php | 2 +- 3 files changed, 25 insertions(+), 60 deletions(-) diff --git a/composer.json b/composer.json index 5a7f30faa..6a6bfaac2 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "require-dev": { "egulias/email-validator": "^4.0", "giggsey/libphonenumber-for-php-lite": "^8.13", + "jeremykendall/php-domain-parser": "^6.0", "malukenho/docheader": "^1.0", "mikey179/vfsstream": "^1.6", "nette/php-generator": "^4.1", @@ -48,6 +49,7 @@ "ext-fileinfo": "File Information", "ext-mbstring": "Multibyte String Functions", "egulias/email-validator": "Improves the Email rule if available", + "jeremykendall/php-domain-parser": "Allows validating domains", "giggsey/libphonenumber-for-php-lite": "Enables the phone rule if available", "sokil/php-isocodes": "Enable rules that validate ISO codes", "sokil/php-isocodes-db-only": "Enable rules that validate ISO codes" diff --git a/library/Rules/Domain.php b/library/Rules/Domain.php index d7ccc652a..139a44028 100644 --- a/library/Rules/Domain.php +++ b/library/Rules/Domain.php @@ -9,88 +9,51 @@ namespace Respect\Validation\Rules; -use Attribute; +use Pdp\Domain as PdpDomain; +use Respect\Validation\Exceptions\MissingComposerDependencyException; use Respect\Validation\Message\Template; use Respect\Validation\Result; -use Respect\Validation\Rule; use Respect\Validation\Rules\Core\Standard; +use Throwable; -use function array_pop; +use function class_exists; use function count; -use function explode; -use function mb_substr_count; +use function is_string; -#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid domain', '{{name}} must not be a valid domain', )] final class Domain extends Standard { - private readonly Rule $genericRule; - - private readonly Rule $tldRule; - - private readonly Rule $partsRule; - - public function __construct(bool $tldCheck = true) - { - $this->genericRule = $this->createGenericRule(); - $this->tldRule = $this->createTldRule($tldCheck); - $this->partsRule = $this->createPartsRule(); + public function __construct( + private readonly bool $requireTld = true, + ) { + if (!class_exists(PdpDomain::class)) { + throw new MissingComposerDependencyException( + 'Domain rule requires PHP Domain Parser', + 'jeremykendall/php-domain-parser', + ); + } } public function evaluate(mixed $input): Result { - $genericResult = $this->genericRule->evaluate($input); - if (!$genericResult->isValid) { + if (!is_string($input)) { return Result::failed($input, $this); } - $parts = explode('.', (string) $input); - if (count($parts) >= 2) { - $childResult = $this->tldRule->evaluate(array_pop($parts)); - if (!$childResult->isValid) { + try { + $domain = \Pdp\Domain::fromIDNA2008($input); + if (count($domain->labels()) === 1) { return Result::failed($input, $this); } - } - - return new Result($this->partsRule->evaluate($parts)->isValid, $input, $this); - } - private function createGenericRule(): Circuit - { - return new Circuit( - new StringType(), - new NoWhitespace(), - new Contains('.'), - new Length(new GreaterThanOrEqual(3)) - ); - } - - private function createTldRule(bool $realTldCheck): Rule - { - if ($realTldCheck) { - return new Tld(); + $domain->label(0); + } catch (Throwable) { + return Result::failed($input, $this); } - return new Circuit(new Not(new StartsWith('-')), new Length(new GreaterThanOrEqual(2))); - } - - private function createPartsRule(): Rule - { - return new Each( - new Circuit( - new Alnum('-'), - new Not(new StartsWith('-')), - new AnyOf( - new Not(new Contains('--')), - new Callback(static function ($str) { - return mb_substr_count($str, '--') == 1; - }) - ), - new Not(new EndsWith('-')) - ) - ); + return Result::passed($input, $this); } } diff --git a/tests/unit/Rules/DomainTest.php b/tests/unit/Rules/DomainTest.php index 983062226..b4721e112 100644 --- a/tests/unit/Rules/DomainTest.php +++ b/tests/unit/Rules/DomainTest.php @@ -65,6 +65,7 @@ public static function providerForDomainWithRealTopLevelDomain(): array ['mail.xn--bcher-kva.ch'], ['example-hyphen.com'], ['example--valid.com'], + ['xn--bcher--kva.ch'], ['std--a.com'], ['r--w.com'], ]; @@ -79,7 +80,6 @@ public static function providerForInvalidDomains(): array ['2222222domain.local'], ['-example-invalid.com'], ['example.invalid.-com'], - ['xn--bcher--kva.ch'], ['example.invalid-.com'], ['1.2.3.256'], ['1.2.3.4'],