mirror of
https://github.com/standardebooks/web.git
synced 2025-07-21 14:55:13 -04:00
Add Safe PHP functions
This commit is contained in:
parent
04a956886a
commit
58cc098058
260 changed files with 49458 additions and 45 deletions
43
vendor/thecodingmachine/phpstan-safe-rule/src/Rules/UseSafeFunctionsRule.php
vendored
Normal file
43
vendor/thecodingmachine/phpstan-safe-rule/src/Rules/UseSafeFunctionsRule.php
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace TheCodingMachine\Safe\PHPStan\Rules;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\FunctionReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Rules\Rule;
|
||||
use PHPStan\ShouldNotHappenException;
|
||||
use TheCodingMachine\Safe\PHPStan\Utils\FunctionListLoader;
|
||||
|
||||
/**
|
||||
* This rule checks that no superglobals are used in code.
|
||||
*/
|
||||
class UseSafeFunctionsRule implements Rule
|
||||
{
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return Node\Expr\FuncCall::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node\Expr\FuncCall $node
|
||||
* @param \PHPStan\Analyser\Scope $scope
|
||||
* @return string[]
|
||||
*/
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
if (!$node->name instanceof Node\Name) {
|
||||
return [];
|
||||
}
|
||||
$functionName = $node->name->toString();
|
||||
$unsafeFunctions = FunctionListLoader::getFunctionList();
|
||||
|
||||
if (isset($unsafeFunctions[$functionName])) {
|
||||
return ["Function $functionName is unsafe to use. It can return FALSE instead of throwing an exception. Please add 'use function Safe\\$functionName;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library."];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
|
||||
namespace TheCodingMachine\Safe\PHPStan\Type\Php;
|
||||
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\FunctionReflection;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeCombinator;
|
||||
use PHPStan\Type\TypeUtils;
|
||||
|
||||
class ReplaceSafeFunctionsDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
|
||||
{
|
||||
|
||||
/** @var array<string, int> */
|
||||
private $functions = [
|
||||
'Safe\preg_replace' => 2,
|
||||
];
|
||||
|
||||
public function isFunctionSupported(FunctionReflection $functionReflection): bool
|
||||
{
|
||||
return array_key_exists($functionReflection->getName(), $this->functions);
|
||||
}
|
||||
|
||||
public function getTypeFromFunctionCall(
|
||||
FunctionReflection $functionReflection,
|
||||
FuncCall $functionCall,
|
||||
Scope $scope
|
||||
): Type {
|
||||
$type = $this->getPreliminarilyResolvedTypeFromFunctionCall($functionReflection, $functionCall, $scope);
|
||||
|
||||
$possibleTypes = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
|
||||
|
||||
if (TypeCombinator::containsNull($possibleTypes)) {
|
||||
$type = TypeCombinator::addNull($type);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
private function getPreliminarilyResolvedTypeFromFunctionCall(
|
||||
FunctionReflection $functionReflection,
|
||||
FuncCall $functionCall,
|
||||
Scope $scope
|
||||
): Type {
|
||||
$argumentPosition = $this->functions[$functionReflection->getName()];
|
||||
if (count($functionCall->args) <= $argumentPosition) {
|
||||
return ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
|
||||
}
|
||||
|
||||
$subjectArgumentType = $scope->getType($functionCall->args[$argumentPosition]->value);
|
||||
$defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
|
||||
if ($subjectArgumentType instanceof MixedType) {
|
||||
return TypeUtils::toBenevolentUnion($defaultReturnType);
|
||||
}
|
||||
$stringType = new StringType();
|
||||
$arrayType = new ArrayType(new MixedType(), new MixedType());
|
||||
|
||||
$isStringSuperType = $stringType->isSuperTypeOf($subjectArgumentType);
|
||||
$isArraySuperType = $arrayType->isSuperTypeOf($subjectArgumentType);
|
||||
$compareSuperTypes = $isStringSuperType->compareTo($isArraySuperType);
|
||||
if ($compareSuperTypes === $isStringSuperType) {
|
||||
return $stringType;
|
||||
} elseif ($compareSuperTypes === $isArraySuperType) {
|
||||
if ($subjectArgumentType instanceof ArrayType) {
|
||||
return $subjectArgumentType->generalizeValues();
|
||||
}
|
||||
return $subjectArgumentType;
|
||||
}
|
||||
|
||||
return $defaultReturnType;
|
||||
}
|
||||
}
|
32
vendor/thecodingmachine/phpstan-safe-rule/src/Utils/FunctionListLoader.php
vendored
Normal file
32
vendor/thecodingmachine/phpstan-safe-rule/src/Utils/FunctionListLoader.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace TheCodingMachine\Safe\PHPStan\Utils;
|
||||
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\FunctionReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
|
||||
class FunctionListLoader
|
||||
{
|
||||
private static $functions;
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getFunctionList(): array
|
||||
{
|
||||
if (self::$functions === null) {
|
||||
if (\file_exists(__DIR__.'/../../../safe/generated/functionsList.php')) {
|
||||
$functions = require __DIR__.'/../../../safe/generated/functionsList.php';
|
||||
} elseif (\file_exists(__DIR__.'/../../vendor/thecodingmachine/safe/generated/functionsList.php')) {
|
||||
$functions = require __DIR__.'/../../vendor/thecodingmachine/safe/generated/functionsList.php';
|
||||
} else {
|
||||
throw new \RuntimeException('Could not find thecodingmachine/safe\'s functionsList.php file.');
|
||||
}
|
||||
// Let's index these functions by their name
|
||||
self::$functions = \Safe\array_combine($functions, $functions);
|
||||
}
|
||||
return self::$functions;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue