Эффективная организация поиска файлов в PHP проектах

Раздел: Управление файлами в PHP -> Поиск и список файлов

Поиск файлов с помощью RecursiveDirectoryIterator

Наиболее эффективный способ рекурсивного поиска файлов в PHP - использование классов RecursiveDirectoryIterator и RecursiveIteratorIterator. Этот подход не загружает память списком всех файлов сразу, позволяет фильтровать результаты и обрабатывать большие каталоги.


$iterator = new RecursiveDirectoryIterator('/путь/к/каталогу');
$filter = new RecursiveCallbackFilterIterator($iterator, function($current, $key, $iterator) {
    // Пропускаем точки и скрытые файлы
    if ($current->getFilename()[0] === '.') return false;
    return $current->isFile() || $current->isDir();
});
$files = new RecursiveIteratorIterator($filter, RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $fileinfo) {
    if ($fileinfo->isFile()) {
        echo $fileinfo->getPathname() . PHP_EOL;
    }
}
  

Php file find (поиск файлов в php)

Пояснение шагов:

  1. Создаётся объект RecursiveDirectoryIterator для начального каталога.
  2. С помощью RecursiveCallbackFilterIterator исключаются скрытые файлы.
  3. Обход выполняется через RecursiveIteratorIterator в режиме SELF_FIRST (сначала директории, потом файлы).
  4. В цикле проверяется, является ли текущий элемент файлом, и выводится полный путь.

Типичные ошибки:

  • Ошибка доступа к каталогу: если нет прав на чтение, вызывается исключение UnexpectedValueException. Решение - оборачивать код в try-catch.
  • Бесконечный обход символических ссылок: можно добавить $iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS | RecursiveDirectoryIterator::FOLLOW_SYMLINKS) и проверять isLink().
  • Слишком глубокие каталоги вызывают переполнение памяти - используйте setMaxDepth() для ограничения глубины.

Как выполнить поиск по маске имени с помощью glob?

Функция glob() возвращает массив файлов и каталогов, соответствующих шаблону, используя синтаксис, похожий на регулярные выражения (но не RegExp). Подходит для простых запросов без рекурсии.


$files = glob('/var/www/*.txt');
foreach ($files as $file) {
    echo basename($file) . PHP_EOL;
}
  

Цель: быстрый поиск файлов по одному расширению в одной директории.

Проблема: glob() не обходит подкаталоги. Для рекурсии требуется дополнительно обрабатывать папки или использовать GLOB_BRACE с ограниченными возможностями.

Решение - написать рекурсивную обёртку или комбинировать со scandir().

Как получить список всех файлов с помощью scandir и ручной рекурсии?

scandir() возвращает массив имён в каталоге. Для рекурсивного обхода пишется собственная функция.


function scanRecursive($dir, &$results = []) {
    $files = scandir($dir);
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            scanRecursive($path, $results);
        } else {
            $results[] = $path;
        }
    }
    return $results;
}
$allFiles = scanRecursive('/home/project');
  

Цель: полный контроль над процессом, возможность добавления логики фильтрации.

Ошибки: рекурсивные вызовы могут превысить лимит памяти при глубокой вложенности. Рекомендуется ограничивать глубину параметром $depth.

Как найти файлы по нескольким расширениям одновременно?

Применение glob() с флагом GLOB_BRACE:


$files = glob('/path/*.{php,inc,txt}', GLOB_BRACE);
  

Внимание: флаг GLOB_BRACE доступен не во всех системах (не работает на некоторых платформах). Альтернатива - ручная проверка расширения в цикле.

Расширенные примеры поиска файлов

Пример 1. Рекурсивный поиск с ограничением глубины и фильтрацией по дате модификации.

Пример

$iterator = new RecursiveDirectoryIterator('/data');
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$filterDate = new RecursiveCallbackFilterIterator($iterator, function($current) {
    // Оставляем только файлы, изменённые за последние 7 дней
    return $current->isFile() && time() - $current->getMTime() < 7 * 86400;
});
$limited = new RecursiveIteratorIterator($filterDate);
$limited->setMaxDepth(3); // глубина не более 3 уровней
foreach ($limited as $file) {
    echo $file->getPathname() . ' | ' . date('Y-m-d', $file->getMTime()) . PHP_EOL;
}
/data/logs/2025/03/error.log | 2025-03-10
/data/docs/report.pdf | 2025-03-12

Пример 2. Использование FilesystemIterator для простого обхода без рекурсии.

Пример

$iterator = new FilesystemIterator('/home/user/images');
foreach ($iterator as $file) {
    if ($file->isFile() && $file->getExtension() === 'jpg') {
        echo $file->getBasename() . ' - ' . $file->getSize() . ' байт' . PHP_EOL;
    }
}
photo1.jpg - 245000 байт
photo2.jpg - 180000 байт

Пример 3. Рекурсивный поиск через glob с помощью самописной функции.

Пример

function globRecursive($pattern, $flags = 0) {
    $files = glob($pattern, $flags);
    foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $subdir) {
        $files = array_merge($files, globRecursive($subdir . '/' . basename($pattern), $flags));
    }
    return $files;
}
$allConfigs = globRecursive('/etc/**/*.conf');
print_r($allConfigs);
Array
(
    [0] => /etc/apache2/apache2.conf
    [1] => /etc/nginx/nginx.conf
    [2] => /etc/php/8.1/cli/php.ini
)

Пример 4. Поиск с исключением определённых каталогов (например, .git).

Пример

$dir = '/project';
$iterator = new RecursiveDirectoryIterator($dir);
$filter = new RecursiveCallbackFilterIterator($iterator, function($current, $key, $iterator) {
    if (in_array($current->getBasename(), ['.git', 'node_modules', 'vendor'])) {
        return false; // пропускаем эти директории
    }
    return $current->isFile();
});
$files = new RecursiveIteratorIterator($filter);
foreach ($files as $file) {
    echo $file->getPathname() . PHP_EOL;
}
/project/src/App.php
/project/tests/UnitTest.php
/project/public/index.php

Поиск файлов в PHP - comments

En
Php file find (php)