PHP 8.4.1 Released!

Performance

Certi elementi utilizzati per i criteri di riconoscimento sono più efficienti di altri. E' più efficiente usare le classi di caratteri come [aeiou] piuttosto che un gruppo di alternative come (a|e|i|o|u). In generale la costruzione più semplice per ottenere un dato scopo è la più efficiente. Nel libro di Jeffrey Friedl sono illustrate varie tecniche sull'ottimizzazione delle espressioni regolari.

Quando un criterio comincia con .* ed è attiva l'opzione PCRE_DOTALL, il criterio è implicitamente ancorato da PCRE, dato che può riconoscere solo l'inizio della stringa. Tuttavia, se non è attivo PCRE_DOTALL, PCRE non può fare questa ottimizzazione, perché il meta-carattere . non riconosce più il carattere di "a capo", e quindi se la stringa contiene dei caratteri di "a capo", il riconoscimento può par- tire dal carattere immediatamente successivo ad uno di questi e non dall'inizio. Ad esempio il criterio (.*) second può eseguire un riconoscimento nel testo "first\nand second" (dove \n indica il carattere "a capo") ottenendo "and" come prima stringa catturata. perché ciò accada è necessario che PCRE possa iniziare il riconoscimento dopo ogni "a capo".

Se si deve usare un simile criterio in stringhe che non contengono caratteri di "a capo", le performance migliori si possono ottenere abilitando PCRE_DOTALL, oppure iniziando il criterio con ^.* in modo da richiedere un ancoraggio esplicito. Così si risparmia a PCRE di scandirsi il testo alla ricerca di un "a capo" da cui ripartire per la ricerca.

Occorre prestare attenzione ai criteri che contengono ripetizioni indefinite annidate. Possono richiedere molto tempo se applicati a stringhe non riconoscibili. Si consideri il frammento (a+)*

Questo può riconoscere "aaaa" in 33 modi differenti, e questo numero può crescere molto rapidamente se la stringa da riconoscere è più lunga. (Il carattere di ripetizione * può eseguire riconoscimenti per 0,1,2,3 o 4 ripetizioni, e per ciascuna di esse, tranne lo 0, il carattere di ripetizione + può eseguire riconoscimenti per diversi numeri di volte). Quindi se la parte successiva del criterio è tale da non permettere il completamento del riconoscimento, PCRE, per principio, ugualmente tenta tutte le possibili variazioni, richiedendo diverso tempo.

Una ottimizzazione riesce a catturare qualche caso semplice come in (a+)*b dove si indica che seguirà un carattere alfanumerico. PCRE, prima di imbarcarsi nella procedura standard di riconoscimento, verifica se nel testo vi è la lettera "b", e se non c'è restituisce immediatamente un esito negativo. Tuttavia se non viene indicata una lettera seguente questa ottimizzazione non può essere utilizzata. Se ne può notare la differenza analizzando il comportamento del criterio (a+)*\d rispetto al precedente. Il primo, utilizzato con una stringa composta da "a", fallisce immediatamente, l'ultimo richiede un tempo apprezzabile, soprattutto se applicato a stringhe con più di 20 caratteri.

add a note

User Contributed Notes 1 note

up
1
arthur200126 at gmail dot com
9 months ago
> Beware of patterns that contain nested indefinite repeats. These can take a long time to run when applied to a string that does not match.

To say that it takes a "long time" is an understatement: the time taken would be exponential, specifically 2^n, where n is the number of "a" characters. This behavior could lead to a "regular expression denial of service" (ReDoS) if you run such a expression on user-provided input.

To not be hit by ReDoS, do one (or maybe more than one) of the three things:

* Write your expression so that it is not vulnerable. https://www.regular-expressions.info/redos.html is a good resource (both the "atomic" and "possessive" options are available in PHP/PCRE). Use a "ReDoS detector" or "regex linter" if your eyeballs can't catch all the issues.
* Set up some limits for preg_match. Use `ini_set(...)` on the values mentioned on https://www.php.net/manual/en/pcre.configuration.php. Reducing the limits might cause regexes to fail, but that is usually better than stalling your whole server.
* Use a different regex implementation. There used to be an RE2 extension; not any more!
To Top