11.01.2015 Views

Initiation aux expressions régulières en PHP

Initiation aux expressions régulières en PHP

Initiation aux expressions régulières en PHP

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong><br />

par Guillaume Rossolini<br />

Date de publication : 28 mai 2006<br />

Dernière mise à jour : 4 août 2006<br />

<strong>PHP</strong> dispose de divers moy<strong>en</strong>s permettant de vérifier le cont<strong>en</strong>u d'une<br />

variable. Ce tutoriel traite des <strong>expressions</strong> <strong>régulières</strong>, aussi appelées<br />

<strong>expressions</strong> rationnelles.


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

I - Introduction<br />

I-A - Remerciem<strong>en</strong>ts<br />

I-B - Problématique<br />

II - Syntaxe<br />

II-1 - La base : trouver une sous chaîne dans une chaîne<br />

II-2 - Les alternatives (barre verticale |)<br />

II-3 - L'ancrage (acc<strong>en</strong>t circonflexe ^ et signe dollar $)<br />

II-4 - Les classes<br />

II-5 - Les quantifieurs<br />

II-6 - Les par<strong>en</strong>thèses<br />

Les par<strong>en</strong>thèses capturantes<br />

Les par<strong>en</strong>thèses non capturantes<br />

II-7 - Les modificateurs<br />

II-8 - Les assertions<br />

Les assertions négatives avant<br />

Les assertions négatives arrière<br />

III - Fonctions<br />

III-1 - preg_grep()<br />

III-2 - preg_match_all()<br />

III-3 - preg_match()<br />

III-4 - preg_quote()<br />

III-5 - preg_replace()<br />

III-6 - preg_replace_callback()<br />

III-7 - preg_split()<br />

IV - Sécurité<br />

V - Conclusion<br />

- 2 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

I - Introduction<br />

I-A - Remerciem<strong>en</strong>ts<br />

Je ti<strong>en</strong>s à remercier mathieu et titoumimi pour leurs conseils avisés lors de la rédaction de ce tutoriel.<br />

I-B - Problématique<br />

Les <strong>expressions</strong> <strong>régulières</strong> que nous allons utiliser (car il <strong>en</strong> existe plusieurs sortes) sont héritées du langage Perl.<br />

Elles sont appelées PCRE pour Perl-Compatible Regular Expressions bi<strong>en</strong> que, comme le souligne le manuel<br />

<strong>PHP</strong>, cette dénomination soit un abus de langage.<br />

Nous n'utiliserons pas la syntaxe héritée de POSIX, bi<strong>en</strong> qu'elle soit très similaire, car elle est moins intéressante.<br />

En effet, les PCRE repr<strong>en</strong>n<strong>en</strong>t la norme POSIX <strong>en</strong> l'agrém<strong>en</strong>tant de nouvelles fonctionnalités que nous aborderons<br />

ici. De plus, le temps d'exécution des PCRE est souv<strong>en</strong>t plus court que celui des <strong>expressions</strong> POSIX. Il n'y a<br />

vraim<strong>en</strong>t que des avantages à passer de l'un à l'autre !<br />

Les regex (pour simplifier, j'utiliserai ce terme par la suite) sont un moy<strong>en</strong> de parcourir avec précision le cont<strong>en</strong>u<br />

d'une chaîne de caractères.<br />

• de délimiteurs : //, ##, [], , etc.<br />

• du masque à proprem<strong>en</strong>t parler, situé <strong>en</strong>tre les délimiteurs<br />

• de modificateurs, situés après le délimiteur de fin : U, s, i, m, etc.<br />

Tout au long de l'article, je vous donnerai le code <strong>PHP</strong> permettant de reproduire les exemples.<br />

- 3 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

II - Syntaxe<br />

Nous allons comm<strong>en</strong>cer par des regex très simples afin de nous familiariser avec la bestiole. Pour cela, nous<br />

allons écrire des <strong>expressions</strong> qui permettront de faire la même chose que certaines fonctions déjà mises à<br />

disposition par <strong>PHP</strong>. Bi<strong>en</strong> <strong>en</strong>t<strong>en</strong>du, ces fonctions sont à utiliser de préfér<strong>en</strong>ce : nous ne les remplaçons ici qu'à des<br />

fins didactiques.<br />

II-1 - La base : trouver une sous chaîne dans une chaîne<br />

En <strong>PHP</strong>, la fonction strpos() permet de savoir si une chaîne se trouve dans une autre chaîne :<br />

Exemple d'utilisation de strpos()<br />

<br />

Tester ce script<br />

N. B. : En cas de succès, la fonction strpos() retourne la position de la sous chaîne dans la chaîne mais cela ne<br />

nous est pas nécessaire : nous cherchons simplem<strong>en</strong>t à déterminer son exist<strong>en</strong>ce.<br />

Du mom<strong>en</strong>t que nous ne souhaitons pas récupérer cette valeur, nous pouvons simuler strpos() au moy<strong>en</strong> d'une<br />

regex. Pour cela, nous utiliserons la fonction preg_match() :<br />

Exemple d'utilisation de preg_match()<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple d'utilisation de preg_match()<br />

foreach($subjects as $subject){<br />

echo "$subject ";<br />

if(preg_match($pattern, $subject)){<br />

echo "Oui";<br />

}<br />

else{<br />

echo "Non";<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

/rossolini/ => La chaîne "rossolini" telle quelle.<br />

Tester ce script<br />

Évidemm<strong>en</strong>t, ce premier exemple n'est pas très intéressant. Il nous permet à peine d'introduire les délimiteurs.<br />

Les délimiteurs sont, ici, les deux barres obliques <strong>en</strong>cadrant la chaîne à chercher. En réalité, il est possible<br />

d'utiliser une grande variété de délimiteurs. J'aurais pu écrire #rossolini#, `rossolini`, [rossolini], ,<br />

etc. Reportez-vous au manuel <strong>PHP</strong> pour <strong>en</strong> avoir la liste complète. Je ne recommande pas l'utilisation des<br />

par<strong>en</strong>thèses, crochets et accolades car cela peut compliquer les choses dans l'expression (cf. plus loin).<br />

L'une des différ<strong>en</strong>ces majeures <strong>en</strong>tre les <strong>expressions</strong> POSIX et les PCRE est l'exist<strong>en</strong>ce de ces délimiteurs ; ils<br />

permett<strong>en</strong>t de spécifier des modificateurs à la suite de l'expression, par exemple :<br />

Exemple de modificateur<br />

<br />

Décomposition de la regex : []<br />

/ROSSOLINI/i => La chaîne "rossolini" quelle que soit la casse.<br />

- 5 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Tester ce script<br />

Ici, j'ai ajouté le modificateur i permettant de r<strong>en</strong>dre l'expression ins<strong>en</strong>sible à la casse, c'est-à-dire de chercher<br />

toutes les variantes majuscules/minuscules de "rossolini". Dans l'exemple ci-dessus, c'est équival<strong>en</strong>t à invoquer la<br />

fonction stripos().<br />

II-2 - Les alternatives (barre verticale |)<br />

L'un des intérêts des regex est de permettre de donner des alternatives. Ainsi, nous pouvons savoir si une chaîne<br />

conti<strong>en</strong>t au moins l'une de plusieurs sous chaînes, cela sans à avoir à appeler plusieurs fois la fonction à la suite :<br />

Exemple d'alternatives avec strpos()<br />

<br />

Tester ce script<br />

Exemple d'alternatives avec une regex<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple d'alternatives avec une regex<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

/rossolini|www/ => Soit la chaîne "rossolini", soit "www".<br />

Tester ce script<br />

Cela dit, s'il s'agit de trouver deux sous chaînes dans une chaîne, alors il est préférable de lancer deux regex plutôt<br />

que d'essayer de le faire <strong>en</strong> une fois : cela pourrait s'avérer bi<strong>en</strong> complexe, illisible et très long à exécuter.<br />

II-3 - L'ancrage (acc<strong>en</strong>t circonflexe ^ et signe dollar $)<br />

Il est possible d'ancrer une regex, de manière à ne trouver de correspondances qu'au début de la chaîne, à la fin<br />

ou les deux (chaîne <strong>en</strong>tière). Cela se fait au moy<strong>en</strong> des symboles ^ et $.<br />

Exemples d'ancrages de regex<br />

<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

- 7 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Décomposition de la regex : []<br />

#^http$# => La chaîne "http".<br />

#http$# => La chaîne "http" <strong>en</strong> fin de chaîne.<br />

#^http# => La chaîne "http" <strong>en</strong> début de chaîne.<br />

Tester ce script<br />

N. B. : J'ai pris soin d'utiliser un délimiteur différ<strong>en</strong>t de la barre oblique, dans la mesure où elle se trouve dans le<br />

masque ($pattern). Sans cela, il aurait fallu échapper la barre oblique, or je préfère simplifier la lecture de la regex.<br />

Il y a bi<strong>en</strong> sûr des équival<strong>en</strong>ces tant que nous cherchons une sous chaîne fixe :<br />

Simulation d'ancrage de début ^<br />

<br />

Tester ce script<br />

Simulation d'ancrage de fin $<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Simulation d'ancrage de fin $<br />

echo "Non";<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Tester ce script<br />

Simulation d'ancrage complet ^ et $<br />

<br />

Tester ce script<br />

II-4 - Les classes<br />

Les regex permett<strong>en</strong>t une chose intéressante : savoir si une chaîne conti<strong>en</strong>t une liste de caractères (plutôt qu'une<br />

sous chaîne précise).<br />

Exemple de classe alphabétique<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple de classe alphabétique<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

/[a-z]/ => Il suffit d'une lettre minuscule dans la chaîne.<br />

Tester ce script<br />

Dans cet exemple, la regex regarde s'il y a au moins une lettre dans la chaîne. Le trait d'union permet d'indiquer<br />

une série : "[a-z]" compr<strong>en</strong>d l'alphabet <strong>en</strong>tier, "[0-9]" tous les chiffres, "[4-7]" uniquem<strong>en</strong>t les chiffres de 4 à 7 inclus.<br />

Nous pourrions indiquer "[4567]" à la place de "[4-7]" mais bon... Idem pour les lettres, il est possible d'écrire tout<br />

l'alphabet dans les crochets. Le trait d'union permet de simplifier l'expression.<br />

Précisons que ce qui se trouve à l'intérieur d'une classe (à l'exception des délimiteurs, de la barre oblique arrière \<br />

et du trait d'union -) n'a pas besoin d'être échappé. Ici, par exemple, le point est pris <strong>en</strong> tant que tel et non comme<br />

joker :<br />

Exemple de classe mixte<br />

<br />

Décomposition de la regex : []<br />

#^[a-z:/.-]+$# => Un ou plusieurs caractères parmi les lettres de l'alphabet, les deux points, la barre oblique, le<br />

point et le trait d'union.<br />

Tester ce script<br />

Enfin, une note sur le .* : bi<strong>en</strong> que pratique, il est souv<strong>en</strong>t peu judicieux de l'utiliser. Il est généralem<strong>en</strong>t préférable<br />

d'utiliser une classe dite négative :<br />

- 10 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple de classe négative<br />

<br />

Décomposition de la regex : []<br />

#^[^ ]+$# => N'importe quel caractère mais pas une seule espace dans la chaîne.<br />

Tester ce script<br />

• Caractère décimal<br />

[[:digit:]] ou [0-9] ou \d<br />

Équival<strong>en</strong>t <strong>PHP</strong> pour is_int($subject) : preg_match('/^\d+$/', $subject)<br />

Équival<strong>en</strong>t <strong>PHP</strong> approximatif pour is_numeric($subject) : preg_match('/^\d+(\.\d*)$/', $subject)<br />

• Caractère alphabétique<br />

[[:alpha:]] ou [a-zA-Z]<br />

Équival<strong>en</strong>t <strong>PHP</strong> approximatif pour ctype_alpha($subject) : preg_match('/^[a-z]+$/i', $subject)<br />

• Caractère alphanumérique<br />

[[:alphanum:]] ou [a-zA-Z0-9]<br />

- 11 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

• Caractère blanc (espace, tabulation, saut de ligne)<br />

[[:space:]] ou [\040\r\t] ou \s<br />

Équival<strong>en</strong>t C : isspace()<br />

• Limite de mot<br />

\b<br />

Les classes du g<strong>en</strong>re [[::]] sont héritées de la norme POSIX. Pour une liste plus complète, je vous laisse vous<br />

r<strong>en</strong>dre vers l'article de mon collègue Hugo Étiévant.<br />

II-5 - Les quantifieurs<br />

Il est possible de dire combi<strong>en</strong> de fois le dernier caractère (ou la dernière classe) peut/doit être répété. C'est<br />

l'objectif des quantifieurs.<br />

• "Zéro ou une fois" : point d'interrogation <br />

• "Zéro, une ou plusieurs fois" : étoile *<br />

• "Au moins une fois" : signe plus +<br />

• "Deux fois" : {2}<br />

• "De deux à quatre fois" : {2,4}<br />

• "Au moins deux fois" : {2,}<br />

• est équival<strong>en</strong>t à {0,1}<br />

• * est équival<strong>en</strong>t à {0,}<br />

• + est équival<strong>en</strong>t à {1,}<br />

Les regex pouvant être très rapidem<strong>en</strong>t compliquées, il est préférable de les simplifier tant que possible. Conseil<br />

d'ami.<br />

Il est évidemm<strong>en</strong>t possible de mettre n'importe quel nombre dans les accolades (pourvu que le premier nombre<br />

soit inférieur au second).<br />

N'oublions pas le fameux joker : le point. Il permet de remplacer n'importe quel caractère.<br />

Récupérer les domaines et sous domaines<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Récupérer les domaines et sous domaines<br />

echo "Le masque $pattern correspond-il à :";<br />

foreach($subjects as $subject){<br />

echo "$subject ";<br />

if(preg_match($pattern, $subject)){<br />

echo "Oui";<br />

}<br />

else{<br />

echo "Non";<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

#http://[a-z.-]+\.[a-z]{2,4}/#<br />

• http://<br />

• [a-z.-]+ : Au moins un caractère parmi les lettres de l'alphabet, le point et le trait d'union<br />

• \.[a-z]{2,4} : Un point suivi de deux à quatre lettres de l'alphabet<br />

Tester ce script<br />

II-6 - Les par<strong>en</strong>thèses<br />

Les regex permett<strong>en</strong>t une autre chose intéressante, à savoir de capturer des portions de la chaîne parcourue. Cela<br />

se fait au moy<strong>en</strong> des par<strong>en</strong>thèses.<br />

Pour récupérer une capture, il faut spécifier le paramètre optionnel de preg_match(). Cette variable conti<strong>en</strong>dra un<br />

tableau des résultats : l'index zéro conti<strong>en</strong>dra la chaîne complète correspondant au masque puis chaque index<br />

suivant sera rempli par une capture dans l'ordre où elles sont définies.<br />

Les par<strong>en</strong>thèses capturantes<br />

Exemple de capture simple<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple de capture simple<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

#http://([a-z-]+)\.developpez.com/#<br />

• http://<br />

• ([a-z-]+) : Un ou plusieurs caractères parmi les lettres et le trait d'union<br />

• \.developpez.com/<br />

Tester ce script<br />

Exemple de capture multiple<br />

<br />

Décomposition de la regex : []<br />

#http://([a-z-]+)\.([a-z]+)\.([a-z]+)/#<br />

• http://<br />

• \.([a-z]+) : Un point suivi d'une ou plusieurs lettres.<br />

• /<br />

Tester ce script<br />

Une version plus intéressante (car moins redondante) serait : []<br />

#http://([a-z-]+)(:\.([a-z]+)){2}/#<br />

- 14 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

• http://<br />

• (:\.([a-z]+)){2} : Un point suivi d'un ou plusieurs caractères parmi les lettres et le trait d'union. Ce bloc est<br />

répété une fois.<br />

• /<br />

Pour récupérer plusieurs fois un masque dans une même chaîne, nous pouvons utiliser la fonction<br />

preg_match_all() :<br />

Exemple permettant de récupérer le sous domaine, le domaine et l'ext<strong>en</strong>sion racine d'une l'URL<br />

<br />

Décomposition de la regex : []<br />

#[./]([a-z-]+)# => Un point ou une barre oblique, puis au moins une lettre de l'alphabet.<br />

Tester ce script<br />

Une autre utilisation des captures est la référ<strong>en</strong>ce arrière :<br />

Exemple de remplacem<strong>en</strong>t<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple de remplacem<strong>en</strong>t<br />

echo "$subject ";<br />

if(preg_match($pattern, $subject)){<br />

echo preg_replace(<br />

$pattern,<br />

"Le sous domaine est '\1', le domaine est '\2'",<br />

$subject);<br />

echo "";<br />

echo preg_replace(<br />

$pattern,<br />

"Le sous domaine est '$1', le domaine est '$2'",<br />

$subject);<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

#http://([a-z-]+)\.(developpez\.com)/#<br />

• http://<br />

• ([a-z-]+)\. : Une ou plusieurs lettres de l'alphabet (ou traits d'union) suivies d'un point<br />

• (developpez\.com)/ : La chaîne "developpez.com"<br />

Tester ce script<br />

Ici, j'ai utilisé les deux manières d'appeler une référ<strong>en</strong>ce arrière : au moy<strong>en</strong> de la barre oblique inversée \ ou au<br />

moy<strong>en</strong> du signe dollar $, suivies du numéro de la référ<strong>en</strong>ce (<strong>en</strong> comm<strong>en</strong>çant à 1, non à 0). Les deux méthodes<br />

sont équival<strong>en</strong>tes. Faites att<strong>en</strong>tion si vous utilisez plus de neuf référ<strong>en</strong>ces car la conv<strong>en</strong>tion de nommage peut<br />

poser problème. Reportez-vous à la docum<strong>en</strong>tation <strong>PHP</strong> pour toute information complém<strong>en</strong>taire.<br />

Les par<strong>en</strong>thèses non capturantes<br />

Il est possible d'utiliser des par<strong>en</strong>thèses sans pour autant définir une capture. Cela peut servir dans certaines<br />

situations, notamm<strong>en</strong>t lorsque nous voulons donner une alternative :<br />

Par<strong>en</strong>thèses non capturantes<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Par<strong>en</strong>thèses non capturantes<br />

><br />

Décomposition de la regex : []<br />

/[a-z]+\s(:[a-z]+['\s])([a-z]+(:es|ons|ez|<strong>en</strong>t|e))/i<br />

• [a-z]+\s : Une ou plusieurs lettres de l'alphabet suivies d'une espace<br />

• (:[a-z]+['\s]) : Une ou plusieurs lettres de l'alphabet suivies soit d'une espace soit d'une apostrophe (ce<br />

bloc est facultatif)<br />

• ([a-z]+(:es|ons|ez|<strong>en</strong>t|e)) : Tout mot terminant par "e", "es", "ons", "ez" ou "<strong>en</strong>t" (on capture le mot <strong>en</strong>tier)<br />

Tester ce script<br />

Dans cet exemple, ce qui nous intéresse n'est pas uniquem<strong>en</strong>t la terminaison du verbe mais le verbe <strong>en</strong>tier. Il y a<br />

donc un couple de par<strong>en</strong>thèses capturantes autour du verbe et un couple de par<strong>en</strong>thèses non capturantes autour<br />

de la terminaison.<br />

II-7 - Les modificateurs<br />

Les modificateurs sont un apport très consistant des PCRE depuis la norme POSIX. Ils permett<strong>en</strong>t de modifier la<br />

manière dont le moteur de regex va parcourir la chaîne.<br />

• U<br />

"Ungreedy", c'est-à-dire non gourmand. Cela signifie que l'expression trouvera des résultats aussi petits que<br />

possible.<br />

Essayez l'expression ci-dessous avec et sans le modificateur U. Dans certains cas, la regex pourrait même<br />

retourner depuis le premier jusqu'au dernier (cf. exemple ci-dessous) !<br />

• s<br />

Permet de demander au point de cont<strong>en</strong>ir égalem<strong>en</strong>t les sauts de ligne. Par défaut, ce n'est pas le cas.<br />

• i<br />

Permet de ne pas t<strong>en</strong>ir compte de la casse. Ainsi, les masques [a-z], [A-Z] et toutes leurs variantes sont<br />

équival<strong>en</strong>ts. Il est inutile de préciser [a-zA-Z], ce qui peut être pratique dans de nombreux cas.<br />

Essayez ces exemples avec et sans leur modificateur :<br />

Exemple de modificateur 'U' (expression non gourmande)<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Exemple de modificateur 'U' (expression non gourmande)<br />

$patterns = array();<br />

$patterns[] = "#(.*)#";<br />

$patterns[] = "#(.*)#U";<br />

$subjects = array();<br />

$subjects[] = "Je m'appelle Guillaume,"<br />

.' mon site est http://g-rossolini.developpez.com/.";<br />

$subjects[] = "Il s'appelle Pierre-Baptiste,"<br />

.' son site est http://pbnaigeon.developpez.com/.";<br />

foreach($patterns as $pattern){<br />

echo "Le masque $pattern correspond-il à :";<br />

foreach($subjects as $subject){<br />

$matches = array();<br />

echo "$subject ";<br />

if(preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)){<br />

echo "Oui : ";<br />

print_r($matches);<br />

echo "";<br />

}<br />

else{<br />

echo "Non";<br />

}<br />

><br />

}<br />

echo "";<br />

}<br />

echo "";<br />

Décomposition de la regex : []<br />

#(.*)#U => N'importe quelle suite de caractères <strong>en</strong>cadrée d'une balise de mise <strong>en</strong> gras.<br />

Tester ce script<br />

Exemple de modificateur 's'<br />

<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

- 18 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Décomposition de la regex : []<br />

#(.*)#s => N'importe quelle suite de caractères <strong>en</strong>cadrée d'une balise de mise <strong>en</strong> italique.<br />

Tester ce script<br />

II-8 - Les assertions<br />

Les assertions permett<strong>en</strong>t de déterminer la prés<strong>en</strong>ce ou l'abs<strong>en</strong>ce de caractères avant ou après la position du<br />

curseur dans la chaîne. Pour plus de détails sur ce curseur, veuillez vous reporter à la docum<strong>en</strong>tation officielle.<br />

Il existe des assertions simples telles que \b, décrit succinctem<strong>en</strong>t plus haut, ainsi que des assertions plus<br />

complexes. Nous allons nous attarder sur ces dernières.<br />

Je ne traiterai pas des assertion positives car elles me sembl<strong>en</strong>t totalem<strong>en</strong>t inutiles : autant mettre la chaîne sans<br />

assertion, cela revi<strong>en</strong>t au même que faire une assertion positive. Pour les curieux, il s'agit de (=) et (<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

Décomposition des regex : []<br />

#http://(!www)# => La chaîne "http://" non suivie de "www" #http://(!php)# => La chaîne "http://" non suivie<br />

de "php"<br />

- 19 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Tester ce script<br />

Les assertions négatives arrière<br />

Elles permett<strong>en</strong>t de déterminer si une chaîne est précédée d'une autre chaîne (par son abs<strong>en</strong>ce).<br />

Le sous domaine n'est pas...<br />

<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

Décomposition des regex : []<br />

#(


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

III - Fonctions<br />

III-1 - preg_grep()<br />

Permet d'appliquer une regex à chaque élém<strong>en</strong>t d'un tableau. Retourne un tableau des élém<strong>en</strong>ts pour lesquels la<br />

regex s'applique avec succès.<br />

Trouver les noms propres dans un tableau<br />

<br />

Décomposition de la regex : []<br />

/^[A-Z]/ => La chaîne comm<strong>en</strong>ce par une majuscule de l'alphabet<br />

Tester ce script<br />

III-2 - preg_match_all()<br />

Permet de trouver toutes les occur<strong>en</strong>ces qui satisfont un masque dans une chaîne. Retourne le nombre de succès.<br />

Trouver les noms propres dans une chaîne<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Trouver les noms propres dans une chaîne<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

/[A-Z][a-z]+/ => Une lettre majuscule de l'alphabet puis au moins une lettre minuscule.<br />

Tester ce script<br />

Trouver les li<strong>en</strong>s dans une chaîne<br />

(.*)#Usi";<br />

$subjects = array();<br />

$subjects[] = 'Accueil de Développez.com - '."\n"<br />

.'Forums de Développez.com - ';<br />

$subjects[] = 'Mes articles - '."\n"<br />

.'Les articles <strong>PHP</strong> de Développez.com';<br />

echo "Le masque $pattern correspond-il à :";<br />

foreach($subjects as $subject){<br />

$matches = array();<br />

echo "$subject ";<br />

if(preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)){<br />

echo "Oui :";<br />

print_r($matches);<br />

echo "";<br />

}<br />

else{<br />

echo "Non";<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

/# : Une chaîne quelconque <strong>en</strong>cadrée de guillem<strong>en</strong>ts, le tout dans une balise d'ancrage<br />

HTML.<br />

• (.*) : Une chaîne quelconque suivie de la balise fermante de l'ancrage.<br />

Tester ce script<br />

III-3 - preg_match()<br />

Similaire à preg_match_all() mais s'arrête au premier résultat. Idéal pour déterminer l'exist<strong>en</strong>ce d'une sous chaîne<br />

satisfaisant un masque. Retourne un état du succès de l'opération (vrai/f<strong>aux</strong>).<br />

Déterminer si une adresse e-mail est syntaxiquem<strong>en</strong>t valide<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Déterminer si une adresse e-mail est syntaxiquem<strong>en</strong>t valide<br />

$pattern = "/^([^@\s]+)@(:([-a-z0-9]+)\.)+([a-z]{2,})$/i";<br />

$subjects = array();<br />

$subjects[] = "http://g-rossolini.developpez.com/";<br />

$subjects[] = "truc@domaine.com";<br />

$subjects[] = "bidule@autre-domaine.fr";<br />

echo "Le masque $pattern correspond-il à :";<br />

foreach($subjects as $subject){<br />

$matches = array();<br />

echo "$subject ";<br />

if(preg_match($pattern, $subject, $matches, PREG_SET_ORDER)){<br />

echo "Oui :";<br />

print_r($matches);<br />

echo "";<br />

}<br />

else{<br />

echo "Non";<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

/^([^@\s]+)@(:([-a-z0-9]+)\.)+([a-z]{2,})$/<br />

• ^([^@\s]+)@ : Au début de la chaîne, tous les caractères qui ne sont pas espace, arobase, ;<br />

s'<strong>en</strong>suit l'arobase<br />

• (:([-a-z0-9]+)\.)+ : Les lettres, chiffres et traits d'union ; le tout est suivi d'un point<br />

• ([a-z]{2,})$ : À partir de deux lettres<br />

Tester ce script<br />

III-4 - preg_quote()<br />

L'équival<strong>en</strong>t d'addslashes() pour les regex. Utile uniquem<strong>en</strong>t pour construire le masque des fonctions PCRE.<br />

Retourne la chaîne échappée.<br />

Déterminer si une chaîne est une question (majuscule et point d'interrogation)<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Déterminer si une chaîne est une question (majuscule et point d'interrogation)<br />

><br />

Décomposition de la regex : []<br />

/ROSSOLINI/i<br />

• ^[A-Z] : Une majuscule <strong>en</strong> début de chaîne<br />

• .* : N'importe quels caractères (voire aucun)<br />

• \$ : Un point d'interrogation ferme la chaîne<br />

• \*$ : Une étoile ferme la chaîne<br />

Tester ce script<br />

III-5 - preg_replace()<br />

Permet de remplacer au moy<strong>en</strong> d'une regex. Retourne la chaîne modifiée.<br />

BBCode simple<br />

<br />

Décomposition de la regex : []<br />

#\[b\](.*)\[/b\]# => Un bloc BBCode [b] et [/b] <strong>en</strong>cadre n'importe quelle suite de caractères<br />

Tester ce script<br />

III-6 - preg_replace_callback()<br />

Idem que preg_replace() mais permet d'utiliser une fonction utilisateur pour effectuer les remplacem<strong>en</strong>ts<br />

complexes (plus d'une instruction). Retourne la chaîne modifiée.<br />

BBCode complexe<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

BBCode complexe<br />

function color_string($match){<br />

// Ici, nous pourrions faire<br />

// une connexion à une base de données<br />

switch($match[1]){<br />

case "red":<br />

$new_color = "#FF0000";<br />

break;<br />

}<br />

}<br />

case "gre<strong>en</strong>":<br />

$new_color = "#00FF00";<br />

break;<br />

case "blue":<br />

$new_color = "#0000FF";<br />

break;<br />

default:<br />

$new_color = NULL;<br />

break;<br />

if($new_color){<br />

return ''.$match[2].'';<br />

}<br />

else{<br />

return $match[2];<br />

}<br />

$pattern<br />

= "#\[colour="([a-z]+)"\](.*)\[/colour\]#";<br />

$subjects = array();<br />

$subjects[] = "expression [color="blue"]régulière[/color]";<br />

$subjects[] = "expression [colour="gre<strong>en</strong>"]régulière[/color]";<br />

$subjects[] = "expression [colour="red"]régulière[/colour]";<br />

$subjects[] = "expression [couleur="blue"]régulière[/couleur]";<br />

$subjects[] = "expression [color="gre<strong>en</strong>"]régulière[/col]";<br />

$subjects[] = "expression [font-color="red"]régulière[/font-color]";<br />

echo "Le masque $pattern se trouve-t-il :";<br />

foreach($subjects as $subject){<br />

echo "dans $subject ";<br />

if(preg_match($pattern, $subject)){<br />

echo "Oui : ".preg_replace_callback(<br />

$pattern, //'color' et 'colour' fonctionn<strong>en</strong>t<br />

"color_string",<br />

$subject);<br />

}<br />

else{<br />

echo "Non";<br />

}<br />

echo "";<br />

}<br />

echo "";<br />

><br />

Décomposition de la regex : []<br />

#\[colour="([a-z]+)"\](.*)\[/colour\]#<br />

• \[colour="([a-z]+)"\] : Un bloc [color=""] ou [colour=""] conti<strong>en</strong>t un nom de couleur (à partir d'une lettre)<br />

• (.*) : N'importe quels caractères (voire aucun) et on les capture<br />

• \[/colour\] : Un bloc [color] ou [colour]<br />

Tester ce script<br />

III-7 - preg_split()<br />

- 25 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Alternative PCRE à split(). Idéal pour parcourir un fichier CSV dont on ne connaît pas à l'avance le séparateur de<br />

champs.<br />

Découper une chaîne<br />

<br />

Décomposition de la regex : []<br />

/[,&\s()]/ => Utiliser la virgule, l'esperluette, les caractères d'espacem<strong>en</strong>t et les par<strong>en</strong>thèses pour découper une<br />

chaîne.<br />

Tester ce script<br />

- 26 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

IV - Sécurité<br />

Il existe une technique appelée "regex injection". Le principe est de tirer parti du modificateur "e" utilisé dans<br />

certaines regexes afin d'introduire et d'exécuter du code <strong>PHP</strong> arbitraire, à la manière de l'injection SQL.<br />

Repr<strong>en</strong>ons l'exemple ci-dessus de preg_replace() afin d'illustrer l'utilisation du modificateur 'e'<br />

<br />

Décomposition de la regex : []<br />

#\[b\](.*)\[/b\]#e => N'importe quelle suite de caractères <strong>en</strong>cadrée d'une balise BBCode de mise <strong>en</strong> gras.<br />

Tester ce script<br />

La regex apparaît avec le modificateur "e", utilisable uniquem<strong>en</strong>t avec la fonction preg_replace().<br />

La fonction preg_replace() n'utilise plus seulem<strong>en</strong>t '$1' mais "''.strtoupper('$1').''" afin de mettre <strong>en</strong><br />

majuscules la chaîne trouvée.<br />

Cette regex fonctionne mais il y a un inconvéni<strong>en</strong>t : elle peut être vulnérable à une injection de code. Dans le cas<br />

prés<strong>en</strong>t, puisque l'utilisateur ne peut ri<strong>en</strong> introduire dans la chaîne, nous sommes <strong>en</strong> sécurité. Toutefois, il me<br />

semble périlleux d'utiliser une méthode qui, sous certaines conditions, permet à quelqu'un d'exécuter du code <strong>PHP</strong><br />

de son choix.<br />

En fait, la faille de sécurité (injection de regex) est utilisable uniquem<strong>en</strong>t si l'utilisateur a un contrôle sur la chaîne<br />

de remplacem<strong>en</strong>t. Il est difficile de trouver un exemple représ<strong>en</strong>tatif, dans la mesure où ces situations sont très<br />

rares.<br />

Christian W<strong>en</strong>z propose une démonstration dans son article Regular Expression Injection. Je me permets de<br />

reformuler son code afin de vous proposer une version qui me semble plus adaptée : utiliser la fonction md5()<br />

plutôt que strtolower(). C'est l'appel à ces fonctions qui r<strong>en</strong>d le modificateur "e" obligatoire lorsque nous utilisons<br />

preg_replace().<br />

users.xml : les mots de passe sont tous deux 'secret' <strong>en</strong> MD5<br />

<br />

- 27 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

users.xml : les mots de passe sont tous deux 'secret' <strong>en</strong> MD5<br />

<br />

<br />

administrator<br />

1e6947ac7fb3a9529a9726eb692c8cc5<br />

<br />

<br />

John Doe<br />

1e6947ac7fb3a9529a9726eb692c8cc5<br />

<br />

<br />

Démonstration de l'injection de regex<br />

<br />

<br />

<br />

<br />

Nom d'utilisateur :<br />

<br />

<br />

<br />

Mot de passe actuel :<br />

<br />

<br />

<br />

Nouveau mot de passe :<br />

<br />

<br />

<br />

<br />

<br />

// Si le remplacem<strong>en</strong>t a fonctionné, on écrit le nouveau XML<br />

if($nb_of_changes){<br />

file_put_cont<strong>en</strong>ts('users.xml', $users);<br />

}<br />

Décomposition de la regex : []<br />

- 28 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

#(>username\s*/usernamepassword\s*/password Les<br />

balises XML "username" et "password" cont<strong>en</strong>ant les valeurs saisies par l'utilisateur et un nombre variable<br />

d'espaces.<br />

• '.die('Arrêt du script').'<br />

• '.system('reboot').'<br />

• '.eval('echo "Informations de debug:"; echo ""; print_r($_POST); echo ""; exit;').'<br />

Il n'est pas possible de passer plus d'une commande <strong>PHP</strong> avec cette vulnérabilité. Cep<strong>en</strong>dant, s'il n'est pas<br />

désactivé sur le serveur, le construct <strong>PHP</strong> eval() permet d'exécuter toutes les commandes que nous voulons.<br />

Une solution sûre consiste à ne pas utiliser le modificateur "e" et à déléguer les traitem<strong>en</strong>ts à une autre fonction<br />

(plutôt que de tout faire dans preg_replace()), appelée "fonction de callback". C'est r<strong>en</strong>du possible par<br />

preg_replace_callback().<br />

Alternative sécurisée au premier exemple<br />

<br />

Décomposition de la regex : []<br />

#\[b\](.*)\[/b\]# => N'importe quelle suite de caractères <strong>en</strong>cadrée d'une balise BBCode de mise <strong>en</strong> gras.<br />

Tester ce script<br />

Alternative sécurisée au second exemple<br />


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

Alternative sécurisée au second exemple<br />

// Données <strong>en</strong> <strong>en</strong>trée<br />

$username = (isset($_POST['username'])) $_POST['username'] : '';<br />

$password = (isset($_POST['password'])) $_POST['password'] : '';<br />

$newpassword = (isset($_POST['newpassword'])) $_POST['newpassword'] : '';<br />

><br />

<br />

<br />

<br />

Nom d'utilisateur :<br />

<br />

<br />

<br />

Mot de passe actuel :<br />

<br />

<br />

<br />

Nouveau mot de passe :<br />

<br />

<br />

<br />

<br />

<br />

// Si le remplacem<strong>en</strong>t a fonctionné, on écrit le nouveau XML<br />

if($nb_of_changes){<br />

file_put_cont<strong>en</strong>ts('users.xml', $users);<br />

}<br />

Décomposition de la regex : []<br />

#(>username\s*/usernamepassword\s*/password Les<br />

balises XML "username" et "password" cont<strong>en</strong>ant les valeurs saisies par l'utilisateur et un nombre variable<br />

d'espaces.<br />

- 30 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/


<strong>Initiation</strong> <strong>aux</strong> <strong>expressions</strong> <strong>régulières</strong> <strong>en</strong> <strong>PHP</strong> par Guillaume Rossolini<br />

V - Conclusion<br />

Utilisées à bon esci<strong>en</strong>t, les <strong>expressions</strong> <strong>régulières</strong> permett<strong>en</strong>t de faire beaucoup de choses.<br />

Gardez à l'esprit qu'il est plus rapide d'exécuter une fonction native de <strong>PHP</strong> qu'une expression régulière, ainsi il ne<br />

faut pas <strong>en</strong> mettre à toutes les sauces.<br />

Le moteur de PCRE optimise vos <strong>expressions</strong> avant de les exécuter mais il est toujours préférable de p<strong>en</strong>ser à les<br />

optimiser. Réfléchissez bi<strong>en</strong> à vos regex, ne partez pas dans des solution trop alambiquées. Si l'expression vous<br />

semble complexe à relire, alors il est certainem<strong>en</strong>t temps de la scinder <strong>en</strong> plusieurs petites. Je n'ai pas traité de la<br />

possibilité de comm<strong>en</strong>ter une regex mais sachez que c'est égalem<strong>en</strong>t possible.<br />

• L'équival<strong>en</strong>t de ctype_alpha() <strong>en</strong> regex met 150% plus de temps à trouver le résultat que la fonction native<br />

de <strong>PHP</strong>.<br />

• L'équival<strong>en</strong>t de is_numeric() <strong>en</strong> regex met 250% plus de temps à trouver le résultat que la fonction native de<br />

<strong>PHP</strong>.<br />

• Les <strong>expressions</strong> <strong>régulières</strong> POSIX par Hugo Étiévant<br />

• Post processing d'une page Web pour la réécriture de ses URLs (une utilisation parmi tant d'autres pour les<br />

regex)<br />

• Le script utilisé pour les tests tout au long de ce cours<br />

• Outil de test d'expression régulères<br />

• Le manuel <strong>PHP</strong> sur les PCRE<br />

• Le site officiel des PCRE<br />

• Regular Expression Injection par Christian W<strong>en</strong>z<br />

- 31 -<br />

Les sources prés<strong>en</strong>tés sur cette pages sont libres de droits, et vous pouvez les utiliser à votre conv<strong>en</strong>ance. Par contre la page de prés<strong>en</strong>tation<br />

de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 - Guillaume Rossolini. Aucune<br />

reproduction, même partielle, ne peut être faite de ce site et de l'<strong>en</strong>semble de son cont<strong>en</strong>u : textes, docum<strong>en</strong>ts, images, etc sans l'autorisation<br />

expresse de l'auteur. Sinon vous <strong>en</strong>courez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.<br />

http://g-rossolini.developpez.com/tutoriels/php/<strong>expressions</strong>-regulieres/

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!