glob
Finds all pathnames matching a shell wildcard pattern and returns them as an array.
glob(string $pattern, int $flags = 0): array|false- Added in PHP 4.3.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$pattern | string | The pattern to match. Supports *, ?, [...] character classes and, with GLOB_BRACE, {a,b} alternation. No tilde or variable expansion is performed. |
$flagsoptional | int= 0 | A bitmask of GLOB_* constants: GLOB_MARK, GLOB_NOSORT, GLOB_NOCHECK, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ONLYDIR, GLOB_ERR. |
Return value
array|falseAn array of matched files and directories, an empty array if nothing matched, or false on error. Results are sorted alphabetically unless GLOB_NOSORT is used.
Errors
Emits E_WARNING and returns false when the directory cannot be read, for example under an open_basedir restriction.
glob expands a shell-style wildcard pattern into an array of matching paths. It is the shortest way to answer "give me every .log file in this folder" and, unlike scandir, it returns full paths rather than bare names and never includes . or ...
When to reach for it
Use it for cleanup jobs, migration runners, template discovery, and anywhere you would otherwise pair scandir with a preg_grep. Two flags carry most of the weight: GLOB_ONLYDIR restricts results to directories, and GLOB_BRACE enables {jpg,png,gif} alternation.
What trips people up
Hidden files are invisible. A leading dot must be matched literally, so * never returns .env or .gitignore. There is no flag to change this — add a second glob('.*') pass if you need them.
Recursion is not supported. * does not cross directory separators, so src/*.php only looks one level deep. Use RecursiveDirectoryIterator or an explicit src/*/*.php for deeper searches.
The result is not sorted the way you expect. Sorting is byte-order alphabetical, so file10.txt comes before file2.txt. Apply natsort afterwards.
Finally, GLOB_BRACE is not available on every platform, and the return value can be false, so never pass the result straight into foreach without checking.
Example
When to use it
- Delete every *.tmp file left in a cache directory by a failed job.
- Collect all numbered SQL migration files in order before running them.
- List only the subdirectories of a plugins folder with GLOB_ONLYDIR.
Frequently asked questions
Why does glob not find my hidden or dotfiles?
The * wildcard does not match a leading dot, matching shell behaviour, and there is no flag to override it. Run a second pass with a pattern like glob('.[!.]*') and merge the results.
Can glob search subdirectories recursively?
No — wildcards do not cross directory separators, so a pattern only searches the level it names. Use RecursiveDirectoryIterator with RecursiveIteratorIterator, or write out explicit levels like dir/*/*.php.
What is the difference between glob and scandir?
scandir returns every entry name in a directory including . and .., while glob returns full paths filtered by a pattern and can restrict to directories with GLOB_ONLYDIR. Use glob when you have a pattern, scandir when you want everything.
More examples
Directories only, and marking them
GLOB_ONLYDIR drops readme.txt and returns just the two directories. GLOB_MARK returns everything but appends a trailing slash to directories, which is handy when you want to tell the two apart in one pass without an is_dir() call per entry.
<?php
mkdir("plugins");
mkdir("plugins/auth");
mkdir("plugins/cache");
file_put_contents("plugins/readme.txt", "hi");
print_r(glob("plugins/*", GLOB_ONLYDIR));
print_r(glob("plugins/*", GLOB_MARK));
unlink("plugins/readme.txt");
rmdir("plugins/auth");
rmdir("plugins/cache");
rmdir("plugins");Sorting numbered files naturally
The default order is 10, 1, 2, 20 because the comparison is byte by byte and '1' sorts before '2'. natsort fixes it to 1, 2, 10, 20 — essential when the filenames are a migration or page sequence.
<?php
mkdir("migrations");
foreach ([1, 2, 10, 20] as $n) {
file_put_contents("migrations/{$n}_step.sql", "-- $n");
}
$files = glob("migrations/*.sql");
echo "default: ", implode(', ', array_map('basename', $files)), "\n";
natsort($files);
echo "natsort: ", implode(', ', array_map('basename', $files)), "\n";
array_map("unlink", $files);
rmdir("migrations");Dotfiles need their own pattern
glob("conf/*") finds only app.ini. The second pattern .[!.]* matches names that start with a dot but are not . or .., so merging the two arrays gives the complete listing. Forgetting this is how cleanup scripts leave .env files behind.
<?php
mkdir("conf");
file_put_contents("conf/app.ini", "a=1");
file_put_contents("conf/.env", "KEY=1");
echo "visible: ", count(glob("conf/*")), "\n";
$all = array_merge(glob("conf/*"), glob("conf/.[!.]*"));
print_r(array_map('basename', $all));
array_map("unlink", $all);
rmdir("conf");
Discussion