From 70d42fec3e125691e8c7ba61262052576011ce2c Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Thu, 20 Feb 2025 09:51:26 +0000 Subject: [PATCH 1/2] feat: url patterns --- src/Validator/Host.php | 82 ----------------------------------- src/Validator/URL.php | 47 +++++++++++++++----- src/Validator/URL/Pattern.php | 22 ++++++++++ 3 files changed, 59 insertions(+), 92 deletions(-) delete mode 100755 src/Validator/Host.php create mode 100644 src/Validator/URL/Pattern.php diff --git a/src/Validator/Host.php b/src/Validator/Host.php deleted file mode 100755 index 80fec5ec..00000000 --- a/src/Validator/Host.php +++ /dev/null @@ -1,82 +0,0 @@ -whitelist = $whitelist; - } - - /** - * Get Description - * - * Returns validator description - * - * @return string - */ - public function getDescription(): string - { - return 'URL host must be one of: ' . \implode(', ', $this->whitelist); - } - - /** - * Is valid - * - * Validation will pass when $value starts with one of the given hosts - * - * @param mixed $value - * @return bool - */ - public function isValid($value): bool - { - $urlValidator = new URL(); - - if (!$urlValidator->isValid($value)) { - return false; - } - - $hostnameValidator = new Hostname($this->whitelist); - - return $hostnameValidator->isValid(\parse_url($value, PHP_URL_HOST)); - } - - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_STRING; - } -} diff --git a/src/Validator/URL.php b/src/Validator/URL.php index 1c120086..1389b6a6 100644 --- a/src/Validator/URL.php +++ b/src/Validator/URL.php @@ -3,6 +3,7 @@ namespace Utopia\Validator; use Utopia\Validator; +use Utopia\Validator\URL\Pattern; /** * URL @@ -13,14 +14,17 @@ */ class URL extends Validator { - protected array $allowedSchemes; + /** + * @var array + */ + protected array $patterns; /** - * @param array $allowedSchemes + * @param array $patterns */ - public function __construct(array $allowedSchemes = []) + public function __construct(array $patterns = []) { - $this->allowedSchemes = $allowedSchemes; + $this->patterns = $patterns; } /** @@ -32,8 +36,8 @@ public function __construct(array $allowedSchemes = []) */ public function getDescription(): string { - if (!empty($this->allowedSchemes)) { - return 'Value must be a valid URL with following schemes (' . \implode(', ', $this->allowedSchemes) . ')'; + if (!empty($this->patterns)) { + return 'Value must be a valid URL matching one of the following patterns (' . \implode(', ', $this->patterns) . ')'; } return 'Value must be a valid URL'; @@ -49,15 +53,38 @@ public function getDescription(): string */ public function isValid($value): bool { - if (\filter_var($value, FILTER_VALIDATE_URL) === false) { + $parsed = $this->parseUrl($value); + if (!$parsed) { return false; } - if (!empty($this->allowedSchemes) && !\in_array(\parse_url($value, PHP_URL_SCHEME), $this->allowedSchemes)) { - return false; + if (empty($this->patterns)) { + return true; + } + + foreach ($this->patterns as $pattern) { + $schemeMatch = empty($pattern->schemes) || in_array($parsed['scheme'], $pattern->schemes); + $hostMatch = empty($pattern->hosts) || in_array($parsed['host'], $pattern->hosts); + + if ($schemeMatch && $hostMatch) { + return true; + } + } + + return false; + } + + protected function parseUrl($value): mixed + { + $parsed = \parse_url($value); + + // `parse_url` returns false if the URL is invalid, and when hostname is missing. + // In this case, try to extract the scheme using regex. + if (!$parsed && $matches = \preg_match('/^([a-z]+):\/\//', $value, $matches)) { + $parsed = ['scheme' => $matches[1] ?? '']; } - return true; + return $parsed; } /** diff --git a/src/Validator/URL/Pattern.php b/src/Validator/URL/Pattern.php new file mode 100644 index 00000000..df67249f --- /dev/null +++ b/src/Validator/URL/Pattern.php @@ -0,0 +1,22 @@ +schemes = $schemes; + + if (!is_array($hosts)) { + $hosts = [$hosts]; + } + $this->hosts = $hosts; + } +} From af44a7fe7b9e175713d931f4a1fdce4e9fb157c4 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Thu, 20 Feb 2025 09:54:09 +0000 Subject: [PATCH 2/2] fix: classname --- src/Validator/URL/Pattern.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Validator/URL/Pattern.php b/src/Validator/URL/Pattern.php index df67249f..2752d76d 100644 --- a/src/Validator/URL/Pattern.php +++ b/src/Validator/URL/Pattern.php @@ -2,7 +2,7 @@ namespace Utopia\Validator\URL; -class Patterns +class Pattern { public array $schemes; public array $hosts;