Skip to content

Commit

Permalink
RegularExpressionPatternRule: validate preg_quote'd patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Jul 26, 2024
1 parent 43dce15 commit 7d11678
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/Rules/Regexp/RegularExpressionPatternRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\Php\RegexExpressionHelper;
use function in_array;
use function sprintf;
use function str_starts_with;
Expand All @@ -20,6 +21,12 @@
class RegularExpressionPatternRule implements Rule
{

public function __construct(
private RegexExpressionHelper $regexExpressionHelper,
)
{
}

public function getNodeType(): string
{
return FuncCall::class;
Expand Down Expand Up @@ -74,6 +81,9 @@ private function extractPatterns(FuncCall $functionCall, Scope $scope): array
'preg_filter',
], true)
) {
if ($patternNode instanceof Node\Expr\BinaryOp\Concat) {
$patternType = $this->regexExpressionHelper->resolvePatternConcat($patternNode, $scope);
}
foreach ($patternType->getConstantStrings() as $constantStringType) {
$patternStrings[] = $constantStringType->getValue();
}
Expand Down
53 changes: 52 additions & 1 deletion tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPStan\Type\Php\RegexExpressionHelper;
use function sprintf;
use const PHP_VERSION_ID;

Expand All @@ -15,7 +16,9 @@ class RegularExpressionPatternRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new RegularExpressionPatternRule();
return new RegularExpressionPatternRule(
self::getContainer()->getByType(RegexExpressionHelper::class),
);
}

public function testValidRegexPatternBefore73(): void
Expand Down Expand Up @@ -115,6 +118,30 @@ public function testValidRegexPatternBefore73(): void
'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~',
43,
],
[
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: nok',
57,
],
[
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: nok',
58,
],
[
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
59,
],
[
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: noknono',
61,
],
[
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: noknope',
62,
],
[
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
63,
],
],
);
}
Expand Down Expand Up @@ -221,6 +248,30 @@ public function testValidRegexPatternAfter73(): void
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
43,
],
[
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok', $messagePart),
57,
],
[
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok', $messagePart),
58,
],
[
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
59,
],
[
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: noknono', $messagePart),
61,
],
[
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: noknope', $messagePart),
62,
],
[
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
63,
],
],
);
}
Expand Down
16 changes: 15 additions & 1 deletion tests/PHPStan/Rules/Regexp/data/valid-regex-pattern.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php
<?php namespace RegexExpressionPatterns;

$string = (function (): string {})();

Expand Down Expand Up @@ -48,3 +48,17 @@
],
''
);

function doFoo(string $s) {
preg_match('~ok'. preg_quote($s, '~') .'~', '');
preg_match('~ok'. preg_quote($s) .'~', '');

// invalid preg_quote delimiters will be reported by RegularExpressionQuotingRule
preg_match('nok'. preg_quote($s), '');
preg_match('nok'. preg_quote($s), '');
preg_match('~('. preg_quote($s, '~') .'~', '');

preg_replace('nok'. preg_quote($s).'nono', '');
preg_replace('nok'. preg_quote($s).'nope', '');
preg_replace('~('. preg_quote($s, '~') .'~', '');
}

0 comments on commit 7d11678

Please sign in to comment.