Initiation aux expressions régulières en PHP
Initiation aux expressions régulières en PHP
Initiation aux expressions régulières en PHP
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/