Skip to content

Commit 0b93292

Browse files
committed
Implement OpenSslEncryptParameterOutTypeExtension
1 parent b5fc9ec commit 0b93292

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,6 +1569,11 @@ services:
15691569
tags:
15701570
- phpstan.dynamicFunctionThrowTypeExtension
15711571

1572+
-
1573+
class: PHPStan\Type\Php\OpenSslEncryptParameterOutTypeExtension
1574+
tags:
1575+
- phpstan.functionParameterOutTypeExtension
1576+
15721577
-
15731578
class: PHPStan\Type\Php\ParseStrParameterOutTypeExtension
15741579
tags:
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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\Reflection\FunctionReflection;
8+
use PHPStan\Reflection\ParameterReflection;
9+
use PHPStan\Type\FunctionParameterOutTypeExtension;
10+
use PHPStan\Type\NullType;
11+
use PHPStan\Type\StringType;
12+
use PHPStan\Type\Type;
13+
use PHPStan\Type\TypeCombinator;
14+
use function current;
15+
use function in_array;
16+
use function openssl_get_cipher_methods;
17+
use function strtolower;
18+
use function substr;
19+
20+
final class OpenSslEncryptParameterOutTypeExtension implements FunctionParameterOutTypeExtension
21+
{
22+
23+
public function isFunctionSupported(FunctionReflection $functionReflection, ParameterReflection $parameter): bool
24+
{
25+
return $functionReflection->getName() === 'openssl_encrypt' && $parameter->getName() === 'tag';
26+
}
27+
28+
public function getParameterOutTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $funcCall, ParameterReflection $parameter, Scope $scope): ?Type
29+
{
30+
$args = $funcCall->getArgs();
31+
$cipherArg = $args[1] ?? null;
32+
33+
if ($cipherArg === null) {
34+
return null;
35+
}
36+
37+
$cipherType = current($scope->getType($cipherArg->value)->getConstantStrings());
38+
39+
if ($cipherType === false) {
40+
return TypeCombinator::addNull(new StringType());
41+
}
42+
43+
$cipher = strtolower($cipherType->getValue());
44+
$mode = substr($cipher, -3);
45+
46+
if (in_array($mode, ['gcm', 'ccm'], true)) {
47+
return new StringType();
48+
}
49+
50+
return new NullType();
51+
}
52+
53+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
public function testStringCipher(string $cipher): void
10+
{
11+
openssl_encrypt('data', $cipher, random_bytes(32), OPENSSL_RAW_DATA, random_bytes(16), $tag);
12+
assertType('string|null', $tag);
13+
}
14+
15+
public function testUnknownCipher(): void
16+
{
17+
openssl_encrypt('data', 'aes-256-cde', random_bytes(32), OPENSSL_RAW_DATA, random_bytes(16), $tag);
18+
assertType('null', $tag);
19+
}
20+
21+
public function testAeadCipher(): void
22+
{
23+
$cipher = 'aes-256-gcm';
24+
openssl_encrypt('data', $cipher, random_bytes(32), OPENSSL_RAW_DATA, random_bytes(16), $tag);
25+
assertType('string', $tag);
26+
27+
$cipher = 'aes-256-ccm';
28+
openssl_encrypt('data', $cipher, random_bytes(32), OPENSSL_RAW_DATA, random_bytes(16), $tag);
29+
assertType('string', $tag);
30+
}
31+
32+
public function testNonAeadCipher(): void
33+
{
34+
$cipher = 'aes-256-cbc';
35+
openssl_encrypt('data', $cipher, random_bytes(32), OPENSSL_RAW_DATA, random_bytes(16), $tag);
36+
assertType('null', $tag);
37+
}
38+
}

0 commit comments

Comments
 (0)