fnmatch()
La función fnmatch() de PHP compara cadenas con patrones de comodín de shell, útil para filtrar nombres de archivo sin usar expresiones regulares.
¿Qué es la función fnmatch()?
La función fnmatch() comprueba si una cadena coincide con un patrón de comodín de shell — el mismo tipo de patrón que se escribe en una terminal, como *.txt o image-?.png. Devuelve un boolean, por lo que se usa principalmente para filtrar nombres de archivo u otras cadenas sin necesidad de escribir una expresión regular completa.
A pesar del nombre, fnmatch() nunca accede al sistema de archivos. Solo compara el patrón con la cadena que se le pasa, por lo que funciona con cualquier texto, no solo con archivos reales.
Esta página cubre la firma de la función, los caracteres comodín que reconoce, los flags opcionales y los casos prácticos en los que supera tanto a glob() como a las expresiones regulares.
Sintaxis
fnmatch(string $pattern, string $filename, int $flags = 0): bool$pattern— el patrón de comodín de shell contra el que se compara.$filename— la cadena que se evalúa (no tiene que ser un archivo real).$flags— flags de bits opcionales que cambian el comportamiento de la comparación (ver Flags).
La función devuelve true cuando $filename coincide con $pattern, y false en caso contrario.
Ejemplo básico
Aquí myfile.txt coincide con *.txt, por lo que se ejecuta la primera rama y se imprime The string matches the pattern!. Si se cambia la cadena a myfile.csv, la comparación falla.
Caracteres comodín
fnmatch() reconoce los comodines estándar de shell. Saber exactamente qué hace cada uno es clave para usar la función correctamente:
| Comodín | Significado | Patrón de ejemplo | Coincide | No coincide |
|---|---|---|---|---|
* | Cualquier secuencia de caracteres (incluida ninguna) | *.log | error.log, .log | error.txt |
? | Exactamente un carácter | file?.txt | file1.txt | file12.txt |
[...] | Un carácter del conjunto | image.[jp]ng | image.jng, image.png | image.gng |
[!...] | Un carácter que no esté en el conjunto | [!0-9]* | abc | 1abc |
El siguiente ejemplo recorre cada comodín para que puedas verlos uno al lado del otro:
<?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
El tercer argumento acepta una o más de las siguientes constantes, combinadas con el operador OR bit a bit (|):
| Flag | Efecto |
|---|---|
FNM_NOESCAPE | Trata la barra invertida (\) de forma literal en lugar de como carácter de escape. |
FNM_PATHNAME | Una barra (/) en la cadena debe coincidir con una / literal — * y ? no la coincidirán. |
FNM_PERIOD | Un punto inicial en la cadena debe coincidir de forma explícita; * y ? no lo harán. |
FNM_CASEFOLD | Compara sin distinguir mayúsculas de minúsculas. |
FNM_CASEFOLD es el flag al que se recurrirá con mayor frecuencia:
<?php
var_dump(fnmatch("*.PNG", "photo.png")); // bool(false) — case differs
var_dump(fnmatch("*.PNG", "photo.png", FNM_CASEFOLD)); // bool(true) — case ignoredCon FNM_PATHNAME, el comodín * se detiene en los separadores de directorio, lo que resulta útil al comparar rutas completas:
<?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 "/"Un caso de uso práctico: filtrar una lista de archivos
Una tarea habitual es conservar solo los elementos que coinciden con un patrón. Como fnmatch() trabaja con cadenas simples, se combina de forma natural con 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));Esto imprime:
Array
(
[0] => notes.txt
[1] => draft.txt
)fnmatch() vs. glob() vs. expresiones regulares
Estas tres herramientas se solapan, por lo que elegir la correcta es importante:
- Usa
glob()cuando quieras leer archivos reales del disco que coincidan con un patrón. Accede al sistema de archivos y devuelve las rutas coincidentes. - Usa
fnmatch()cuando ya tengas cadenas (nombres de archivo, claves, etiquetas) en memoria y solo necesites una comprobación verdadero/falso contra un patrón de comodín. - Usa
preg_match()cuando necesites el poder completo de las expresiones regulares — grupos de captura, alternancia, cuantificadores — que los comodines simples no pueden expresar.
Advertencias
- No accede al sistema de archivos.
fnmatch()no verifica que un archivo exista; solo compara cadenas. Para acceder al disco usaglob(). - Disponibilidad. En versiones de Windows anteriores a PHP 7.2,
fnmatch()puede no estar disponible. Envuelve las llamadas enfunction_exists('fnmatch')si debes dar soporte a esos entornos. - Los patrones no son expresiones regulares.
*significa "cualquier carácter", no "cero o más del token anterior". Si escribesa+esperando un cuantificador de expresión regular, se trata como los dos caracteres literalesay+. - Archivos ocultos. Por defecto
*coincide con un punto inicial, por lo que*coincide con.gitignore. AñadeFNM_PERIODsi deseas omitir los dotfiles como lo hace una shell.
Conclusión
fnmatch() es la forma más sencilla de probar una cadena contra un patrón de comodín estilo shell en PHP. Recurre a ella cuando necesites un filtrado de nombres de archivo rápido y legible sin la complejidad de una expresión regular — y recuerda a sus compañeras glob() para leer archivos del disco y preg_match() para cualquier cosa más compleja que los comodines.