fnmatch()
Die Funktion fnmatch() in PHP prüft, ob ein string einem Shell-Wildcard-Muster entspricht. Ideal zum Filtern von Dateinamen ohne reguläre Ausdrücke.
Was ist die fnmatch()-Funktion?
Die Funktion fnmatch() prüft, ob ein string einem Shell-Wildcard-Muster entspricht — genau der Art von Muster, die man in einem Terminal eingibt, wie *.txt oder image-?.png. Sie gibt einen boolean-Wert zurück und wird daher am häufigsten verwendet, um Dateinamen oder andere Zeichenketten zu filtern, ohne einen vollständigen regulären Ausdruck schreiben zu müssen.
Trotz des Namens greift fnmatch() niemals auf das Dateisystem zu. Sie vergleicht das Muster lediglich mit dem übergebenen string, funktioniert also mit beliebigem Text — nicht nur mit echten Dateien.
Diese Seite behandelt die Signatur der Funktion, die unterstützten Wildcard-Zeichen, die optionalen Flags sowie die praktischen Einsatzfälle, in denen sie sowohl glob() als auch regulären Ausdrücken überlegen ist.
Syntax
fnmatch(string $pattern, string $filename, int $flags = 0): bool$pattern— das Shell-Wildcard-Muster, gegen das geprüft wird.$filename— der zu testende string (muss keine echte Datei sein).$flags— optionale Bit-Flags, die das Matching-Verhalten ändern (siehe Flags).
Die Funktion gibt true zurück, wenn $filename mit $pattern übereinstimmt, andernfalls false.
Einfaches Beispiel
Hier stimmt myfile.txt mit *.txt überein, sodass der erste Zweig ausgeführt wird und The string matches the pattern! ausgegeben wird. Ändert man den string zu myfile.csv, schlägt die Übereinstimmung fehl.
Wildcard-Zeichen
fnmatch() versteht die standardmäßigen Shell-Wildcards. Zu wissen, was jedes Zeichen genau bedeutet, ist der Schlüssel zur korrekten Verwendung der Funktion:
| Wildcard | Bedeutung | Beispielmuster | Trifft zu | Trifft nicht zu |
|---|---|---|---|---|
* | Beliebige Zeichenfolge (auch leer) | *.log | error.log, .log | error.txt |
? | Genau ein Zeichen | file?.txt | file1.txt | file12.txt |
[...] | Ein Zeichen aus der Menge | image.[jp]ng | image.jng, image.png | image.gng |
[!...] | Ein Zeichen nicht in der Menge | [!0-9]* | abc | 1abc |
Das folgende Beispiel zeigt jeden Wildcard-Typ nebeneinander:
<?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
Das dritte Argument akzeptiert eine oder mehrere der folgenden Konstanten, die mit dem bitweisen OR-Operator (|) kombiniert werden können:
| Flag | Wirkung |
|---|---|
FNM_NOESCAPE | Behandelt einen Backslash (\) als wörtliches Zeichen statt als Escape-Zeichen. |
FNM_PATHNAME | Ein Schrägstrich (/) im string muss durch ein wörtliches / abgeglichen werden — * und ? stimmen nicht damit überein. |
FNM_PERIOD | Ein führender Punkt im string muss explizit abgeglichen werden; * und ? stimmen nicht damit überein. |
FNM_CASEFOLD | Groß-/Kleinschreibung wird beim Abgleich ignoriert. |
FNM_CASEFOLD ist das Flag, das man am häufigsten benötigt:
<?php
var_dump(fnmatch("*.PNG", "photo.png")); // bool(false) — case differs
var_dump(fnmatch("*.PNG", "photo.png", FNM_CASEFOLD)); // bool(true) — case ignoredMit FNM_PATHNAME stoppt der Wildcard * an Verzeichnistrennzeichen, was beim Abgleichen ganzer Pfade nützlich ist:
<?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 "/"Ein praktischer Anwendungsfall: Eine Dateiliste filtern
Eine häufige Aufgabe besteht darin, nur die Einträge zu behalten, die einem Muster entsprechen. Da fnmatch() mit einfachen Zeichenketten arbeitet, lässt es sich gut mit array_filter() kombinieren:
<?php
$files = ["report.pdf", "notes.txt", "draft.txt", "image.png"];
$textFiles = array_filter($files, fn($file) => fnmatch("*.txt", $file));
print_r(array_values($textFiles));Dies gibt aus:
Array
(
[0] => notes.txt
[1] => draft.txt
)fnmatch() vs. glob() vs. Reguläre Ausdrücke
Diese drei Werkzeuge überschneiden sich, daher ist die richtige Wahl entscheidend:
- Verwende
glob(), wenn du echte Dateien von der Festplatte lesen möchtest, die einem Muster entsprechen. Sie greift auf das Dateisystem zu und gibt die passenden Pfade zurück. - Verwende
fnmatch(), wenn du bereits Zeichenketten (Dateinamen, Schlüssel, Labels) im Speicher hast und nur eine true/false-Prüfung gegen ein Wildcard-Muster benötigst. - Verwende
preg_match(), wenn du die volle Leistungsfähigkeit regulärer Ausdrücke benötigst — Capture-Gruppen, Alternativen, Quantoren —, die einfache Wildcards nicht ausdrücken können.
Häufige Fallstricke
- Kein Dateisystemzugriff.
fnmatch()prüft nicht, ob eine Datei existiert; sie vergleicht nur Zeichenketten. Für den Festplattenzugriff verwendeglob(). - Verfügbarkeit. Bei Windows-Builds vor PHP 7.2 kann
fnmatch()nicht verfügbar sein. Umhülle Aufrufe mitfunction_exists('fnmatch'), wenn du diese Umgebungen unterstützen musst. - Muster sind keine regulären Ausdrücke.
*bedeutet „beliebige Zeichen", nicht „null oder mehr des vorherigen Tokens". Wera+schreibt und einen Regex-Quantor erwartet, erhält stattdessen die zwei wörtlichen Zeichenaund+. - Versteckte Dateien. Standardmäßig stimmt
*mit einem führenden Punkt überein, sodass*auch.gitignoretrifft. FügeFNM_PERIODhinzu, wenn du Dotfiles so überspringen möchtest wie eine Shell.
Fazit
fnmatch() ist der einfachste Weg, in PHP einen string gegen ein Shell-artiges Wildcard-Muster zu testen. Greife darauf zurück, wenn du schnelles, lesbares Dateiname-Filtern ohne den Aufwand eines regulären Ausdrucks benötigst — und denke an ihre Begleiter glob() zum Lesen von Dateien von der Festplatte und preg_match() für alles, was komplexer als Wildcards ist.