Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
PhpSafeRegularExpression
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
1 / 1
 validate
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2namespace Apie\RegexValueObjects;
3
4use Apie\Core\Attributes\Description;
5use Apie\Core\Attributes\FakeMethod;
6use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
7use Apie\Core\ValueObjects\IsStringValueObject;
8use Apie\RegexValueObjects\Exceptions\ExpressionContainsLookAheads;
9use Apie\RegexValueObjects\Exceptions\ExpressionContainsRepeatsInRepeats;
10use Apie\RegexValueObjects\Exceptions\InvalidPhpRegularExpression;
11
12#[FakeMethod("createRandom")]
13#[Description('Any regular expression that can be parsed with PHP preg_match method that contains no DDOS-vulnerable patterns.')]
14final class PhpSafeRegularExpression implements StringValueObjectInterface
15{
16    use IsStringValueObject;
17    use SharedRegularExpression;
18
19    public static function validate(string $input): void
20    {
21        if (false === @preg_match($input, '')) {
22            throw new InvalidPhpRegularExpression($input, preg_last_error_msg());
23        }
24
25        // Check for lookaheads and lookbehinds
26        if (preg_match('/(?<!\w)[\(\[]\?[:=!<]|[\(\[]\?[:=!<](?!\w)/', $input)) {
27            throw new ExpressionContainsLookAheads($input);
28        }
29        // Check for nested repetitions
30        $repetition = '((\{\d*,\d*\})|\*|\+)'; // {\d,\d} or * or +
31        if (preg_match('/' . $repetition . '\)*' . $repetition . '/', $input)) {
32            throw new ExpressionContainsRepeatsInRepeats($input);
33        }
34    }
35}