From e83948c06df742b9af4ea5dc85132bd2067003c4 Mon Sep 17 00:00:00 2001 From: BackEndTea Date: Wed, 1 Jan 2020 13:28:58 +0100 Subject: [PATCH 1/3] Add support for FILTER_NULL_ON_FAILURE flag This works for all validates, but not sanitizes. For now this lacks support for bit masks, e.g.: `FILTER_FLAG_IPV4 | FILTER_NULL_ON_FAILURE`. The reason for this is that there is also a `FILTER_FORCE_ARRAY` flag, which puts the result in an array. This option, or bit masks, aren't supported either right now. So adding support for bitmasks without `FILTER_FORCE_ARRAY` would result in more false positives --- .../FilterVarDynamicReturnTypeExtension.php | 42 ++++++++++++ .../Analyser/NodeScopeResolverTest.php | 68 +++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php index b6b14ccee4..08233cd2a9 100644 --- a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Php; +use PhpParser\Node; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; @@ -12,6 +13,7 @@ use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; +use PHPStan\Type\NullType; use PHPStan\Type\StringType; use PHPStan\Type\Type; use PHPStan\Type\UnionType; @@ -22,12 +24,19 @@ class FilterVarDynamicReturnTypeExtension implements DynamicFunctionReturnTypeEx /** @var array */ private $filterTypesHashMaps; + /** @var array */ + private $nullableTypes; + public function __construct() { $booleanType = new BooleanType(); + $nullableBooleanType = new UnionType([new BooleanType(), new NullType()]); $floatOrFalseType = new UnionType([new FloatType(), new ConstantBooleanType(false)]); + $nullableFloatType = new UnionType([new FloatType(), new NullType()]); $intOrFalseType = new UnionType([new IntegerType(), new ConstantBooleanType(false)]); + $nullableIntType = new UnionType([new IntegerType(), new NullType()]); $stringOrFalseType = new UnionType([new StringType(), new ConstantBooleanType(false)]); + $nullableStringType = new UnionType([new StringType(), new NullType()]); $this->filterTypesHashMaps = [ 'FILTER_SANITIZE_EMAIL' => $stringOrFalseType, @@ -47,6 +56,17 @@ public function __construct() 'FILTER_VALIDATE_REGEXP' => $stringOrFalseType, 'FILTER_VALIDATE_URL' => $stringOrFalseType, ]; + + $this->nullableTypes = [ + 'FILTER_VALIDATE_BOOLEAN' => $nullableBooleanType, + 'FILTER_VALIDATE_EMAIL' => $nullableStringType, + 'FILTER_VALIDATE_FLOAT' => $nullableFloatType, + 'FILTER_VALIDATE_INT' => $nullableIntType, + 'FILTER_VALIDATE_IP' => $nullableStringType, + 'FILTER_VALIDATE_MAC' => $nullableStringType, + 'FILTER_VALIDATE_REGEXP' => $nullableStringType, + 'FILTER_VALIDATE_URL' => $nullableStringType, + ]; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -74,7 +94,29 @@ public function getTypeFromFunctionCall( $filterName = (string) $filterExpr->name; + if ($this->isNullableType($filterName, $functionCall->args[2] ?? null)) { + return $this->nullableTypes[$filterName]; + } + return $this->filterTypesHashMaps[$filterName] ?? $mixedType; } + private function isNullableType(string $filterName, ?Node\Arg $thirdArg): bool + { + if ($thirdArg === null || !array_key_exists($filterName, $this->nullableTypes)) { + return false; + } + + $expr = $thirdArg->value; + if ($expr instanceof Node\Expr\Array_) { + foreach ($expr->items as $item) { + if ($item->key instanceof Node\Scalar\String_ && $item->key->value === 'flags') { + $expr = $item->value; + break; + } + } + } + return $expr instanceof ConstFetch && (string) $expr->name === 'FILTER_NULL_ON_FAILURE'; + } + } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 0126a9bd01..cd508646a1 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -8038,34 +8038,102 @@ public function dataFilterVar(): array 'bool', 'filter_var($mixed, FILTER_VALIDATE_BOOLEAN)', ], + [ + 'bool|null', + 'filter_var($mixed, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)', + ], + [ + 'bool|null', + 'filter_var($mixed, FILTER_VALIDATE_BOOLEAN ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_EMAIL)', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE)', + ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_EMAIL ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'float|false', 'filter_var($mixed, FILTER_VALIDATE_FLOAT)', ], + [ + 'float|null', + 'filter_var($mixed, FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE)', + ], + [ + 'float|null', + 'filter_var($mixed, FILTER_VALIDATE_FLOAT ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'int|false', 'filter_var($mixed, FILTER_VALIDATE_INT)', ], + [ + 'int|null', + 'filter_var($mixed, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE)', + ], + [ + 'int|null', + 'filter_var($mixed, FILTER_VALIDATE_INT ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_IP)', ], + [ + 'string|false', + 'filter_var($mixed, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)', + ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE)', + ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_IP ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_MAC)', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_MAC, FILTER_NULL_ON_FAILURE)', + ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_MAC ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_REGEXP)', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_REGEXP, FILTER_NULL_ON_FAILURE)', + ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_REGEXP ,["flags" => FILTER_NULL_ON_FAILURE])', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_URL)', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)', + ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_URL ,["flags" => FILTER_NULL_ON_FAILURE])', + ], ]; } From bc1a93caa631eb4ef9d09b1a06225bc35226db8c Mon Sep 17 00:00:00 2001 From: BackEndTea Date: Thu, 2 Jan 2020 12:29:10 +0100 Subject: [PATCH 2/3] Rework filter var dynamic return to use typesystem This includes support for bit masks, and force array. It also updates the old implementation of retrieving the constant, to use the type system as well, allow usage of variables. --- .../FilterVarDynamicReturnTypeExtension.php | 140 +++++++++++------- .../Analyser/NodeScopeResolverTest.php | 53 +++++++ tests/PHPStan/Analyser/data/filterVar.php | 3 + 3 files changed, 145 insertions(+), 51 deletions(-) diff --git a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php index 08233cd2a9..709e1cd426 100644 --- a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php @@ -3,12 +3,15 @@ namespace PHPStan\Type\Php; use PhpParser\Node; -use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; +use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; +use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; +use PHPStan\Type\Constant\ConstantIntegerType; +use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; @@ -21,52 +24,64 @@ class FilterVarDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** @var array */ + /** @var array */ private $filterTypesHashMaps; - /** @var array */ + /** @var array */ private $nullableTypes; + /** @var ConstantStringType */ + private $flagsString; + public function __construct() { $booleanType = new BooleanType(); - $nullableBooleanType = new UnionType([new BooleanType(), new NullType()]); - $floatOrFalseType = new UnionType([new FloatType(), new ConstantBooleanType(false)]); - $nullableFloatType = new UnionType([new FloatType(), new NullType()]); - $intOrFalseType = new UnionType([new IntegerType(), new ConstantBooleanType(false)]); - $nullableIntType = new UnionType([new IntegerType(), new NullType()]); - $stringOrFalseType = new UnionType([new StringType(), new ConstantBooleanType(false)]); - $nullableStringType = new UnionType([new StringType(), new NullType()]); + $floatType = new FloatType(); + $intType = new IntegerType(); + $stringType = new StringType(); + + $nullType = new NullType(); + $falseType = new ConstantBooleanType(false); + + $nullableBooleanType = new UnionType([$booleanType, $nullType]); + $floatOrFalseType = new UnionType([$floatType, $falseType]); + $nullableFloatType = new UnionType([$floatType, $nullType]); + $intOrFalseType = new UnionType([$intType, $falseType]); + $nullableIntType = new UnionType([$intType, $nullType]); + $stringOrFalseType = new UnionType([$stringType, $falseType]); + $nullableStringType = new UnionType([$stringType, $nullType]); $this->filterTypesHashMaps = [ - 'FILTER_SANITIZE_EMAIL' => $stringOrFalseType, - 'FILTER_SANITIZE_ENCODED' => $stringOrFalseType, - 'FILTER_SANITIZE_MAGIC_QUOTES' => $stringOrFalseType, - 'FILTER_SANITIZE_NUMBER_FLOAT' => $stringOrFalseType, - 'FILTER_SANITIZE_NUMBER_INT' => $stringOrFalseType, - 'FILTER_SANITIZE_SPECIAL_CHARS' => $stringOrFalseType, - 'FILTER_SANITIZE_STRING' => $stringOrFalseType, - 'FILTER_SANITIZE_URL' => $stringOrFalseType, - 'FILTER_VALIDATE_BOOLEAN' => $booleanType, - 'FILTER_VALIDATE_EMAIL' => $stringOrFalseType, - 'FILTER_VALIDATE_FLOAT' => $floatOrFalseType, - 'FILTER_VALIDATE_INT' => $intOrFalseType, - 'FILTER_VALIDATE_IP' => $stringOrFalseType, - 'FILTER_VALIDATE_MAC' => $stringOrFalseType, - 'FILTER_VALIDATE_REGEXP' => $stringOrFalseType, - 'FILTER_VALIDATE_URL' => $stringOrFalseType, + FILTER_SANITIZE_EMAIL => $stringOrFalseType, + FILTER_SANITIZE_ENCODED => $stringOrFalseType, + FILTER_SANITIZE_MAGIC_QUOTES => $stringOrFalseType, + FILTER_SANITIZE_NUMBER_FLOAT => $stringOrFalseType, + FILTER_SANITIZE_NUMBER_INT => $stringOrFalseType, + FILTER_SANITIZE_SPECIAL_CHARS => $stringOrFalseType, + FILTER_SANITIZE_STRING => $stringOrFalseType, + FILTER_SANITIZE_URL => $stringOrFalseType, + FILTER_VALIDATE_BOOLEAN => $booleanType, + FILTER_VALIDATE_EMAIL => $stringOrFalseType, + FILTER_VALIDATE_FLOAT => $floatOrFalseType, + FILTER_VALIDATE_INT => $intOrFalseType, + FILTER_VALIDATE_IP => $stringOrFalseType, + FILTER_VALIDATE_MAC => $stringOrFalseType, + FILTER_VALIDATE_REGEXP => $stringOrFalseType, + FILTER_VALIDATE_URL => $stringOrFalseType, ]; $this->nullableTypes = [ - 'FILTER_VALIDATE_BOOLEAN' => $nullableBooleanType, - 'FILTER_VALIDATE_EMAIL' => $nullableStringType, - 'FILTER_VALIDATE_FLOAT' => $nullableFloatType, - 'FILTER_VALIDATE_INT' => $nullableIntType, - 'FILTER_VALIDATE_IP' => $nullableStringType, - 'FILTER_VALIDATE_MAC' => $nullableStringType, - 'FILTER_VALIDATE_REGEXP' => $nullableStringType, - 'FILTER_VALIDATE_URL' => $nullableStringType, + FILTER_VALIDATE_BOOLEAN => $nullableBooleanType, + FILTER_VALIDATE_EMAIL => $nullableStringType, + FILTER_VALIDATE_FLOAT => $nullableFloatType, + FILTER_VALIDATE_INT => $nullableIntType, + FILTER_VALIDATE_IP => $nullableStringType, + FILTER_VALIDATE_MAC => $nullableStringType, + FILTER_VALIDATE_REGEXP => $nullableStringType, + FILTER_VALIDATE_URL => $nullableStringType, ]; + + $this->flagsString = new ConstantStringType('flags'); } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -87,36 +102,59 @@ public function getTypeFromFunctionCall( return $mixedType; } - $filterExpr = $filterArg->value; - if (!$filterExpr instanceof ConstFetch) { + $filterType = $scope->getType($filterArg->value); + if (!$filterType instanceof ConstantIntegerType) { return $mixedType; } - $filterName = (string) $filterExpr->name; + $filterValue = $filterType->getValue(); + + $flagsArg = $functionCall->args[2] ?? null; + if ($this->isNullableType($filterValue, $flagsArg, $scope)) { + $type = $this->nullableTypes[$filterValue]; + } else { + $type = $this->filterTypesHashMaps[$filterValue] ?? $mixedType; + } + + if ($this->isForcedArrayType($flagsArg, $scope)) { + return new ArrayType(new MixedType(), $type); + } + + return $type; + } - if ($this->isNullableType($filterName, $functionCall->args[2] ?? null)) { - return $this->nullableTypes[$filterName]; + private function isNullableType(int $filterValue, ?Node\Arg $flagsArg, Scope $scope): bool + { + if ($flagsArg === null || !array_key_exists($filterValue, $this->nullableTypes)) { + return false; } - return $this->filterTypesHashMaps[$filterName] ?? $mixedType; + return $this->hasFlag(FILTER_NULL_ON_FAILURE, $flagsArg, $scope); } - private function isNullableType(string $filterName, ?Node\Arg $thirdArg): bool + private function isForcedArrayType(?Node\Arg $flagsArg, Scope $scope): bool { - if ($thirdArg === null || !array_key_exists($filterName, $this->nullableTypes)) { + if ($flagsArg === null) { return false; } - $expr = $thirdArg->value; - if ($expr instanceof Node\Expr\Array_) { - foreach ($expr->items as $item) { - if ($item->key instanceof Node\Scalar\String_ && $item->key->value === 'flags') { - $expr = $item->value; - break; - } - } + return $this->hasFlag(FILTER_FORCE_ARRAY, $flagsArg, $scope); + } + + private function hasFlag(int $flag, Node\Arg $expression, Scope $scope): bool + { + $type = $this->getFlagsValue($scope->getType($expression->value)); + + return $type instanceof ConstantIntegerType && ($type->getValue() & $flag) === $flag; + } + + private function getFlagsValue(Type $exprType): Type + { + if (!$exprType instanceof ConstantArrayType) { + return $exprType; } - return $expr instanceof ConstFetch && (string) $expr->name === 'FILTER_NULL_ON_FAILURE'; + + return $exprType->getOffsetValueType($this->flagsString); } } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index cd508646a1..3e21f8c29e 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -8006,6 +8006,10 @@ public function dataFilterVar(): array 'string|false', 'filter_var($mixed, FILTER_SANITIZE_EMAIL)', ], + [ + 'array', + 'filter_var($mixed, FILTER_SANITIZE_EMAIL, FILTER_FORCE_ARRAY)', + ], [ 'string|false', 'filter_var($mixed, FILTER_SANITIZE_ENCODED)', @@ -8066,6 +8070,19 @@ public function dataFilterVar(): array 'float|null', 'filter_var($mixed, FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE)', ], + + [ + 'array', + 'filter_var($mixed, FILTER_VALIDATE_FLOAT, FILTER_FORCE_ARRAY)', + ], + [ + 'array', + 'filter_var($mixed, FILTER_VALIDATE_FLOAT, FILTER_FORCE_ARRAY | FILTER_NULL_ON_FAILURE)', + ], + [ + 'array', + 'filter_var($mixed, FILTER_VALIDATE_FLOAT, $forceArrayFilter | $nullFilter)', + ], [ 'float|null', 'filter_var($mixed, FILTER_VALIDATE_FLOAT ,["flags" => FILTER_NULL_ON_FAILURE])', @@ -8086,6 +8103,10 @@ public function dataFilterVar(): array 'string|false', 'filter_var($mixed, FILTER_VALIDATE_IP)', ], + [ + 'string|false', + 'filter_var($mixed, $filterIp)', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)', @@ -8094,6 +8115,14 @@ public function dataFilterVar(): array 'string|null', 'filter_var($mixed, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE)', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)', + ], + [ + 'array', + 'filter_var($mixed, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4 | FILTER_FORCE_ARRAY)', + ], [ 'string|null', 'filter_var($mixed, FILTER_VALIDATE_IP ,["flags" => FILTER_NULL_ON_FAILURE])', @@ -8114,6 +8143,10 @@ public function dataFilterVar(): array 'string|false', 'filter_var($mixed, FILTER_VALIDATE_REGEXP)', ], + [ + 'string|false', + 'filter_var($mixed, FILTER_VALIDATE_REGEXP, ["options" => ["regexp" => "/match/"]])', + ], [ 'string|null', 'filter_var($mixed, FILTER_VALIDATE_REGEXP, FILTER_NULL_ON_FAILURE)', @@ -8122,18 +8155,38 @@ public function dataFilterVar(): array 'string|null', 'filter_var($mixed, FILTER_VALIDATE_REGEXP ,["flags" => FILTER_NULL_ON_FAILURE])', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_REGEXP ,["flags" => FILTER_NULL_ON_FAILURE, "options" => ["regexp" => "/match/"]])', + ], [ 'string|false', 'filter_var($mixed, FILTER_VALIDATE_URL)', ], + [ + 'string|false', + 'filter_var($mixed, FILTER_VALIDATE_URL, $mixed)', + ], + [ + 'string|false', + 'filter_var($mixed, FILTER_VALIDATE_URL ,["flags" => $mixed])', + ], [ 'string|null', 'filter_var($mixed, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_URL, $nullFilter)', + ], [ 'string|null', 'filter_var($mixed, FILTER_VALIDATE_URL ,["flags" => FILTER_NULL_ON_FAILURE])', ], + [ + 'string|null', + 'filter_var($mixed, FILTER_VALIDATE_URL ,["flags" => $nullFilter])', + ], ]; } diff --git a/tests/PHPStan/Analyser/data/filterVar.php b/tests/PHPStan/Analyser/data/filterVar.php index 70317ea60a..a66c0fe1f5 100644 --- a/tests/PHPStan/Analyser/data/filterVar.php +++ b/tests/PHPStan/Analyser/data/filterVar.php @@ -5,6 +5,9 @@ function () { /** @var mixed $mixed */ $mixed = null; + $nullFilter = \FILTER_NULL_ON_FAILURE; + $forceArrayFilter = \FILTER_FORCE_ARRAY; + $filterIp = FILTER_VALIDATE_IP; die; }; From b2955d20f3b031bf74778dd505714a9ab631300a Mon Sep 17 00:00:00 2001 From: BackEndTea Date: Thu, 2 Jan 2020 13:35:36 +0100 Subject: [PATCH 3/3] Check for filter extension All of the constants got added way before php 7.1, so there is no need to check for each of them individually. --- build/composer-require-checker.json | 6 +++++- src/Type/Php/FilterVarDynamicReturnTypeExtension.php | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build/composer-require-checker.json b/build/composer-require-checker.json index bff20de50f..879f93aa40 100644 --- a/build/composer-require-checker.json +++ b/build/composer-require-checker.json @@ -4,7 +4,11 @@ "static", "self", "parent", "array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "PHPUnit\\Framework\\TestCase", "PHPUnit\\Framework\\AssertionFailedError", - "JSON_THROW_ON_ERROR", "SimpleXMLElement", "PHPStan\\ExtensionInstaller\\GeneratedConfig", "Nette\\DI\\InvalidConfigurationException" + "JSON_THROW_ON_ERROR", "SimpleXMLElement", "PHPStan\\ExtensionInstaller\\GeneratedConfig", "Nette\\DI\\InvalidConfigurationException", + "FILTER_SANITIZE_EMAIL", "FILTER_SANITIZE_EMAIL", "FILTER_SANITIZE_ENCODED", "FILTER_SANITIZE_MAGIC_QUOTES", "FILTER_SANITIZE_NUMBER_FLOAT", + "FILTER_SANITIZE_NUMBER_INT", "FILTER_SANITIZE_SPECIAL_CHARS", "FILTER_SANITIZE_STRING", "FILTER_SANITIZE_URL", "FILTER_VALIDATE_BOOLEAN", + "FILTER_VALIDATE_EMAIL", "FILTER_VALIDATE_FLOAT", "FILTER_VALIDATE_INT", "FILTER_VALIDATE_IP", "FILTER_VALIDATE_MAC", "FILTER_VALIDATE_REGEXP", + "FILTER_VALIDATE_URL", "FILTER_NULL_ON_FAILURE", "FILTER_FORCE_ARRAY" ], "php-core-extensions" : [ "Core", diff --git a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php index 709e1cd426..e58ed9f7da 100644 --- a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php @@ -35,6 +35,10 @@ class FilterVarDynamicReturnTypeExtension implements DynamicFunctionReturnTypeEx public function __construct() { + if (!defined('FILTER_SANITIZE_EMAIL')) { + return; + } + $booleanType = new BooleanType(); $floatType = new FloatType(); $intType = new IntegerType(); @@ -86,7 +90,7 @@ public function __construct() public function isFunctionSupported(FunctionReflection $functionReflection): bool { - return strtolower($functionReflection->getName()) === 'filter_var'; + return defined('FILTER_SANITIZE_EMAIL') && strtolower($functionReflection->getName()) === 'filter_var'; } public function getTypeFromFunctionCall(