fnmatch()
La fonction fnmatch() est une fonction PHP intégrée qui vérifie si une chaîne correspond à un motif générique de shell, utilisée pour filtrer des noms de fichiers.
Qu'est-ce que la fonction fnmatch() ?
La fonction fnmatch() vérifie si une chaîne correspond à un motif générique de shell — le même type de motif que vous tapez dans un terminal, comme *.txt ou image-?.png. Elle retourne un boolean, aussi est-elle le plus souvent utilisée pour filtrer des noms de fichiers ou d'autres chaînes sans écrire une expression régulière complète.
Malgré son nom, fnmatch() n'accède jamais au système de fichiers. Elle compare uniquement le motif à la chaîne que vous lui passez, et fonctionne donc sur n'importe quel texte, pas seulement sur de vrais fichiers.
Cette page couvre la signature de la fonction, les caractères génériques qu'elle reconnaît, les flags optionnels, ainsi que les cas pratiques où elle surpasse à la fois glob() et les expressions régulières.
Syntaxe
fnmatch(string $pattern, string $filename, int $flags = 0): bool$pattern— le motif générique de shell à comparer.$filename— la chaîne à tester (elle n'a pas besoin d'être un vrai fichier).$flags— flags binaires optionnels qui modifient le comportement de la correspondance (voir Flags).
La fonction retourne true lorsque $filename correspond à $pattern, et false sinon.
Exemple de base
Ici myfile.txt correspond à *.txt, donc la première branche s'exécute et affiche The string matches the pattern!. Remplacez la chaîne par myfile.csv et la correspondance échoue.
Caractères génériques
fnmatch() reconnaît les caractères génériques shell standard. Savoir exactement ce que fait chacun est la clé pour utiliser la fonction correctement :
| Caractère générique | Signification | Exemple de motif | Correspond à | Ne correspond pas à |
|---|---|---|---|---|
* | N'importe quelle séquence de caractères (y compris aucun) | *.log | error.log, .log | error.txt |
? | Exactement un caractère | file?.txt | file1.txt | file12.txt |
[...] | Un caractère de l'ensemble | image.[jp]ng | image.jng, image.png | image.gng |
[!...] | Un caractère absent de l'ensemble | [!0-9]* | abc | 1abc |
L'exemple suivant illustre chaque caractère générique côte à côte :
<?php
var_dump(fnmatch("*.log", "error.log")); // bool(true) — * matches "error"
var_dump(fnmatch("file?.txt", "file1.txt")); // bool(true) — ? matches one char
var_dump(fnmatch("file?.txt", "file12.txt"));// bool(false) — ? matches only ONE char
var_dump(fnmatch("img.[jp]ng", "img.png")); // bool(true) — p is in [jp]
var_dump(fnmatch("[!0-9]*", "abc")); // bool(true) — first char is not a digit
var_dump(fnmatch("[!0-9]*", "1abc")); // bool(false) — first char IS a digitFlags
Le troisième argument accepte une ou plusieurs des constantes suivantes, combinées avec l'opérateur OR binaire (|) :
| Flag | Effet |
|---|---|
FNM_NOESCAPE | Traite une barre oblique inverse (\) littéralement plutôt que comme un caractère d'échappement. |
FNM_PATHNAME | Un slash (/) dans la chaîne doit être mis en correspondance par un / littéral — * et ? ne pourront pas le faire. |
FNM_PERIOD | Un point en début de chaîne doit être mis en correspondance explicitement ; * et ? ne pourront pas le faire. |
FNM_CASEFOLD | Effectue la correspondance sans tenir compte de la casse. |
FNM_CASEFOLD est le flag que vous utiliserez le plus souvent :
<?php
var_dump(fnmatch("*.PNG", "photo.png")); // bool(false) — case differs
var_dump(fnmatch("*.PNG", "photo.png", FNM_CASEFOLD)); // bool(true) — case ignoredAvec FNM_PATHNAME, le caractère générique * s'arrête aux séparateurs de répertoire, ce qui est pratique pour faire correspondre des chemins complets :
<?php
var_dump(fnmatch("src/*.php", "src/index.php")); // bool(true)
var_dump(fnmatch("src/*.php", "src/lib/db.php")); // bool(true) — * crosses the slash
var_dump(fnmatch("src/*.php", "src/lib/db.php", FNM_PATHNAME));// bool(false) — * cannot cross "/"Cas pratique : filtrer une liste de fichiers
Une tâche courante consiste à ne conserver que les entrées correspondant à un motif. Comme fnmatch() fonctionne sur des chaînes simples, elle s'associe naturellement à array_filter() :
<?php
$files = ["report.pdf", "notes.txt", "draft.txt", "image.png"];
$textFiles = array_filter($files, fn($file) => fnmatch("*.txt", $file));
print_r(array_values($textFiles));Cela affiche :
Array
(
[0] => notes.txt
[1] => draft.txt
)fnmatch() vs. glob() vs. expressions régulières
Ces trois outils se recoupent, aussi le choix du bon outil est-il important :
- Utilisez
glob()lorsque vous souhaitez lire des fichiers réels depuis le disque correspondant à un motif. Elle accède au système de fichiers et retourne les chemins correspondants. - Utilisez
fnmatch()lorsque vous avez déjà des chaînes (noms de fichiers, clés, étiquettes) en mémoire et que vous n'avez besoin que d'une vérification vrai/faux par rapport à un motif générique. - Utilisez
preg_match()lorsque vous avez besoin de toute la puissance des expressions régulières — groupes de capture, alternance, quantificateurs — que les simples caractères génériques ne peuvent pas exprimer.
Pièges courants
- Ce n'est pas le système de fichiers.
fnmatch()ne vérifie pas l'existence d'un fichier ; elle compare uniquement des chaînes. Pour l'accès au disque, utilisezglob(). - Disponibilité. Sur les versions Windows antérieures à PHP 7.2,
fnmatch()peut être indisponible. Enveloppez les appels dansfunction_exists('fnmatch')si vous devez prendre en charge ces environnements. - Les motifs ne sont pas des expressions régulières.
*signifie « n'importe quels caractères », et non « zéro ou plusieurs occurrences du jeton précédent ». Si vous écriveza+en vous attendant à un quantificateur regex, il sera traité comme les deux caractères littérauxaet+. - Fichiers cachés. Par défaut,
*correspond à un point en début de nom, donc*correspond à.gitignore. AjoutezFNM_PERIODsi vous souhaitez ignorer les fichiers dotfiles comme le fait un shell.
Conclusion
fnmatch() est le moyen le plus simple de tester une chaîne par rapport à un motif générique de type shell en PHP. Utilisez-la lorsque vous avez besoin d'un filtrage rapide et lisible des noms de fichiers sans la complexité d'une expression régulière — et n'oubliez pas ses compagnons glob() pour lire des fichiers depuis le disque et preg_match() pour tout ce qui est plus complexe que les caractères génériques.