Skip to content

Commit 8263604

Browse files
authored
[BUGFIX] Improve selector validation performance (#1372)
Avoid [catastrophic backtracking](https://www.regular-expressions.info/catastrophic.html) in selector validation regular expression by using possessive quantifier with mutually exclusive alternations. Also remove outdated description from DocBlock, but add description for extended class summarizing differences.
1 parent 995442b commit 8263604

File tree

3 files changed

+56
-19
lines changed

3 files changed

+56
-19
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Please also have a look at our
1818

1919
### Fixed
2020

21+
- Improve performance of selector validation
22+
(avoiding silent PCRE catastrophic failure) (#1372)
2123
- Use typesafe versions of PHP functions (#1368, #1370)
2224

2325
### Documentation

src/Property/KeyframeSelector.php

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,41 @@
77
class KeyframeSelector extends Selector
88
{
99
/**
10-
* regexp for specificity calculations
10+
* This differs from the parent class:
11+
* - comma is not allowed unless escaped or quoted;
12+
* - percentage value is allowed by itself.
1113
*
12-
* @var string
14+
* @var non-empty-string
1315
*
1416
* @internal since 8.5.2
1517
*/
1618
public const SELECTOR_VALIDATION_RX = '/
17-
^(
18-
(?:
19-
[a-zA-Z0-9\\x{00A0}-\\x{FFFF}_^$|*="\'~\\[\\]()\\-\\s\\.:#+>]* # any sequence of valid unescaped characters
20-
(?:\\\\.)? # a single escaped character
21-
(?:([\'"]).*?(?<!\\\\)\\2)? # a quoted text like [id="example"]
22-
)*
23-
)|
24-
(\\d+%) # keyframe animation progress percentage (e.g. 50%)
25-
$
26-
/ux';
19+
^(
20+
(?:
21+
# any sequence of valid unescaped characters, except quotes
22+
[a-zA-Z0-9\\x{00A0}-\\x{FFFF}_^$|*=~\\[\\]()\\-\\s\\.:#+>]++
23+
|
24+
# one or more escaped characters
25+
(?:\\\\.)++
26+
|
27+
# quoted text, like in `[id="example"]`
28+
(?:
29+
# opening quote
30+
([\'"])
31+
(?:
32+
# sequence of characters except closing quote or backslash
33+
(?:(?!\\g{-1}|\\\\).)++
34+
|
35+
# one or more escaped characters
36+
(?:\\\\.)++
37+
)*+ # zero or more times
38+
# closing quote or end (unmatched quote is currently allowed)
39+
(?:\\g{-1}|$)
40+
)
41+
)*+ # zero or more times
42+
|
43+
# keyframe animation progress percentage (e.g. 50%), untrimmed
44+
\\s*+(\\d++%)\\s*+
45+
)$
46+
/ux';
2747
}

src/Property/Selector.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,34 @@
1515
class Selector implements Renderable
1616
{
1717
/**
18-
* regexp for specificity calculations
19-
*
20-
* @var string
18+
* @var non-empty-string
2119
*
2220
* @internal since 8.5.2
2321
*/
2422
public const SELECTOR_VALIDATION_RX = '/
2523
^(
2624
(?:
27-
[a-zA-Z0-9\\x{00A0}-\\x{FFFF}_^$|*="\'~\\[\\]()\\-\\s\\.:#+>,]* # any sequence of valid unescaped characters
28-
(?:\\\\.)? # a single escaped character
29-
(?:([\'"]).*?(?<!\\\\)\\2)? # a quoted text like [id="example"]
30-
)*
25+
# any sequence of valid unescaped characters, except quotes
26+
[a-zA-Z0-9\\x{00A0}-\\x{FFFF}_^$|*=~\\[\\]()\\-\\s\\.:#+>,]++
27+
|
28+
# one or more escaped characters
29+
(?:\\\\.)++
30+
|
31+
# quoted text, like in `[id="example"]`
32+
(?:
33+
# opening quote
34+
([\'"])
35+
(?:
36+
# sequence of characters except closing quote or backslash
37+
(?:(?!\\g{-1}|\\\\).)++
38+
|
39+
# one or more escaped characters
40+
(?:\\\\.)++
41+
)*+ # zero or more times
42+
# closing quote or end (unmatched quote is currently allowed)
43+
(?:\\g{-1}|$)
44+
)
45+
)*+ # zero or more times
3146
)$
3247
/ux';
3348

0 commit comments

Comments
 (0)