Corriger l’erreur preg_match invalid range en PHP

Lors d’une mise à jour PHP, un vieux site peut soudain afficher une erreur qui sent bon la regex fatiguée :

preg_match(): Compilation failed: invalid range in character class at offset 20Langage du code : JavaScript (javascript)

Le message paraît obscur. Pourtant, la cause est souvent très 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 les expressions régulières. Cette migration a rendu certains patterns plus stricts. Résultat : une regex qui passait silencieusement sur une ancienne version PHP peut échouer après une montée de version.

Kinsta: Premium Managed WordPress hosting

Pourquoi cette erreur apparaît-elle ?

Dans une expression régulière, les crochets définissent une classe de caractères.

Par exemple :

/[abc]/

Cette regex accepte un caractère parmi a, b ou c.

Autre exemple :

/[a-z]/

Ici, le tiret indique une plage : toutes les lettres de a à z.

Le problème apparaît quand PHP rencontre un tiret à un endroit ambigu. Par exemple :

/[\w-.]+/

Dans cette classe, le moteur PCRE2 peut interpréter le tiret comme un opérateur de plage entre \w et .. Cette plage n’a pas de sens. PHP refuse donc de compiler l’expression régulière.

C’est pour cela que le message parle de Compilation failed. Le problème ne vient pas de la chaîne testée. Il vient du pattern lui-même.

La correction la plus claire : échapper le tiret

La correction la plus lisible consiste à échapper le tiret avec un antislash :

/[\w\-.]+/

Dans cette version, \- indique clairement que le tiret doit être traité comme un caractère littéral, et non comme une plage.

Exemple PHP complet :

<?php

$filename = 'exemple-test.php';

if ( 1 === preg_match( '/^[\w\-.]+$/', $filename ) ) {
    echo 'Nom valide';
}Langage du code : HTML, XML (xml)

Ici, la regex accepte les caractères de mot, l’underscore, le tiret et le point. Elle compile correctement avec PHP 7.3, PHP 8.4 et PHP 8.5.

Distingo, le livret à 2%

Autre correction valide : placer le tiret à la fin

Une autre solution consiste à placer le tiret à la fin de la classe :

/[\w.-]+/

Dans cette position, le tiret ne peut plus être interprété comme une plage.

Vous pouvez aussi le placer au début :

/[-\w.]+/

Les trois formes suivantes sont donc valides :

/[\w\-.]+/
/[\w.-]+/
/[-\w.]+/

Personnellement, je préfère souvent \-. L’intention reste claire à la relecture, surtout dans du code maintenu par plusieurs personnes.

Exemple avant / après

Voici une regex fragile :

<?php

preg_match( '/^[\w-.]+$/', 'exemple-test.php' );Langage du code : HTML, XML (xml)

Elle peut déclencher :

preg_match(): Compilation failed: invalid range in character classLangage du code : JavaScript (javascript)

Version corrigée :

<?php

preg_match( '/^[\w\-.]+$/', 'exemple-test.php' );Langage du code : HTML, XML (xml)

Ou, si vous préférez placer le tiret à la fin :

<?php

preg_match( '/^[\w.-]+$/', 'exemple-test.php' );Langage du code : HTML, XML (xml)

Dans les deux cas, PHP comprend que le tiret est un caractère autorisé, pas le début d’une plage étrange.

Kinsta: Premium Managed WordPress hosting

Comment retrouver la regex responsable ?

Le message d’erreur indique généralement le fichier et la ligne concernés :

session.php on line 278Langage du code : CSS (css)

Ouvrez ce fichier, puis cherchez un appel à l’une des fonctions PHP suivantes :

  • preg_match()
  • preg_match_all()
  • preg_replace()
  • preg_replace_callback()
  • preg_split()
  • preg_grep()
  • preg_filter()

Ensuite, inspectez les classes de caractères entre crochets. Les patterns suspects ressemblent souvent à ceci :

/[\w-.]+/
/[a-zA-Z0-9-_\s]+/
/[0-9-_]+/
/[\w-:]+/
/[A-z-0-9]+/

Attention au dernier exemple : [A-z] est presque toujours une mauvaise idée. Il ne correspond pas seulement aux lettres. Il inclut aussi des caractères ASCII situés entre Z et a. Préférez [A-Za-z].

Chercher toutes les regex potentiellement fragiles

Sur un projet PHP ou WordPress, vous pouvez commencer par chercher les appels aux fonctions preg_* :

grep -RIn --include='*.php' 'preg_' .Langage du code : PHP (php)

Pour une recherche plus ciblée des classes contenant un tiret, utilisez plutôt ripgrep si disponible :

rg "preg_.*\[[^]]*-" --glob "*.php"Langage du code : JavaScript (javascript)

Cette commande ne remplace pas une revue humaine, mais elle aide à repérer les zones à inspecter.

Dans WordPress, vérifiez en priorité :

  • le thème actif ;
  • le thème enfant ;
  • les plugins anciens ;
  • les mu-plugins ;
  • les snippets personnalisés ;
  • les vieux fichiers copiés depuis un ancien projet ;
  • les bibliothèques embarquées dans un plugin.

Si l’erreur vient d’un plugin tiers, évitez de modifier directement le fichier du plugin. Mettez-le à jour, signalez le bug, ou remplacez le plugin s’il n’est plus maintenu.

Distingo, le livret à 2%

Tester une regex rapidement en PHP

Vous pouvez tester un pattern directement en ligne de commande :

php -r "var_dump(preg_match('/^[\w\-.]+$/', 'exemple-test.php'));"Langage du code : JavaScript (javascript)

Si la regex compile et correspond, PHP retourne :

int(1)

Si elle compile mais ne correspond pas, PHP retourne :

int(0)

Si elle ne compile pas, PHP émet un warning. Vous pouvez aussi contrôler la dernière erreur PCRE avec preg_last_error() et preg_last_error_msg().

<?php

$result = preg_match( '/^[\w\-.]+$/', 'exemple-test.php' );

if ( false === $result ) {
    echo preg_last_error_msg();
}Langage du code : HTML, XML (xml)

Sur PHP récent, preg_last_error_msg() donne un message plus lisible que le simple code numérique retourné par preg_last_error().

Ne corrigez pas toutes les regex avec un remplacement automatique

Le mauvais réflexe serait de remplacer tous les - par \- dans toutes les regex du projet.

Pourquoi ? Parce que certains tirets sont de vraies plages :

/[a-z]/
/[0-9]/
/[A-Fa-f0-9]/Langage du code : JavaScript (javascript)

Dans ces exemples, le tiret doit rester un opérateur de plage. Le modifier casserait le sens de la regex.

Il faut donc corriger uniquement les tirets qui doivent représenter un caractère littéral. Oui, c’est un peu moins rapide qu’un remplacement global. Mais c’est aussi nettement moins suicidaire.

Cas fréquent : valider un slug ou un nom de fichier

Pour valider un slug simple contenant lettres, chiffres, underscores et tirets :

<?php

$slug = 'mon-article-2026';

if ( 1 === preg_match( '/^[A-Za-z0-9_-]+$/', $slug ) ) {
    echo 'Slug valide';
}Langage du code : HTML, XML (xml)

Ici, le tiret est placé à la fin de la classe. Il n’est donc pas ambigu.

Pour un nom de fichier simple avec point autorisé :

<?php

$filename = 'archive-2026.zip';

if ( 1 === preg_match( '/^[A-Za-z0-9_.-]+$/', $filename ) ) {
    echo 'Nom de fichier valide';
}Langage du code : HTML, XML (xml)

Cette regex accepte les lettres ASCII, les chiffres, l’underscore, le point et le tiret.

Cas Unicode : attention à \w

Le raccourci \w peut sembler pratique, mais son comportement dépend du mode Unicode et de la version PCRE2 utilisée. En PHP 8.4, PCRE2 apporte notamment des changements autour de certaines classes Unicode et de \w en mode Unicode.

Si vous validez un identifiant strictement ASCII, préférez une classe explicite :

/^[A-Za-z0-9_.-]+$/

Si vous voulez accepter des lettres Unicode, soyez explicite et ajoutez le modificateur u :

/^[\p{L}\p{N}_.-]+$/u

Cette version accepte les lettres et chiffres Unicode, ainsi que l’underscore, le point et le tiret.

Faut-il modifier PHP ou le serveur ?

Non, dans la grande majorité des cas. Il ne faut pas rétrograder PHP ni désactiver une option serveur pour corriger cette erreur.

L’erreur vient du pattern regex. La bonne correction consiste donc à rendre l’expression régulière valide pour PCRE2.

Autrement dit : ce n’est pas un problème d’infrastructure. C’est une correction de code.

Et dans WordPress ?

Sur WordPress, cette erreur apparaît souvent après une montée de version PHP. Le cœur WordPress est rarement responsable. Le problème vient plutôt d’un plugin ancien, d’un thème peu maintenu ou d’un snippet personnalisé.

Avant de modifier quoi que ce soit en production :

  • reproduisez l’erreur sur un staging ;
  • activez les logs WordPress ;
  • identifiez le fichier et la ligne ;
  • mettez le plugin ou thème à jour ;
  • corrigez le code personnalisé si c’est votre code ;
  • remplacez le plugin s’il n’est plus maintenu.

Si vous préparez une migration PHP plus large, consultez aussi Tester la compatibilité WordPress avec PHP 8. L’objectif est simple : éviter que la production serve de laboratoire.

Checklist de correction

  • Lire le fichier et la ligne indiqués par le warning PHP.
  • Trouver l’appel à preg_match(), preg_replace() ou autre fonction preg_*.
  • Inspecter les classes de caractères entre crochets.
  • Repérer les tirets ambigus.
  • Échapper le tiret avec \- si c’est un caractère littéral.
  • Ou placer le tiret au début ou à la fin de la classe.
  • Ne pas modifier les vraies plages comme a-z ou 0-9.
  • Tester la regex avec la version PHP utilisée en production.
  • Déployer la correction sur staging avant production.

À retenir

  • invalid range in character class indique une plage invalide dans une classe de caractères.
  • Le tiret - est souvent le coupable.
  • Depuis PHP 7.3, PCRE2 valide certains patterns plus strictement.
  • /[\w-.]+/ est fragile.
  • /[\w\-.]+/ est clair et compatible.
  • /[\w.-]+/ est également valide.
  • Il faut corriger la regex, pas rétrograder PHP.

Articles liés sur SkyMinds

Pour compléter ce dépannage PHP et WordPress, ces articles peuvent vous aider :

FAQ

Que signifie “invalid range in character class” ?

Cette erreur signifie qu’une classe de caractères contient une plage invalide. Le cas le plus fréquent est un tiret mal placé dans une regex, par exemple /[\w-.]+/.

Pourquoi l’erreur apparaît-elle après une mise à jour PHP ?

Depuis PHP 7.3, PHP utilise PCRE2 pour les expressions régulières. PCRE2 valide certains patterns plus strictement. Une regex tolérée auparavant peut donc échouer après migration.

Quelle est la meilleure correction ?

Échappez le tiret avec \- lorsqu’il doit être lu comme un caractère littéral. Vous pouvez aussi le placer au début ou à la fin de la classe de caractères.

Faut-il rétrograder PHP pour corriger cette erreur ?

Non. Il faut corriger la regex. Rétrograder PHP masque le problème et retarde la correction. Le pattern doit être compatible avec PCRE2.

Puis-je remplacer tous les tirets par \- automatiquement ?

Non. Certains tirets définissent de vraies plages, comme [a-z] ou [0-9]. Il faut inspecter chaque classe de caractères et corriger uniquement les tirets littéraux ambigus.

Cette erreur peut-elle venir d’un plugin WordPress ?

Oui. Elle apparaît souvent dans un plugin ancien, un thème peu maintenu ou un snippet personnalisé après une montée de version PHP. Mettez d’abord les extensions à jour, puis corrigez ou remplacez le code fautif.

Sources

Demandez à l'IA son opinion
Gravatar for Matt Biscay

Je suis Matt Biscay, développeur WordPress & WooCommerce certifié chez Codeable, administrateur système et enseignant.

J’aide les entreprises à créer, optimiser et fiabiliser leurs sites WordPress avec une approche technique propre : performance, sécurité, maintenance, développement sur mesure et résolution de problèmes complexes.

Sur Skyminds, je partage des tutoriels WordPress, WooCommerce, Linux et administration système, avec des solutions testées sur des cas réels et pensées pour durer.

Découvrez mes services WordPress et WooCommerce.

1 pensée sur “Corriger l’erreur preg_match invalid range en PHP”

  1. Merci pour le coup de pouce.
    C’est quand même débile. Je dois revoir tout mes fichiers de tous mes sites pour voir si j’en ai pas d’autre…

    Répondre

Opinions