fnmatch()
A função fnmatch() do PHP verifica se uma string corresponde a um padrão de curinga de shell, sendo usada para filtrar nomes de ficheiros.
O que é a Função fnmatch()?
A função fnmatch() verifica se uma string corresponde a um padrão de curinga de shell — o mesmo tipo de padrão que se escreve num terminal, como *.txt ou image-?.png. Ela retorna um boolean, por isso é usada com mais frequência para filtrar nomes de ficheiros ou outras strings sem precisar de escrever uma expressão regular completa.
Apesar do nome, fnmatch() nunca acede ao sistema de ficheiros. Ela apenas compara o padrão com a string fornecida, portanto funciona com qualquer texto, não apenas ficheiros reais.
Esta página aborda a assinatura da função, os caracteres curinga que ela reconhece, as flags opcionais e os casos práticos em que ela supera tanto glob() como as expressões regulares.
Sintaxe
fnmatch(string $pattern, string $filename, int $flags = 0): bool$pattern— o padrão de curinga de shell a ser verificado.$filename— a string a ser testada (não precisa de ser um ficheiro real).$flags— flags de bit opcionais que alteram o comportamento da correspondência (ver Flags).
A função retorna true quando $filename corresponde a $pattern, e false caso contrário.
Exemplo Básico
Aqui myfile.txt corresponde a *.txt, portanto o primeiro ramo é executado e imprime The string matches the pattern!. Substitua a string por myfile.csv e a correspondência falha.
Caracteres Curinga
fnmatch() reconhece os curingas padrão de shell. Saber exatamente o que cada um faz é fundamental para usar a função corretamente:
| Curinga | Significado | Padrão de exemplo | Corresponde | Não corresponde |
|---|---|---|---|---|
* | Qualquer sequência de caracteres (incluindo nenhum) | *.log | error.log, .log | error.txt |
? | Exatamente um caractere | file?.txt | file1.txt | file12.txt |
[...] | Um caractere do conjunto | image.[jp]ng | image.jng, image.png | image.gng |
[!...] | Um caractere não presente no conjunto | [!0-9]* | abc | 1abc |
O exemplo a seguir percorre cada curinga para que os possa ver lado a lado:
<?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
O terceiro argumento aceita uma ou mais das seguintes constantes, combinadas com o operador OR bit a bit (|):
| Flag | Efeito |
|---|---|
FNM_NOESCAPE | Trata uma barra invertida (\) literalmente em vez de como caractere de escape. |
FNM_PATHNAME | Uma barra (/) na string deve ser correspondida por um / literal — * e ? não a corresponderão. |
FNM_PERIOD | Um ponto inicial na string deve ser correspondido explicitamente; * e ? não o corresponderão. |
FNM_CASEFOLD | Correspondência sem distinção de maiúsculas e minúsculas. |
FNM_CASEFOLD é a flag que será usada com mais frequência:
<?php
var_dump(fnmatch("*.PNG", "photo.png")); // bool(false) — case differs
var_dump(fnmatch("*.PNG", "photo.png", FNM_CASEFOLD)); // bool(true) — case ignoredCom FNM_PATHNAME, o curinga * para nos separadores de diretório, o que é útil ao fazer correspondência de caminhos completos:
<?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 "/"Um Caso de Uso Prático: Filtrar uma Lista de Ficheiros
Uma tarefa comum é manter apenas as entradas que correspondem a um padrão. Como fnmatch() funciona com strings simples, combina naturalmente com 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));Isto imprime:
Array
(
[0] => notes.txt
[1] => draft.txt
)fnmatch() vs. glob() vs. Expressões Regulares
Estas três ferramentas se sobrepõem, portanto escolher a certa é importante:
- Use
glob()quando quiser ler ficheiros reais do disco que correspondam a um padrão. Ela acede ao sistema de ficheiros e retorna os caminhos correspondentes. - Use
fnmatch()quando já tiver strings (nomes de ficheiros, chaves, etiquetas) em memória e precisar apenas de uma verificação verdadeiro/falso em relação a um padrão de curinga. - Use
preg_match()quando precisar de toda a potência das expressões regulares — grupos de captura, alternância, quantificadores — que curingas simples não conseguem expressar.
Armadilhas
- Não é o sistema de ficheiros.
fnmatch()não verifica se um ficheiro existe; apenas compara strings. Para acesso ao disco, useglob(). - Disponibilidade. Em versões do Windows anteriores ao PHP 7.2,
fnmatch()pode estar indisponível. Envolva as chamadas emfunction_exists('fnmatch')se precisar de suportar esses ambientes. - Os padrões não são regex.
*significa "quaisquer caracteres", não "zero ou mais do token anterior". Se escrevera+esperando um quantificador de regex, será tratado como os dois caracteres literaisae+. - Ficheiros ocultos. Por padrão,
*corresponde a um ponto inicial, portanto*corresponde a.gitignore. AdicioneFNM_PERIODse quiser ignorar dotfiles como faz um shell.
Conclusão
fnmatch() é a forma mais simples de testar uma string em relação a um padrão de curinga no estilo de shell em PHP. Recorra a ela quando precisar de filtragem de nomes de ficheiros rápida e legível sem o custo de uma expressão regular — e lembre-se dos seus companheiros glob() para ler ficheiros do disco e preg_match() para qualquer coisa mais complexa que curingas.