PHP glob()函数

glob()函数用于根据指定的模式匹配文件路径,返回匹配的文件和目录数组。它支持类似shell的通配符模式匹配。

语法

array|false glob ( string $pattern [, int $flags = 0 ] )

参数说明

参数 描述
pattern 匹配模式,支持shell通配符:* ? []
flags 可选标志位,控制函数行为(详见下表)

标志位(flags)详解

常量 描述
GLOB_MARK 1 在每个返回的项目中加一个斜线(目录标记)
GLOB_NOSORT 2 按照目录中出现的顺序返回(不排序)
GLOB_NOCHECK 4 如果没有匹配的文件,返回模式本身
GLOB_NOESCAPE 8 反斜线不转义元字符
GLOB_BRACE 16 扩展 {a,b,c} 来匹配 'a'、'b' 或 'c'
GLOB_ONLYDIR 32 仅返回匹配模式的目录项
GLOB_ERR 64 在读取错误时停止(如目录不可读),默认情况下忽略错误

通配符规则

通配符 描述 示例 匹配结果
* 匹配任意数量的任意字符(包括零个字符) *.php index.php, test.php, .php
? 匹配任意单个字符 file?.txt file1.txt, fileA.txt, file_.txt
[] 匹配方括号中的任意一个字符 file[0-9].txt file0.txt, file1.txt, file9.txt
{} 扩展匹配(需要GLOB_BRACE标志) file.{txt,php} file.txt, file.php
** 递归匹配(PHP 5.3+) dir/**/*.php dir/a.php, dir/sub/b.php

示例代码

示例1:基本文件匹配

<?php
// 创建测试文件
touch('test1.php');
touch('test2.php');
touch('image1.jpg');
touch('image2.png');
mkdir('subdir');
touch('subdir/test3.php');

// 基本匹配示例
echo "<h5>1. 匹配所有PHP文件:</h5>";
$phpFiles = glob('*.php');
echo "<pre>" . print_r($phpFiles, true) . "</pre>";

echo "<h5>2. 匹配特定模式的文件:</h5>";
$imageFiles = glob('image*.{jpg,png,gif}', GLOB_BRACE);
echo "<pre>" . print_r($imageFiles, true) . "</pre>";

echo "<h5>3. 匹配单个字符:</h5>";
$testFiles = glob('test?.php');
echo "<pre>" . print_r($testFiles, true) . "</pre>";

echo "<h5>4. 匹配目录(使用GLOB_ONLYDIR):</h5>";
$directories = glob('*', GLOB_ONLYDIR);
echo "<pre>" . print_r($directories, true) . "</pre>";

// 清理测试文件
unlink('test1.php');
unlink('test2.php');
unlink('image1.jpg');
unlink('image2.png');
unlink('subdir/test3.php');
rmdir('subdir');
?>

示例2:递归文件搜索

<?php
// 递归搜索函数(PHP 5.3+支持 ** 通配符)
function recursiveGlob($pattern, $flags = 0) {
    // 使用 ** 进行递归匹配(需要 PHP 5.3+)
    if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
        $files = glob($pattern, $flags);
        return $files !== false ? $files : [];
    }

    // PHP 5.3以下的替代方案
    $files = [];
    $parts = explode('/', $pattern);
    $dir = $parts[0];

    if ($dir === '**') {
        // 递归搜索所有子目录
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator('.'),
            RecursiveIteratorIterator::SELF_FIRST
        );

        $pattern = implode('/', array_slice($parts, 1));
        foreach ($iterator as $file) {
            if (fnmatch($pattern, $file->getPathname())) {
                $files[] = $file->getPathname();
            }
        }
    } else {
        $files = glob($pattern, $flags);
    }

    return $files !== false ? $files : [];
}

// 使用示例
echo "<h5>递归搜索所有PHP文件(包括子目录):</h5>";

// 创建测试目录结构
@mkdir('project');
@mkdir('project/src');
@mkdir('project/tests');
touch('project/index.php');
touch('project/src/utils.php');
touch('project/tests/test.php');

// PHP 5.3+ 方式
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
    $allPhpFiles = recursiveGlob('project/**/*.php');
    echo "<pre>" . print_r($allPhpFiles, true) . "</pre>";
} else {
    echo "需要 PHP 5.3+ 支持 ** 递归通配符<br>";
    $allPhpFiles = recursiveGlob('**/*.php');
    echo "<pre>" . print_r($allPhpFiles, true) . "</pre>";
}

// 清理
unlink('project/index.php');
unlink('project/src/utils.php');
unlink('project/tests/test.php');
rmdir('project/src');
rmdir('project/tests');
rmdir('project');
?>

示例3:高级文件搜索类

<?php
class AdvancedFileSearcher {
    private $rootPath;
    private $patterns = [];
    private $excludePatterns = [];
    private $flags = 0;

    public function __construct($rootPath = '.') {
        $this->rootPath = rtrim($rootPath, '/\\');
    }

    /**
     * 添加搜索模式
     */
    public function addPattern($pattern) {
        $this->patterns[] = $pattern;
        return $this;
    }

    /**
     * 添加排除模式
     */
    public function excludePattern($pattern) {
        $this->excludePatterns[] = $pattern;
        return $this;
    }

    /**
     * 设置标志位
     */
    public function setFlags($flags) {
        $this->flags = $flags;
        return $this;
    }

    /**
     * 执行搜索
     */
    public function search() {
        $results = [];

        foreach ($this->patterns as $pattern) {
            $fullPattern = $this->rootPath . '/' . ltrim($pattern, '/');
            $matches = glob($fullPattern, $this->flags);

            if ($matches !== false) {
                foreach ($matches as $file) {
                    // 检查是否应该排除
                    if (!$this->shouldExclude($file)) {
                        $results[] = $file;
                    }
                }
            }
        }

        // 去重并排序
        $results = array_unique($results);
        if (!($this->flags & GLOB_NOSORT)) {
            sort($results);
        }

        return $results;
    }

    /**
     * 递归搜索(支持子目录)
     */
    public function searchRecursive() {
        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
            throw new Exception("递归搜索需要 PHP 5.3+");
        }

        $results = [];

        foreach ($this->patterns as $pattern) {
            // 将模式转换为递归模式
            $recursivePattern = $this->convertToRecursivePattern($pattern);
            $fullPattern = $this->rootPath . '/' . ltrim($recursivePattern, '/');

            $matches = glob($fullPattern, $this->flags);

            if ($matches !== false) {
                foreach ($matches as $file) {
                    if (!$this->shouldExclude($file)) {
                        $results[] = $file;
                    }
                }
            }
        }

        $results = array_unique($results);
        if (!($this->flags & GLOB_NOSORT)) {
            sort($results);
        }

        return $results;
    }

    /**
     * 转换为递归模式
     */
    private function convertToRecursivePattern($pattern) {
        $dir = dirname($pattern);
        $file = basename($pattern);

        if ($dir === '.') {
            return '**/' . $file;
        }

        return $dir . '/**/' . $file;
    }

    /**
     * 检查是否应该排除文件
     */
    private function shouldExclude($file) {
        foreach ($this->excludePatterns as $pattern) {
            $fullPattern = $this->rootPath . '/' . ltrim($pattern, '/');
            if (fnmatch($fullPattern, $file)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 按文件类型过滤
     */
    public function filterByType($type = 'file') {
        $results = $this->search();
        $filtered = [];

        foreach ($results as $file) {
            if ($type === 'file' && is_file($file)) {
                $filtered[] = $file;
            } elseif ($type === 'dir' && is_dir($file)) {
                $filtered[] = $file;
            }
        }

        return $filtered;
    }
}

// 使用示例
try {
    // 创建测试文件结构
    @mkdir('project');
    @mkdir('project/src');
    @mkdir('project/tests');
    @mkdir('project/tmp');
    touch('project/index.php');
    touch('project/composer.json');
    touch('project/src/Controller.php');
    touch('project/src/Model.php');
    touch('project/tests/TestController.php');
    touch('project/tmp/cache.tmp');

    echo "<h5>高级文件搜索示例:</h5>";

    // 创建搜索器
    $searcher = new AdvancedFileSearcher('project');

    // 搜索所有PHP文件,排除测试目录
    $searcher
        ->addPattern('*.php')
        ->addPattern('src/*.php')
        ->excludePattern('tests/*');

    $phpFiles = $searcher->searchRecursive();
    echo "<h6>所有PHP文件(排除tests目录):</h6>";
    echo "<pre>" . print_r($phpFiles, true) . "</pre>";

    // 搜索所有JSON文件
    $searcher2 = new AdvancedFileSearcher('project');
    $jsonFiles = $searcher2->addPattern('*.json')->search();
    echo "<h6>所有JSON文件:</h6>";
    echo "<pre>" . print_r($jsonFiles, true) . "</pre>";

    // 只搜索目录
    $searcher3 = new AdvancedFileSearcher('project');
    $directories = $searcher3
        ->addPattern('*')
        ->setFlags(GLOB_ONLYDIR)
        ->search();
    echo "<h6>所有子目录:</h6>";
    echo "<pre>" . print_r($directories, true) . "</pre>";

    // 清理
    unlink('project/index.php');
    unlink('project/composer.json');
    unlink('project/src/Controller.php');
    unlink('project/src/Model.php');
    unlink('project/tests/TestController.php');
    unlink('project/tmp/cache.tmp');
    rmdir('project/src');
    rmdir('project/tests');
    rmdir('project/tmp');
    rmdir('project');

} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}
?>

注意事项

重要提示:
  • 性能考虑:glob()在大型目录上可能较慢,考虑使用opendir()readdir()循环
  • 递归搜索:PHP 5.3+ 支持**递归通配符,旧版本需要自己实现递归
  • 符号链接:glob()会解析符号链接,可能返回符号链接指向的文件
  • 隐藏文件:模式*不会匹配以点(.)开头的文件,需要使用.*
  • 大小写敏感:在Unix系统上glob()区分大小写,Windows上不区分
  • 返回顺序:默认按字母顺序排序,使用GLOB_NOSORT保持原始顺序
  • 错误处理:默认忽略读取错误,使用GLOB_ERR在错误时停止
  • 内存使用:返回所有匹配结果,对于大量文件可能消耗较多内存
  • 模式限制:不支持完整的正则表达式,只支持有限的shell通配符

glob() vs scandir()

特性 glob() scandir()
功能 模式匹配文件路径 列出目录中的所有文件和目录
模式支持 支持通配符 * ? [] {} 不支持模式匹配
返回结果 只返回匹配的项目 返回所有项目(包括 . 和 ..)
性能 可能较慢(需要模式匹配) 通常较快(简单列出)
使用场景 搜索特定类型的文件 遍历目录中的所有项目

相关函数

  • scandir() - 列出指定路径中的文件和目录
  • opendir() - 打开目录句柄
  • readdir() - 从目录句柄中读取条目
  • fnmatch() - 用模式匹配文件名
  • is_file() - 判断是否是文件
  • is_dir() - 判断是否是目录
  • RecursiveDirectoryIterator - 递归目录迭代器

典型应用场景

文件类型搜索

搜索特定类型的文件,如所有图片、文档或源代码文件。

项目文件遍历

在项目中查找所有配置文件、模板文件或资源文件。

日志文件分析

查找特定时间段的日志文件进行分析和处理。

批量文件操作

对匹配特定模式的文件执行批量操作,如重命名、删除或处理。