Lors de la mise à jour d’un vieux site vers PHP 8.4, je suis tombé sur cette erreur dans les logs PHP :
preg_match(): Compilation failed: invalid range in character class at offset 20 session.php on line 278Code language: JavaScript (javascript)
Le message peut paraître obscur au premier abord. Pourtant, la cause est souvent toute simple : une expression régulière contient un tiret mal placé dans une classe de caractères.
Depuis PHP 7.3, PHP utilise PCRE2 pour gérer les expressions régulières. Cette migration a rendu la validation des expressions régulières plus stricte. Résultat : certains patterns qui fonctionnaient auparavant ne compilent plus correctement après une mise à jour de PHP. La migration vers PCRE2 a bien été introduite avec PHP 7.3, comme l’indiquent la RFC PHP et la documentation PHP sur l’installation de PCRE.
Pourquoi cette erreur apparaît-elle ?
Dans une expression régulière, les crochets permettent de définir une classe de caractères. Par exemple, [abc] signifie : “accepte a, b ou c”.
Le problème vient souvent du tiret -. Dans une classe de caractères, il peut indiquer une plage. Par exemple, [a-z] signifie : “toutes les lettres minuscules de a à z”.
Donc, quand PCRE2 rencontre une expression comme celle-ci, il peut interpréter le tiret comme le début d’une plage invalide :
preg_match('/[\w-.]+/', '');Code language: JavaScript (javascript)
Avant PHP 7.3, ce type de pattern pouvait passer sans bruit selon le contexte. Avec PCRE2, la validation devient plus stricte, et PHP renvoie alors une erreur du type Compilation failed: invalid range in character class. PHP.Watch donne exactement ce cas comme exemple de rupture possible après la migration vers PCRE2.
La solution : échapper le tiret dans la regex
Pour corriger l’erreur, il suffit généralement d’échapper le tiret avec un antislash :
preg_match('/[\w\-.]+/', '');Code language: JavaScript (javascript)
Ici, \- indique clairement à PCRE2 que le tiret doit être traité comme un caractère littéral, et non comme un opérateur de plage.
Autrement dit, cette classe de caractères accepte désormais les caractères alphanumériques, l’underscore, le tiret et le point, sans ambiguïté.
Autre solution : placer le tiret à la fin de la classe
Il existe aussi une autre correction valide : placer le tiret à la fin de la classe de caractères.
preg_match('/[\w.-]+/', '');Code language: JavaScript (javascript)
Dans cette position, le tiret ne peut plus être interprété comme une plage entre deux caractères. Personnellement, je préfère l’échapper explicitement, car l’intention reste plus lisible lors d’une relecture du code.
À quoi correspond “invalid range in character class” ?
Le message invalid range in character class signifie que PCRE2 a trouvé une plage invalide dans une classe de caractères.
Par exemple, dans une classe comme [\w-.], le moteur peut essayer de comprendre le segment \w-. comme une plage. Or cette plage n’a pas de sens. PCRE2 refuse donc de compiler l’expression régulière.
C’est pour cela que l’erreur mentionne une “compilation failed”. Le problème ne vient pas de la chaîne testée, mais du pattern lui-même. PHP n’arrive même pas à compiler la regex avant de l’exécuter.
Comment retrouver la regex responsable ?
Le message d’erreur indique généralement le fichier et la ligne concernés :
session.php on line 278Code language: CSS (css)
Il faut donc ouvrir ce fichier, puis chercher un appel à l’une de ces fonctions PHP :
preg_match()preg_match_all()preg_replace()preg_split()preg_grep()
Ensuite, vérifiez les classes de caractères entre crochets. Le cas le plus fréquent ressemble à ceci :
/[\w-.]+/
Il faut alors remplacer le pattern par une version explicite :
/[\w\-.]+/
Ou, si vous préférez placer le tiret à la fin :
/[\w.-]+/
Exemple concret avant / après
Voici le code qui peut provoquer l’erreur avec PHP 7.3 ou une version plus récente :
<?php
preg_match('/[\w-.]+/', 'exemple-test.php');Code language: HTML, XML (xml)
Et voici la version corrigée :
<?php
preg_match('/[\w\-.]+/', 'exemple-test.php');Code language: HTML, XML (xml)
Cette fois, le tiret est interprété comme un caractère normal. L’expression régulière compile donc correctement.
Faut-il modifier PHP ou le serveur ?
Non. Dans la grande majorité des cas, il ne faut pas rétrograder PHP ni modifier la configuration serveur. L’erreur vient du pattern regex. La bonne correction consiste donc à rendre l’expression régulière compatible avec PCRE2.
C’est une correction de code, pas une correction d’infrastructure.
À retenir
- Depuis PHP 7.3, PHP utilise PCRE2 pour les expressions régulières.
- PCRE2 valide les patterns plus strictement.
- L’erreur
invalid range in character classvient souvent d’un tiret mal placé dans une classe de caractères. - La solution la plus claire consiste à échapper le tiret avec
\-. - Une autre solution consiste à placer le tiret au début ou à la fin de la classe.
Dans mon cas, la correction suivante a suffi :
preg_match('/[\w\-.]+/', '');Code language: JavaScript (javascript)
Une fois le tiret échappé, plus d’erreur à ce niveau.