fnmatch()
The fnmatch() function is a built-in PHP function that performs a filename matching using a shell wildcard pattern. This function is used to match filenames
What is the fnmatch() Function?
The fnmatch() function checks whether a string matches a shell wildcard pattern — the same kind of pattern you type in a terminal, such as *.txt or image-?.png. It returns a boolean, so it is most often used to filter filenames or other strings without writing a full regular expression.
Despite the name, fnmatch() never touches the filesystem. It only compares the pattern against the string you pass in, so it works on any text, not just real files.
This page covers the function's signature, the wildcard characters it understands, the optional flags, and the practical cases where it beats both glob() and regular expressions.
Syntax
fnmatch(string $pattern, string $filename, int $flags = 0): bool$pattern— the shell wildcard pattern to match against.$filename— the string being tested (it does not have to be a real file).$flags— optional bit flags that change matching behavior (see Flags).
The function returns true when $filename matches $pattern, and false otherwise.
Basic Example
Here myfile.txt matches *.txt, so the first branch runs and prints The string matches the pattern!. Swap the string to myfile.csv and the match fails.
Wildcard Characters
fnmatch() understands the standard shell wildcards. Knowing exactly what each one does is the key to using the function correctly:
| Wildcard | Meaning | Example pattern | Matches | Does not match |
|---|---|---|---|---|
* | Any sequence of characters (including none) | *.log | error.log, .log | error.txt |
? | Exactly one character | file?.txt | file1.txt | file12.txt |
[...] | One character from the set | image.[jp]ng | image.jng, image.png | image.gng |
[!...] | One character not in the set | [!0-9]* | abc | 1abc |
The following example walks through each wildcard so you can see them side by side:
<?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
The third argument accepts one or more of the following constants, combined with the bitwise OR operator (|):
| Flag | Effect |
|---|---|
FNM_NOESCAPE | Treat a backslash (\) literally instead of as an escape character. |
FNM_PATHNAME | A slash (/) in the string must be matched by a literal / — * and ? will not match it. |
FNM_PERIOD | A leading period in the string must be matched explicitly; * and ? will not match it. |
FNM_CASEFOLD | Match case-insensitively. |
FNM_CASEFOLD is the flag you will reach for most often:
<?php
var_dump(fnmatch("*.PNG", "photo.png")); // bool(false) — case differs
var_dump(fnmatch("*.PNG", "photo.png", FNM_CASEFOLD)); // bool(true) — case ignoredWith FNM_PATHNAME, the * wildcard stops at directory separators, which is handy when matching whole paths:
<?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 "/"A Practical Use Case: Filtering a List of Files
A common task is keeping only the entries that match a pattern. Because fnmatch() works on plain strings, it pairs naturally with 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));This prints:
Array
(
[0] => notes.txt
[1] => draft.txt
)fnmatch() vs. glob() vs. Regular Expressions
These three tools overlap, so choosing the right one matters:
- Use
glob()when you want to read actual files from disk that match a pattern. It hits the filesystem and returns the matching paths. - Use
fnmatch()when you already have strings (filenames, keys, labels) in memory and only need a true/false check against a wildcard pattern. - Use
preg_match()when you need the full power of regular expressions — capture groups, alternation, quantifiers — that simple wildcards cannot express.
Gotchas
- It is not the filesystem.
fnmatch()does not verify that a file exists; it only compares strings. For disk access useglob(). - Availability. On Windows builds before PHP 7.2,
fnmatch()may be unavailable. Wrap calls infunction_exists('fnmatch')if you must support those environments. - Patterns are not regex.
*means "any characters," not "zero or more of the previous token." If you writea+expecting a regex quantifier, it is treated as the two literal charactersaand+. - Hidden files. By default
*matches a leading dot, so*matches.gitignore. AddFNM_PERIODif you want to skip dotfiles the way a shell does.
Conclusion
fnmatch() is the simplest way to test a string against a shell-style wildcard pattern in PHP. Reach for it when you need quick, readable filename filtering without the overhead of a regular expression — and remember its companions glob() for reading files from disk and preg_match() for anything more complex than wildcards.