Buckets:
| /** | |
| * This file is part of the Nette Framework (https://nette.org) | |
| * Copyright (c) 2004 David Grudl (https://davidgrudl.com) | |
| */ | |
| declare(strict_types=1); | |
| namespace Nette\Utils; | |
| use Nette; | |
| /** | |
| * Validation utilities. | |
| */ | |
| class Validators | |
| { | |
| use Nette\StaticClass; | |
| private const BuiltinTypes = [ | |
| 'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1, | |
| 'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1, | |
| 'never' => 1, 'true' => 1, | |
| ]; | |
| /** @var array<string,?callable> */ | |
| protected static $validators = [ | |
| // PHP types | |
| 'array' => 'is_array', | |
| 'bool' => 'is_bool', | |
| 'boolean' => 'is_bool', | |
| 'float' => 'is_float', | |
| 'int' => 'is_int', | |
| 'integer' => 'is_int', | |
| 'null' => 'is_null', | |
| 'object' => 'is_object', | |
| 'resource' => 'is_resource', | |
| 'scalar' => 'is_scalar', | |
| 'string' => 'is_string', | |
| // pseudo-types | |
| 'callable' => [self::class, 'isCallable'], | |
| 'iterable' => 'is_iterable', | |
| 'list' => [Arrays::class, 'isList'], | |
| 'mixed' => [self::class, 'isMixed'], | |
| 'none' => [self::class, 'isNone'], | |
| 'number' => [self::class, 'isNumber'], | |
| 'numeric' => [self::class, 'isNumeric'], | |
| 'numericint' => [self::class, 'isNumericInt'], | |
| // string patterns | |
| 'alnum' => 'ctype_alnum', | |
| 'alpha' => 'ctype_alpha', | |
| 'digit' => 'ctype_digit', | |
| 'lower' => 'ctype_lower', | |
| 'pattern' => null, | |
| 'space' => 'ctype_space', | |
| 'unicode' => [self::class, 'isUnicode'], | |
| 'upper' => 'ctype_upper', | |
| 'xdigit' => 'ctype_xdigit', | |
| // syntax validation | |
| 'email' => [self::class, 'isEmail'], | |
| 'identifier' => [self::class, 'isPhpIdentifier'], | |
| 'uri' => [self::class, 'isUri'], | |
| 'url' => [self::class, 'isUrl'], | |
| // environment validation | |
| 'class' => 'class_exists', | |
| 'interface' => 'interface_exists', | |
| 'directory' => 'is_dir', | |
| 'file' => 'is_file', | |
| 'type' => [self::class, 'isType'], | |
| ]; | |
| /** @var array<string,callable> */ | |
| protected static $counters = [ | |
| 'string' => 'strlen', | |
| 'unicode' => [Strings::class, 'length'], | |
| 'array' => 'count', | |
| 'list' => 'count', | |
| 'alnum' => 'strlen', | |
| 'alpha' => 'strlen', | |
| 'digit' => 'strlen', | |
| 'lower' => 'strlen', | |
| 'space' => 'strlen', | |
| 'upper' => 'strlen', | |
| 'xdigit' => 'strlen', | |
| ]; | |
| /** | |
| * Verifies that the value is of expected types separated by pipe. | |
| * @throws AssertionException | |
| */ | |
| public static function assert(mixed $value, string $expected, string $label = 'variable'): void | |
| { | |
| if (!static::is($value, $expected)) { | |
| $expected = str_replace(['|', ':'], [' or ', ' in range '], $expected); | |
| $translate = ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float', 'NULL' => 'null']; | |
| $type = $translate[gettype($value)] ?? gettype($value); | |
| if (is_int($value) || is_float($value) || (is_string($value) && strlen($value) < 40)) { | |
| $type .= ' ' . var_export($value, return: true); | |
| } elseif (is_object($value)) { | |
| $type .= ' ' . $value::class; | |
| } | |
| throw new AssertionException("The $label expects to be $expected, $type given."); | |
| } | |
| } | |
| /** | |
| * Verifies that element $key in array is of expected types separated by pipe. | |
| * @param mixed[] $array | |
| * @throws AssertionException | |
| */ | |
| public static function assertField( | |
| array $array, | |
| $key, | |
| ?string $expected = null, | |
| string $label = "item '%' in array", | |
| ): void | |
| { | |
| if (!array_key_exists($key, $array)) { | |
| throw new AssertionException('Missing ' . str_replace('%', $key, $label) . '.'); | |
| } elseif ($expected) { | |
| static::assert($array[$key], $expected, str_replace('%', $key, $label)); | |
| } | |
| } | |
| /** | |
| * Verifies that the value is of expected types separated by pipe. | |
| */ | |
| public static function is(mixed $value, string $expected): bool | |
| { | |
| foreach (explode('|', $expected) as $item) { | |
| if (str_ends_with($item, '[]')) { | |
| if (is_iterable($value) && self::everyIs($value, substr($item, 0, -2))) { | |
| return true; | |
| } | |
| continue; | |
| } elseif (str_starts_with($item, '?')) { | |
| $item = substr($item, 1); | |
| if ($value === null) { | |
| return true; | |
| } | |
| } | |
| [$type] = $item = explode(':', $item, 2); | |
| if (isset(static::$validators[$type])) { | |
| try { | |
| if (!static::$validators[$type]($value)) { | |
| continue; | |
| } | |
| } catch (\TypeError $e) { | |
| continue; | |
| } | |
| } elseif ($type === 'pattern') { | |
| if (Strings::match($value, '|^' . ($item[1] ?? '') . '$|D')) { | |
| return true; | |
| } | |
| continue; | |
| } elseif (!$value instanceof $type) { | |
| continue; | |
| } | |
| if (isset($item[1])) { | |
| $length = $value; | |
| if (isset(static::$counters[$type])) { | |
| $length = static::$counters[$type]($value); | |
| } | |
| $range = explode('..', $item[1]); | |
| if (!isset($range[1])) { | |
| $range[1] = $range[0]; | |
| } | |
| if (($range[0] !== '' && $length < $range[0]) || ($range[1] !== '' && $length > $range[1])) { | |
| continue; | |
| } | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Finds whether all values are of expected types separated by pipe. | |
| * @param mixed[] $values | |
| */ | |
| public static function everyIs(iterable $values, string $expected): bool | |
| { | |
| foreach ($values as $value) { | |
| if (!static::is($value, $expected)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /** | |
| * Checks if the value is an integer or a float. | |
| * @return ($value is int|float ? true : false) | |
| */ | |
| public static function isNumber(mixed $value): bool | |
| { | |
| return is_int($value) || is_float($value); | |
| } | |
| /** | |
| * Checks if the value is an integer or a integer written in a string. | |
| * @return ($value is non-empty-string ? bool : ($value is int ? true : false)) | |
| */ | |
| public static function isNumericInt(mixed $value): bool | |
| { | |
| return is_int($value) || (is_string($value) && preg_match('#^[+-]?[0-9]+$#D', $value)); | |
| } | |
| /** | |
| * Checks if the value is a number or a number written in a string. | |
| * @return ($value is non-empty-string ? bool : ($value is int|float ? true : false)) | |
| */ | |
| public static function isNumeric(mixed $value): bool | |
| { | |
| return is_float($value) || is_int($value) || (is_string($value) && preg_match('#^[+-]?([0-9]++\.?[0-9]*|\.[0-9]+)$#D', $value)); | |
| } | |
| /** | |
| * Checks if the value is a syntactically correct callback. | |
| */ | |
| public static function isCallable(mixed $value): bool | |
| { | |
| return $value && is_callable($value, syntax_only: true); | |
| } | |
| /** | |
| * Checks if the value is a valid UTF-8 string. | |
| */ | |
| public static function isUnicode(mixed $value): bool | |
| { | |
| return is_string($value) && preg_match('##u', $value); | |
| } | |
| /** | |
| * Checks if the value is 0, '', false or null. | |
| * @return ($value is 0|''|false|null ? true : false) | |
| */ | |
| public static function isNone(mixed $value): bool | |
| { | |
| return $value == null; // intentionally == | |
| } | |
| /** @internal */ | |
| public static function isMixed(): bool | |
| { | |
| return true; | |
| } | |
| /** | |
| * Checks if a variable is a zero-based integer indexed array. | |
| * @deprecated use Nette\Utils\Arrays::isList | |
| * @return ($value is list ? true : false) | |
| */ | |
| public static function isList(mixed $value): bool | |
| { | |
| return Arrays::isList($value); | |
| } | |
| /** | |
| * Checks if the value is in the given range [min, max], where the upper or lower limit can be omitted (null). | |
| * Numbers, strings and DateTime objects can be compared. | |
| */ | |
| public static function isInRange(mixed $value, array $range): bool | |
| { | |
| if ($value === null || !(isset($range[0]) || isset($range[1]))) { | |
| return false; | |
| } | |
| $limit = $range[0] ?? $range[1]; | |
| if (is_string($limit)) { | |
| $value = (string) $value; | |
| } elseif ($limit instanceof \DateTimeInterface) { | |
| if (!$value instanceof \DateTimeInterface) { | |
| return false; | |
| } | |
| } elseif (is_numeric($value)) { | |
| $value *= 1; | |
| } else { | |
| return false; | |
| } | |
| return (!isset($range[0]) || ($value >= $range[0])) && (!isset($range[1]) || ($value <= $range[1])); | |
| } | |
| /** | |
| * Checks if the value is a valid email address. It does not verify that the domain actually exists, only the syntax is verified. | |
| */ | |
| public static function isEmail(string $value): bool | |
| { | |
| $atom = "[-a-z0-9!#$%&'*+/=?^_`{|}~]"; // RFC 5322 unquoted characters in local-part | |
| $alpha = "a-z\x80-\xFF"; // superset of IDN | |
| return (bool) preg_match(<<<XX | |
| (^(?n) | |
| ("([ !#-[\\]-~]*|\\\\[ -~])+"|$atom+(\\.$atom+)*) # quoted or unquoted | |
| @ | |
| ([0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)+ # domain - RFC 1034 | |
| [$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain | |
| $)Dix | |
| XX, $value); | |
| } | |
| /** | |
| * Checks if the value is a valid URL address. | |
| */ | |
| public static function isUrl(string $value): bool | |
| { | |
| $alpha = "a-z\x80-\xFF"; | |
| return (bool) preg_match(<<<XX | |
| (^(?n) | |
| https?://( | |
| (([-_0-9$alpha]+\\.)* # subdomain | |
| [0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)? # domain | |
| [$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain | |
| |\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3} # IPv4 | |
| |\\[[0-9a-f:]{3,39}\\] # IPv6 | |
| )(:\\d{1,5})? # port | |
| (/\\S*)? # path | |
| (\\?\\S*)? # query | |
| (\\#\\S*)? # fragment | |
| $)Dix | |
| XX, $value); | |
| } | |
| /** | |
| * Checks if the value is a valid URI address, that is, actually a string beginning with a syntactically valid schema. | |
| */ | |
| public static function isUri(string $value): bool | |
| { | |
| return (bool) preg_match('#^[a-z\d+\.-]+:\S+$#Di', $value); | |
| } | |
| /** | |
| * Checks whether the input is a class, interface or trait. | |
| * @deprecated | |
| */ | |
| public static function isType(string $type): bool | |
| { | |
| return class_exists($type) || interface_exists($type) || trait_exists($type); | |
| } | |
| /** | |
| * Checks whether the input is a valid PHP identifier. | |
| */ | |
| public static function isPhpIdentifier(string $value): bool | |
| { | |
| return preg_match('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#D', $value) === 1; | |
| } | |
| /** | |
| * Determines if type is PHP built-in type. Otherwise, it is the class name. | |
| */ | |
| public static function isBuiltinType(string $type): bool | |
| { | |
| return isset(self::BuiltinTypes[strtolower($type)]); | |
| } | |
| /** | |
| * Determines if type is special class name self/parent/static. | |
| */ | |
| public static function isClassKeyword(string $name): bool | |
| { | |
| return (bool) preg_match('#^(self|parent|static)$#Di', $name); | |
| } | |
| /** | |
| * Checks whether the given type declaration is syntactically valid. | |
| */ | |
| public static function isTypeDeclaration(string $type): bool | |
| { | |
| return (bool) preg_match(<<<'XX' | |
| ~((?n) | |
| \?? (?<type> \\? (?<name> [a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) (\\ (?&name))* ) | | |
| (?<intersection> (?&type) (& (?&type))+ ) | | |
| (?<upart> (?&type) | \( (?&intersection) \) ) (\| (?&upart))+ | |
| )$~xAD | |
| XX, $type); | |
| } | |
| } | |
Xet Storage Details
- Size:
- 10.7 kB
- Xet hash:
- 2f697537c0946c7426ad5e1188671753927f59ad2940ed36e3fa1cc96308aea7
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.