validation-bugsnag-email

This commit is contained in:
RafficMohammed
2023-01-31 13:17:59 +05:30
parent 2ec836b447
commit 9dd3f53910
769 changed files with 20242 additions and 14060 deletions

View File

@@ -20,7 +20,8 @@
"require-dev": {
"nette/tester": "~2.0",
"tracy/tracy": "^2.3",
"phpstan/phpstan": "^1.0"
"phpstan/phpstan": "^1.0",
"jetbrains/phpstorm-attributes": "dev-master"
},
"conflict": {
"nette/di": "<3.0.6"

View File

@@ -1,33 +0,0 @@
How to contribute & use the issue tracker
=========================================
Nette welcomes your contributions. There are several ways to help out:
* Create an issue on GitHub, if you have found a bug
* Write test cases for open bug issues
* Write fixes for open bug/feature issues, preferably with test cases included
* Contribute to the [documentation](https://nette.org/en/writing)
Issues
------
Please **do not use the issue tracker to ask questions**. We will be happy to help you
on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette).
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report.
**Feature requests** are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature.
Contributing
------------
If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing).
The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them.
Please do not fix whitespace, format code, or make a purely cosmetic patch.
Thanks! :heart:

View File

@@ -1,14 +0,0 @@
<?php
/**
* Rules for Nette Coding Standard
* https://github.com/nette/coding-standard
*/
declare(strict_types=1);
return [
// use function in Arrays.php, Callback.php, Html.php, Strings.php
'single_import_per_statement' => false,
'ordered_imports' => false,
];

View File

@@ -1,18 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Custom" namespace="Nette">
<rule ref="$presets/php72.xml"/>
<!-- bug in SlevomatCodingStandard -->
<rule ref="SlevomatCodingStandard.Operators.RequireCombinedAssignmentOperator">
<severity>0</severity>
</rule>
<!-- bug in FunctionSpacingSniff -->
<exclude-pattern>./tests/Utils/Reflection.getDeclaringMethod.alias.phpt</exclude-pattern>
<exclude-pattern>./tests/Utils/Reflection.getDeclaringMethod.insteadof.phpt</exclude-pattern>
<!-- use function in Arrays.php, Callback.php, Html.php, Strings.php -->
<rule ref="SlevomatCodingStandard.Namespaces.MultipleUsesPerLine.MultipleUsesPerLine">
<severity>0</severity>
</rule>
</ruleset>

View File

@@ -13,21 +13,21 @@ Introduction
In package nette/utils you will find a set of [useful classes](https://doc.nette.org/utils) for everyday use:
- [Arrays](https://doc.nette.org/arrays) - manipulate arrays
- [Callback](https://doc.nette.org/callback) - PHP callbacks
- [Date and Time](https://doc.nette.org/datetime) - modify times and dates
- [Filesystem](https://doc.nette.org/filesystem) - copying, renaming, …
- [Helper Functions](https://doc.nette.org/helpers)
- [HTML elements](https://doc.nette.org/html-elements) - generate HTML
- [Images](https://doc.nette.org/images) - crop, resize, rotate images
- [JSON](https://doc.nette.org/json) - encoding and decoding
- [Generating Random Strings](https://doc.nette.org/random)
- [Paginator](https://doc.nette.org/paginator) - pagination math
- [PHP Reflection](https://doc.nette.org/reflection)
- [Strings](https://doc.nette.org/strings) - useful text functions
- [SmartObject](https://doc.nette.org/smartobject) - PHP object enhancements
- [Validation](https://doc.nette.org/validators) - validate inputs
- [Type](https://doc.nette.org/type) - PHP data type
- [Arrays](https://doc.nette.org/utils/arrays) - manipulate arrays
- [Callback](https://doc.nette.org/utils/callback) - PHP callbacks
- [Date and Time](https://doc.nette.org/utils/datetime) - modify times and dates
- [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, …
- [Helper Functions](https://doc.nette.org/utils/helpers)
- [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML
- [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images
- [JSON](https://doc.nette.org/utils/json) - encoding and decoding
- [Generating Random Strings](https://doc.nette.org/utils/random)
- [Paginator](https://doc.nette.org/utils/paginator) - pagination math
- [PHP Reflection](https://doc.nette.org/utils/reflection)
- [Strings](https://doc.nette.org/utils/strings) - useful text functions
- [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements
- [Validation](https://doc.nette.org/utils/validators) - validate inputs
- [Type](https://doc.nette.org/utils/type) - PHP data type
Installation

View File

@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use JetBrains\PhpStorm\Language;
use Nette;
use function is_array, is_int, is_object, count;
@@ -203,7 +204,12 @@ class Arrays
* @param string[] $array
* @return string[]
*/
public static function grep(array $array, string $pattern, int $flags = 0): array
public static function grep(
array $array,
#[Language('RegExp')]
string $pattern,
int $flags = 0
): array
{
return Strings::pcre('preg_grep', [$pattern, $array, $flags]);
}

View File

@@ -157,7 +157,7 @@ final class Callback
*/
public static function isStatic(callable $callable): bool
{
return is_array($callable) ? is_string($callable[0]) : is_string($callable);
return is_string(is_array($callable) ? $callable[0] : $callable);
}

View File

@@ -393,7 +393,8 @@ class Image
$newWidth,
$newHeight,
int $flags = self::FIT
): array {
): array
{
if ($newWidth === null) {
} elseif (self::isPercent($newWidth)) {
$newWidth = (int) round($srcWidth / 100 * abs($newWidth));

View File

@@ -19,23 +19,12 @@ final class Reflection
{
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,
];
private const ClassKeywords = [
'self' => 1, 'parent' => 1, 'static' => 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)]);
return Validators::isBuiltinType($type);
}
@@ -44,7 +33,7 @@ final class Reflection
*/
public static function isClassKeyword(string $name): bool
{
return isset(self::ClassKeywords[strtolower($name)]);
return Validators::isClassKeyword($name);
}
@@ -261,7 +250,7 @@ final class Reflection
if (empty($name)) {
throw new Nette\InvalidArgumentException('Class name must not be empty.');
} elseif (isset(self::BuiltinTypes[$lower])) {
} elseif (Validators::isBuiltinType($lower)) {
return $lower;
} elseif ($lower === 'self' || $lower === 'static') {

View File

@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use JetBrains\PhpStorm\Language;
use Nette;
use function is_array, is_object, strlen;
@@ -485,7 +486,12 @@ class Strings
* Splits a string into array by the regular expression. Parenthesized expression in the delimiter are captured.
* Parameter $flags can be any combination of PREG_SPLIT_NO_EMPTY and PREG_OFFSET_CAPTURE flags.
*/
public static function split(string $subject, string $pattern, int $flags = 0): array
public static function split(
string $subject,
#[Language('RegExp')]
string $pattern,
int $flags = 0
): array
{
return self::pcre('preg_split', [$pattern, $subject, -1, $flags | PREG_SPLIT_DELIM_CAPTURE]);
}
@@ -495,7 +501,13 @@ class Strings
* Checks if given string matches a regular expression pattern and returns an array with first found match and each subpattern.
* Parameter $flags can be any combination of PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags.
*/
public static function match(string $subject, string $pattern, int $flags = 0, int $offset = 0): ?array
public static function match(
string $subject,
#[Language('RegExp')]
string $pattern,
int $flags = 0,
int $offset = 0
): ?array
{
if ($offset > strlen($subject)) {
return null;
@@ -511,7 +523,13 @@ class Strings
* Finds all occurrences matching regular expression pattern and returns a two-dimensional array. Result is array of matches (ie uses by default PREG_SET_ORDER).
* Parameter $flags can be any combination of PREG_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL and PREG_PATTERN_ORDER flags.
*/
public static function matchAll(string $subject, string $pattern, int $flags = 0, int $offset = 0): array
public static function matchAll(
string $subject,
#[Language('RegExp')]
string $pattern,
int $flags = 0,
int $offset = 0
): array
{
if ($offset > strlen($subject)) {
return [];
@@ -531,7 +549,13 @@ class Strings
* @param string|array $pattern
* @param string|callable $replacement
*/
public static function replace(string $subject, $pattern, $replacement = '', int $limit = -1): string
public static function replace(
string $subject,
#[Language('RegExp')]
$pattern,
$replacement = '',
int $limit = -1
): string
{
if (is_object($replacement) || is_array($replacement)) {
if (!is_callable($replacement, false, $textual)) {

View File

@@ -17,11 +17,11 @@ use Nette;
*/
final class Type
{
/** @var array */
/** @var array<int, string|self> */
private $types;
/** @var bool */
private $single;
private $simple;
/** @var string |, & */
private $kind;
@@ -44,24 +44,29 @@ final class Type
: $reflection->getType();
}
if ($type === null) {
return null;
return $type ? self::fromReflectionType($type, $reflection, true) : null;
}
} elseif ($type instanceof \ReflectionNamedType) {
$name = self::resolve($type->getName(), $reflection);
return new self($type->allowsNull() && $type->getName() !== 'mixed' ? [$name, 'null'] : [$name]);
private static function fromReflectionType(\ReflectionType $type, $of, bool $asObject)
{
if ($type instanceof \ReflectionNamedType) {
$name = self::resolve($type->getName(), $of);
return $asObject
? new self($type->allowsNull() && $name !== 'mixed' ? [$name, 'null'] : [$name])
: $name;
} elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
return new self(
array_map(
function ($t) use ($reflection) { return self::resolve($t->getName(), $reflection); },
function ($t) use ($of) { return self::fromReflectionType($t, $of, false); },
$type->getTypes()
),
$type instanceof \ReflectionUnionType ? '|' : '&'
);
} else {
throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($reflection));
throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($of));
}
}
@@ -71,37 +76,39 @@ final class Type
*/
public static function fromString(string $type): self
{
if (!preg_match('#(?:
\?([\w\\\\]+)|
[\w\\\\]+ (?: (&[\w\\\\]+)* | (\|[\w\\\\]+)* )
)()$#xAD', $type, $m)) {
if (!Validators::isTypeDeclaration($type)) {
throw new Nette\InvalidArgumentException("Invalid type '$type'.");
}
[, $nType, $iType] = $m;
if ($nType) {
return new self([$nType, 'null']);
} elseif ($iType) {
return new self(explode('&', $type), '&');
} else {
return new self(explode('|', $type));
if ($type[0] === '?') {
return new self([substr($type, 1), 'null']);
}
$unions = [];
foreach (explode('|', $type) as $part) {
$part = explode('&', trim($part, '()'));
$unions[] = count($part) === 1 ? $part[0] : new self($part, '&');
}
return count($unions) === 1 && $unions[0] instanceof self
? $unions[0]
: new self($unions);
}
/**
* Resolves 'self', 'static' and 'parent' to the actual class name.
* @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection
* @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $of
*/
public static function resolve(string $type, $reflection): string
public static function resolve(string $type, $of): string
{
$lower = strtolower($type);
if ($reflection instanceof \ReflectionFunction) {
if ($of instanceof \ReflectionFunction) {
return $type;
} elseif ($lower === 'self' || $lower === 'static') {
return $reflection->getDeclaringClass()->name;
} elseif ($lower === 'parent' && $reflection->getDeclaringClass()->getParentClass()) {
return $reflection->getDeclaringClass()->getParentClass()->name;
return $of->getDeclaringClass()->name;
} elseif ($lower === 'parent' && $of->getDeclaringClass()->getParentClass()) {
return $of->getDeclaringClass()->getParentClass()->name;
} else {
return $type;
}
@@ -110,31 +117,42 @@ final class Type
private function __construct(array $types, string $kind = '|')
{
if ($types[0] === 'null') { // null as last
array_push($types, array_shift($types));
$o = array_search('null', $types, true);
if ($o !== false) { // null as last
array_splice($types, $o, 1);
$types[] = 'null';
}
$this->types = $types;
$this->single = ($types[1] ?? 'null') === 'null';
$this->simple = is_string($types[0]) && ($types[1] ?? 'null') === 'null';
$this->kind = count($types) > 1 ? $kind : '';
}
public function __toString(): string
{
return $this->single
? (count($this->types) > 1 ? '?' : '') . $this->types[0]
: implode($this->kind, $this->types);
$multi = count($this->types) > 1;
if ($this->simple) {
return ($multi ? '?' : '') . $this->types[0];
}
$res = [];
foreach ($this->types as $type) {
$res[] = $type instanceof self && $multi ? "($type)" : $type;
}
return implode($this->kind, $res);
}
/**
* Returns the array of subtypes that make up the compound type as strings.
* @return string[]
* @return array<int, string|string[]>
*/
public function getNames(): array
{
return $this->types;
return array_map(function ($t) {
return $t instanceof self ? $t->getNames() : $t;
}, $this->types);
}
@@ -144,16 +162,18 @@ final class Type
*/
public function getTypes(): array
{
return array_map(function ($name) { return self::fromString($name); }, $this->types);
return array_map(function ($t) {
return $t instanceof self ? $t : new self([$t]);
}, $this->types);
}
/**
* Returns the type name for single types, otherwise null.
* Returns the type name for simple types, otherwise null.
*/
public function getSingleName(): ?string
{
return $this->single
return $this->simple
? $this->types[0]
: null;
}
@@ -178,29 +198,36 @@ final class Type
/**
* Returns true whether it is a single type. Simple nullable types are also considered to be single types.
* Returns true whether it is a simple type. Single nullable types are also considered to be simple types.
*/
public function isSimple(): bool
{
return $this->simple;
}
/** @deprecated use isSimple() */
public function isSingle(): bool
{
return $this->single;
return $this->simple;
}
/**
* Returns true whether the type is both a single and a PHP built-in type.
* Returns true whether the type is both a simple and a PHP built-in type.
*/
public function isBuiltin(): bool
{
return $this->single && Reflection::isBuiltinType($this->types[0]);
return $this->simple && Validators::isBuiltinType($this->types[0]);
}
/**
* Returns true whether the type is both a single and a class name.
* Returns true whether the type is both a simple and a class name.
*/
public function isClass(): bool
{
return $this->single && !Reflection::isBuiltinType($this->types[0]);
return $this->simple && !Validators::isBuiltinType($this->types[0]);
}
@@ -209,43 +236,46 @@ final class Type
*/
public function isClassKeyword(): bool
{
return $this->single && Reflection::isClassKeyword($this->types[0]);
return $this->simple && Validators::isClassKeyword($this->types[0]);
}
/**
* Verifies type compatibility. For example, it checks if a value of a certain type could be passed as a parameter.
*/
public function allows(string $type): bool
public function allows(string $subtype): bool
{
if ($this->types === ['mixed']) {
return true;
}
$type = self::fromString($type);
$subtype = self::fromString($subtype);
return $subtype->isUnion()
? Arrays::every($subtype->types, function ($t) {
return $this->allows2($t instanceof self ? $t->types : [$t]);
})
: $this->allows2($subtype->types);
}
if ($this->isIntersection()) {
if (!$type->isIntersection()) {
return false;
}
return Arrays::every($this->types, function ($currentType) use ($type) {
$builtin = Reflection::isBuiltinType($currentType);
return Arrays::some($type->types, function ($testedType) use ($currentType, $builtin) {
return $builtin
? strcasecmp($currentType, $testedType) === 0
: is_a($testedType, $currentType, true);
});
});
}
private function allows2(array $subtypes): bool
{
return $this->isUnion()
? Arrays::some($this->types, function ($t) use ($subtypes) {
return $this->allows3($t instanceof self ? $t->types : [$t], $subtypes);
})
: $this->allows3($this->types, $subtypes);
}
$method = $type->isIntersection() ? 'some' : 'every';
return Arrays::$method($type->types, function ($testedType) {
$builtin = Reflection::isBuiltinType($testedType);
return Arrays::some($this->types, function ($currentType) use ($testedType, $builtin) {
private function allows3(array $types, array $subtypes): bool
{
return Arrays::every($types, function ($type) use ($subtypes) {
$builtin = Validators::isBuiltinType($type);
return Arrays::some($subtypes, function ($subtype) use ($type, $builtin) {
return $builtin
? strcasecmp($currentType, $testedType) === 0
: is_a($testedType, $currentType, true);
? strcasecmp($type, $subtype) === 0
: is_a($subtype, $type, true);
});
});
}

View File

@@ -19,6 +19,12 @@ 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
@@ -118,7 +124,8 @@ class Validators
$key,
?string $expected = null,
string $label = "item '%' in array"
): void {
): void
{
if (!array_key_exists($key, $array)) {
throw new AssertionException('Missing ' . str_replace('%', $key, $label) . '.');
@@ -327,7 +334,7 @@ class Validators
[$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain
$)Dix
XX
, $value);
, $value);
}
@@ -351,7 +358,7 @@ XX
(\\#\\S*)? # fragment
$)Dix
XX
, $value);
, $value);
}
@@ -380,4 +387,38 @@ XX
{
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'
~(
\?? (?<type> \\? (?<name> [a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) (\\ (?&name))* ) |
(?<intersection> (?&type) (& (?&type))+ ) |
(?<upart> (?&type) | \( (?&intersection) \) ) (\| (?&upart))+
)$~xAD
XX
, $type);
}
}