Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1e9efb6

Browse files
committed
Add more precise return types for the openssl cipher functions
1 parent 7644bd0 commit 1e9efb6

File tree

5 files changed

+165
-0
lines changed

5 files changed

+165
-0
lines changed

‎conf/config.neon‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,11 @@ services:
15801580
tags:
15811581
- phpstan.dynamicFunctionThrowTypeExtension
15821582

1583+
-
1584+
class: PHPStan\Type\Php\OpensslCipherFunctionsReturnTypeExtension
1585+
tags:
1586+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1587+
15831588
-
15841589
class: PHPStan\Type\Php\OpenSslEncryptParameterOutTypeExtension
15851590
tags:
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\FuncCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Php\PhpVersion;
8+
use PHPStan\Reflection\FunctionReflection;
9+
use PHPStan\Reflection\ParametersAcceptorSelector;
10+
use PHPStan\Type\Constant\ConstantBooleanType;
11+
use PHPStan\Type\Constant\ConstantStringType;
12+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
13+
use PHPStan\Type\Type;
14+
use PHPStan\Type\TypeCombinator;
15+
use function array_map;
16+
use function array_unique;
17+
use function count;
18+
use function function_exists;
19+
use function in_array;
20+
use function is_null;
21+
use function openssl_get_cipher_methods;
22+
use function strtoupper;
23+
24+
final class OpensslCipherFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension
25+
{
26+
27+
/** @var string[]|null */
28+
private ?array $supportedAlgorithms = null;
29+
30+
public function __construct(private PhpVersion $phpVersion)
31+
{
32+
}
33+
34+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
35+
{
36+
return in_array($functionReflection->getName(), ['openssl_cipher_iv_length', 'openssl_cipher_key_length'], true);
37+
}
38+
39+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
40+
{
41+
if (!$this->phpVersion->throwsValueErrorForInternalFunctions()) {
42+
return null;
43+
}
44+
45+
if (count($functionCall->getArgs()) < 1) {
46+
return null;
47+
}
48+
49+
$strings = $scope->getType($functionCall->getArgs()[0]->value)->getConstantStrings();
50+
$results = array_unique(array_map(fn (ConstantStringType $algorithm): bool => $this->isSupportedAlgorithm($algorithm->getValue()), $strings));
51+
52+
if (count($results) !== 1) {
53+
return null;
54+
}
55+
56+
$returnType = ParametersAcceptorSelector::selectFromArgs(
57+
$scope,
58+
$functionCall->getArgs(),
59+
$functionReflection->getVariants(),
60+
)->getReturnType();
61+
62+
return $results[0]
63+
? TypeCombinator::remove($returnType, new ConstantBooleanType(false))
64+
: new ConstantBooleanType(false);
65+
}
66+
67+
private function isSupportedAlgorithm(string $algorithm): bool
68+
{
69+
return in_array(strtoupper($algorithm), $this->getSupportedAlgorithms(), true);
70+
}
71+
72+
/** @return string[] */
73+
private function getSupportedAlgorithms(): array
74+
{
75+
if (!is_null($this->supportedAlgorithms)) {
76+
return $this->supportedAlgorithms;
77+
}
78+
79+
$supportedAlgorithms = [];
80+
if (function_exists('openssl_get_cipher_methods')) {
81+
$supportedAlgorithms = openssl_get_cipher_methods(true);
82+
}
83+
$this->supportedAlgorithms = array_map('strtoupper', $supportedAlgorithms);
84+
85+
return $this->supportedAlgorithms;
86+
}
87+
88+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php // lint < 8.0
2+
3+
namespace OpensslCipherIvLengthPhp7;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class OpensslCipher
8+
{
9+
10+
/**
11+
* @param 'aes-256-cbc'|'aes128'|'aes-128-cbc' $validAlgorithms
12+
* @param 'aes-256-cbc'|'invalid' $validAndInvalidAlgorithms
13+
*/
14+
public function doFoo(string $s, $validAlgorithms, $validAndInvalidAlgorithms)
15+
{
16+
assertType('int|false', openssl_cipher_iv_length('aes-256-cbc'));
17+
assertType('int|false', openssl_cipher_iv_length('AES-256-CBC'));
18+
assertType('int|false', openssl_cipher_iv_length('unsupported'));
19+
assertType('int|false', openssl_cipher_iv_length($s));
20+
assertType('int|false', openssl_cipher_iv_length($validAlgorithms));
21+
assertType('int|false', openssl_cipher_iv_length($validAndInvalidAlgorithms));
22+
}
23+
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php // lint >= 8.0
2+
3+
namespace OpensslCipherIvLengthPhp8;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class OpensslCipher
8+
{
9+
10+
/**
11+
* @param 'aes-256-cbc'|'aes128'|'aes-128-cbc' $validAlgorithms
12+
* @param 'aes-256-cbc'|'invalid' $validAndInvalidAlgorithms
13+
*/
14+
public function doFoo(string $s, $validAlgorithms, $validAndInvalidAlgorithms)
15+
{
16+
assertType('int', openssl_cipher_iv_length('aes-256-cbc'));
17+
assertType('int', openssl_cipher_iv_length('AES-256-CBC'));
18+
assertType('false', openssl_cipher_iv_length('unsupported'));
19+
assertType('int|false', openssl_cipher_iv_length($s));
20+
assertType('int', openssl_cipher_iv_length($validAlgorithms));
21+
assertType('int|false', openssl_cipher_iv_length($validAndInvalidAlgorithms));
22+
}
23+
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php // lint >= 8.2
2+
3+
namespace OpensslCipherKeyLength;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class OpensslCipher
8+
{
9+
10+
/**
11+
* @param 'aes-256-cbc'|'aes128'|'aes-128-cbc' $validAlgorithms
12+
* @param 'aes-256-cbc'|'invalid' $validAndInvalidAlgorithms
13+
*/
14+
public function doFoo(string $s, $validAlgorithms, $validAndInvalidAlgorithms)
15+
{
16+
assertType('int', openssl_cipher_key_length('aes-256-cbc'));
17+
assertType('int', openssl_cipher_key_length('AES-256-CBC'));
18+
assertType('false', openssl_cipher_key_length('unsupported'));
19+
assertType('int|false', openssl_cipher_key_length($s));
20+
assertType('int', openssl_cipher_key_length($validAlgorithms));
21+
assertType('int|false', openssl_cipher_key_length($validAndInvalidAlgorithms));
22+
}
23+
24+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /