Supplément pour projet de fin de session
Dernière mise à jour le 5 décembre 2022
Les expressions régulières en PHP
Les expressions régulières se retrouvent dans bon nombre de langages de programmation (vous les avez déjà utilisées en JavaScript). Elles sont utiles pour effectuer des recherches plus spécifiques sur un ensemble de caractères ou une chaîne de caractères.
D'accord, mais à quoi servent-elles exactement?
Elles sont idéales pour tester si une chaîne de caractères correspond à un motif particulier et rendre encore plus flexible la validation des données de formulaires.
Elles sont utilisées, entre autres choses, pour :
- Vérifier si l'URL entrée par l'utilisateur ressemble effectivement à une URL. On peut faire pareil pour les adresses courriel, les numéros de téléphone ou toute autre syntaxe structurée.
- Rechercher et extraire des informations à partir d'une chaîne de caractères.
- Supprimer certains caractères et au besoin les remplacer par d'autres.
Syntaxe
La syntaxe des expressions régulières inclut l’utilisation de caractères spéciaux. Les caractères auxquels on donne une signification spéciale dans une expression régulière, sont : . * ? + [ ] ( ) { } ^ $ |
.
Vous devrez échapper ces caractères chaque fois que vous voudrez les utiliser littéralement. Par exemple, si vous voulez faire correspondre .
, vous devrez écrire \.
Tous les autres caractères prennent automatiquement leur sens littéral.
Le tableau suivant décrit les regex les plus courants :
Motif | Signification |
---|---|
^ | Début de ligne ou de chaîne |
$ | Fin de ligne ou de chaîne |
. | N'importe quel caractère |
x|y | Caractère x ou y |
[abc] | Groupe de caractères : n'importe lequel de ceux entre crochets |
[a-z] | Groupe de caractères : n'importe lequel de a à z |
[^0-9] | Groupe de caractères : tous sauf ceux de 0 à 9 |
(x) | Expression parenthésée (mémorisée) |
* | Caractère précédent de 0 à X fois |
+ | Caractère précédent de 1 à X fois |
? | Caractère précédent de 0 à 1 fois |
{n} | Caractère précédent exactement n fois |
{n,} | Caractère précédent au moins n fois |
{,n} | Caractère précédent au plus n fois |
\ | N'est pas un caractère, sert d'échappement |
\\ | Caractère \ |
\d | Chiffre (équivalent à [0-9] |
\D | Sauf chiffres (équivalent à [^0-9] |
\b | Frontière de mot (espace, alinéa, ...) |
\s | Caractère d'espacement (espace, tabulation, saut de page, ...), équivalent à [ \f\n\r\t\v] |
\S | Un seul caractère, sauf un espacement |
\w | N'importe quel caractère alphanumérique, y compris souligné (_), équivalent à [A-Za-z0-9] |
\W | Tout sauf un caractère alphanumérique, équivalent à [^A-Za-z0-9_] |
Délimiteur
Les principales fonctions PHP qui utilisent les expressions régulières commencent toutes par "preg". Ce sont preg_match(), preg_match_all(), preg_replace(), preg_grep() et preg_split().
La première et la plus importante chose à savoir sur les fonctions "preg" est qu’ils s’attendent à ce que vous encadriez les motifs de regex (REGulat EXpression) avec un caractère délimiteur de chaque côté.
Par exemple, si vous choisissez ~
comme délimiteur, pour le motif regex \b\w\w+\b
, vous devrez donner la chaîne ~\b\w+\b~
à la fonction "preg".
Pour le délimiteur, vous pouvez choisir n’importe quel caractère à l’exception des espaces et des barres obliques inverses. Mais choisissez judicieusement, car si votre délimiteur apparaît dans le motif, il doit être échappé avec le caractère \
.
Fonctions utilisant les expressions régulières
Le tableau suivant rassemble les principales fonctions PHP qui utilisent les expressions régulières.
Fonction | Description |
---|---|
preg_match() |
Recherche un motif dans la chaîne de caractères. Retourne 1 si le motif existe, 0 sinon (et FALSE en cas d'erreur). La fonction arrête la recherche après avoir trouvé la première correspondance. Exemple :
$chaine = "Un anneau pour les gouverner tous.";
$retour = preg_match("/ann/", $chaine);
echo $retour . "<br>";
// affiche 1
$retour = preg_match("/annn/", $chaine);
echo $retour . "<br>";
// affiche 0
|
preg_match_all() |
Effectue une recherche globale sur toutes les occurrences du motif dans la chaîne. La fonction continue la recherche jusqu’à la fin de la chaîne et trouve toutes les correspondances possibles au lieu de s’arrêter au premier résultat comme avec la fonction précédente. Les correspondances sont rangées dans le tableau fourni en paramètre. Exemple : $chaine = "Un anneau pour les gouverner tous."; $resultat = array(); $retour = preg_match_all("/ne[a-z]/", $chaine, $resultat); print_r($resultat); // affiche Array ( [0] => Array ( [0] => nea [1] => ner ) ) |
preg_replace() |
Effectue une recherche et un remplacement d’expressions régulières. Exemple : $chaine = "Un anneau pour les gouverner tous."; $remplacement = "X"; $retour = preg_replace("/ne[a-z]/", $remplacement, $chaine); echo $retour; // affiche Un anXu pour les gouverX tous. |
preg_grep() |
Fait une recherche parmi les éléments du tableau d’entrée, retournant tous les éléments correspondant à l'expression régulière dans un autre tableau (ou FALSE en cas d'erreur). $tab = ["123", "qw45", "gh3", "65tt"]; $tab_retour = preg_grep("/[1-9]{2}/", $tab); print_r($tab_retour); // affiche Array ( [0] => 123 [1] => qw45 [3] => 65tt ) On remarque que le tableau retourné utilise les clés du tableau d'entrée. |
preg_split() |
Divise ("éclate" ou "explose") une chaîne de caractères en un tableau de chaînes de caractères en utilisant une expression régulière. Exemple : $lotr = "Il y avait 3 anneaux pour les rois, 7 pour les nains et 9 pour les hommes."; $tab_retour = preg_split("/[1-9]/", $lotr); echo "<pre>"; foreach ($tab_retour as $chaine) { echo "[ " . $chaine . "]<br>"; } echo "</pre>"; Sortie : [ Il y avait ] [ anneaux pour les rois, ] [ pour les nains et ] [ pour les hommes.] |
Consultez la documentation officielle pour en savoir plus sur l'utilisation de ces fonctions.
Exemple de validation d'une URL
Voici le code nécessaire pou valider une URL :
$url = "https://prog101.com/cours/kb9/"; if (preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:.[A-Z0-9][A-Z0-9_-]*)+):?(d+)?\/?/i', $url)) { echo "URL valide"; } else { echo "URL invalide"; }
D'accord, c'est un peu lourd. Il y a peut-être d'autres moyens...
La fonction filter_var()
La fonction filter_var() filtre une variable à l'aide d'un filtre spécifique.
Exemple :
$url = filter_var("https://prog101.com/cours/kb9/", FILTER_VALIDATE_URL); if (! $url) { echo "La chaîne n'est pas une URL valide"; }
Plus simple n'est-ce pas?
Il existe une dizaine de filtres de validation :
Filtre | Retourne TRUE si est... |
---|---|
FILTER_VALIDATE_BOOLEAN FILTER_VALIDATE_BOOL | un booléen |
FILTER_VALIDATE_DOMAIN | un nom de domaine |
FILTER_VALIDATE_EMAIL | une adresse courriel |
FILTER_VALIDATE_FLOAT | un nombre à virgule flottante |
FILTER_VALIDATE_INT | un nombre entier |
FILTER_VALIDATE_IP | une adresse IP |
FILTER_VALIDATE_MAC | une adresse MAC |
FILTER_VALIDATE_REGEXP | une expression régulière |
FILTER_VALIDATE_URL | une URL |
Il existe aussi des filtres de nettoyage. Consultez la documentation pour en savoir plus.
En guise de résumé
Appliquez ce traitement à tous les intrants de vos applications Web :
[client] Validation du formulaire (validation HTML / JavaScript) ↓ [serveur] Nettoyage et validation des paramètres (PHP, expressions régulières, filtres, etc.) ↓ [base de données] Requêtes préparées ou procédures stockées
Et ne faites jamais confiance à l'utilisateur!
Nettoyer les commentaires (PFI - Livrable 3)
Si vous ne voulez pas voir toutes sortes de choses dans vos commentaires, comme des images ou des messages écrits en caractères géants, vous devez en filtrer le contenu. Et cette fois, il ne s'agit pas d'éviter les injections SQL, mais simplement de filtrer les balises HTML.
Ici deux approche sont possibles :
- Permettre l'utilisation de balises HTML pour agrémenter le texte. Par exemple, autoriser le texte en caractères gras ou italiques. Pour cela vous pouvez faire appel à la fonction strip_tags (déjà présentée) qui permet de filtrer l'ensemble des balises HTML ou d'en autoriser certaines.
-
Permettre l'affichage de balises HTML à des fins explicatives. Par exemple, si un commentaire fait référence à la balise
<header>
, n'est-il pas approprié de pouvoir l'écrire comme tel, entourée des caractères<
et>
? On y arrive en faisant appel à la fonction htmlentities.Exemple avec une balise de titre :
<?php // la balise <h2> sera interprétée par le navigateur $titre = '<h2>Ceci est un titre de niveau 2</h2>'; echo $titre; // la balise <h2> ne sera pas interprétée $titre = htmlentities('<h2>Ceci est un titre de niveau 2</h2>'); echo $titre;
Sortie :
Ceci est un titre de niveau 2
<h2>Ceci est un titre de niveau 2</h2>