Методы поиска файлов PHP в проекте

Раздел: Программирование на PHP -> Работа с файловой системой

Поиск файлов в PHP: основные подходы

Как наиболее эффективно найти все PHP файлы в директории и её поддиректориях?

Наиболее производительный и гибкий способ - использовать классы SPL: RecursiveDirectoryIterator и RecursiveIteratorIterator. Они позволяют обойти дерево каталогов без рекурсии на уровне пользовательского кода и применить фильтр по расширению.


// Поиск всех файлов .php в директории /var/www/project
$directory = new RecursiveDirectoryIterator('/var/www/project');
$iterator = new RecursiveIteratorIterator($directory);
$phpFiles = [];
foreach ($iterator as $file) {
    if ($file->isFile() && $file->getExtension() === 'php') {
        $phpFiles[] = $file->getPathname();
    }
}
print_r($phpFiles);
  

Пояснение: RecursiveDirectoryIterator создает итератор для обхода директории, RecursiveIteratorIterator делает его плоским (рекурсивным циклом). Метод getExtension() возвращает расширение файла без точки. Проверка isFile() исключает директории.

Возможные проблемы:

  • Недостаточно прав доступа к некоторым директориям - итератор пропустит их без уведомления. Для отлова ошибок используйте блок try-catch.
  • Большое количество файлов может вызвать нехватку памяти, так как все пути сохраняются в массиве. В таких случаях обрабатывайте файлы в цикле без накопления.
  • Символические ссылки могут привести к зацикливанию. По умолчанию RecursiveDirectoryIterator не следует по ссылкам, но можно включить флаг RecursiveDirectoryIterator::FOLLOW_SYMLINKS.

Решение:

Используйте флаги при создании итератора: RecursiveDirectoryIterator::SKIP_DOTS | RecursiveDirectoryIterator::FOLLOW_SYMLINKS. Для контроля памяти обрабатывайте файлы внутри цикла.

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

Как найти файлы по простому шаблону без рекурсии?

Для поиска в одной директории по маске имени удобна функция glob(). Она поддерживает шаблоны оболочки Unix.


// Найти все .txt файлы в текущей папке
$txtFiles = glob('*.txt');
print_r($txtFiles);
  

Пояснение: glob возвращает массив путей, соответствующих шаблону. По умолчанию ищет только в указанной директории (без рекурсии).

Типичная ошибка: забыть, что glob не видит файлы в подпапках. Для рекурсивного поиска нужно использовать опцию GLOB_BRACE? Нет, она не добавляет рекурсию. Рекурсию можно организовать вручную через цикл или комбинировать с glob('**/*.php') (требуется PHP 5.3+ и поддержка glob с двумя звездочками, но работает не во всех системах).

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

Как получить список файлов с дополнительной информацией (размер, дата)?

Функция scandir() возвращает массив имен файлов, но не даёт информацию о них. Для получения свойств нужно вызывать дополнительные функции. Более удобный вариант - DirectoryIterator.


$dir = new DirectoryIterator('/path/to/files');
foreach ($dir as $fileInfo) {
    if ($fileInfo->isFile()) {
        echo $fileInfo->getFilename() . ' - ' . $fileInfo->getSize() . ' bytes';
    }
}
  

Пояснение: DirectoryIterator предоставляет методы для получения имени, размера, времени изменения, прав доступа и других атрибутов.

Проблема: если в директории нет файлов, цикл не выполнится. Итератор по умолчанию включает элементы '.' и '..', их нужно отфильтровывать через $fileInfo->isDot().

Как найти файлы по содержимому (например, строке)?

Комбинируем обход файлов с проверкой содержимого через file_get_contents() или потоковое чтение.


$searchTerm = 'function getUser';
$directory = new RecursiveDirectoryIterator('/src');
$iterator = new RecursiveIteratorIterator($directory);
$foundFiles = [];
foreach ($iterator as $file) {
    if ($file->isFile() && $file->getExtension() === 'php') {
        $content = file_get_contents($file->getPathname());
        if (strpos($content, $searchTerm) !== false) {
            $foundFiles[] = $file->getPathname();
        }
    }
}
print_r($foundFiles);
  

Пояснение: Для больших файлов лучше читать построчно, чтобы не тратить память.

Ошибка: использование file_get_contents() для файлов гигабайтного размера может исчерпать память. Альтернатива: открывать файл через fopen() и читать блоками.

Как найти файлы с использованием регулярного выражения в имени?

Функция glob() не поддерживает полноценные регулярные выражения. Для этого используйте DirectoryIterator или RecursiveDirectoryIterator в сочетании с preg_match().


$pattern = '/^config_.*\.json$/';
$dir = new DirectoryIterator('/etc');
$configFiles = [];
foreach ($dir as $file) {
    if ($file->isFile() && preg_match($pattern, $file->getFilename())) {
        $configFiles[] = $file->getPathname();
    }
}
print_r($configFiles);
  

Пояснение: PHP итераторы дают полный контроль над фильтрацией.

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

Ниже приведены более сложные сценарии поиска, которые могут потребоваться в реальных проектах.

Пример 1: Рекурсивный поиск с фильтром по нескольким расширениям

Пример

$extensions = ['php', 'inc', 'phtml'];
$directory = new RecursiveDirectoryIterator('/var/www');
$iterator = new RecursiveIteratorIterator($directory);
$files = [];
foreach ($iterator as $file) {
    if ($file->isFile() && in_array($file->getExtension(), $extensions)) {
        $files[] = $file->getPathname();
    }
}
echo 'Найдено файлов: ' . count($files);
Найдено файлов: 245

Пояснение: Используем in_array() для проверки расширения. Обратите внимание, что getExtension() возвращает пустую строку, если расширения нет, поэтому пустые расширения не попадут.

Пример 2: Поиск файлов определенного размера (больше 1 МБ)

Пример

$minSize = 1 * 1024 * 1024; // 1 MB
$directory = new RecursiveDirectoryIterator('/var/log');
$iterator = new RecursiveIteratorIterator($directory);
$largeFiles = [];
foreach ($iterator as $file) {
    if ($file->isFile() && $file->getSize() >= $minSize) {
        $largeFiles[] = $file->getPathname() . ' (' . round($file->getSize() / 1024 / 1024, 2) . ' MB)';
    }
}
print_r($largeFiles);
Array
(
    [0] => /var/log/nginx/access.log (24.78 MB)
    [1] => /var/log/mysql/slow.log (1.23 MB)
)

Пример 3: Поиск файлов по дате последнего изменения (сегодня)

Пример

$todayStart = strtotime('today midnight');
$todayEnd = strtotime('tomorrow midnight');
$directory = new RecursiveDirectoryIterator('/tmp');
$iterator = new RecursiveIteratorIterator($directory);
$todayFiles = [];
foreach ($iterator as $file) {
    if ($file->isFile() && $file->getMTime() >= $todayStart && $file->getMTime() < $todayEnd) {
        $todayFiles[] = $file->getPathname();
    }
}
echo 'Файлы изменённые сегодня: ' . count($todayFiles);
Файлы изменённые сегодня: 12

Пример 4: Поиск файлов, содержащих два разных слова (логическое И)

Пример

$words = ['warning', 'error'];
$directory = new RecursiveDirectoryIterator('/var/log/app');
$iterator = new RecursiveIteratorIterator($directory);
$foundFiles = [];
foreach ($iterator as $file) {
    if ($file->isFile() && $file->getExtension() === 'log') {
        $handle = fopen($file->getPathname(), 'r');
        if ($handle) {
            $line = fgets($handle); // читаем только первую строку для примера
            if ($line !== false) {
                $containsAll = true;
                foreach ($words as $word) {
                    if (strpos($line, $word) === false) {
                        $containsAll = false;
                        break;
                    }
                }
                if ($containsAll) {
                    $foundFiles[] = $file->getPathname();
                }
            }
            fclose($handle);
        }
    }
}
print_r($foundFiles);
Array
(
    [0] => /var/log/app/errors.log
)

Пример 5: Использование собственного фильтра-итератора (FilterIterator)

Пример

class PhpFileFilter extends FilterIterator {
    public function accept(): bool {
        $current = $this->current();
        if ($current instanceof SplFileInfo) {
            return $current->isFile() && $current->getExtension() === 'php';
        }
        return false;
    }
}

$directory = new RecursiveDirectoryIterator('/project');
$iterator = new RecursiveIteratorIterator($directory);
$filtered = new PhpFileFilter($iterator);
foreach ($filtered as $file) {
    echo $file->getPathname() . PHP_EOL;
}
/project/index.php
/project/src/Controller.php
/project/templates/header.php

Пояснение: Кастомный фильтр инкапсулирует логику отбора. Можно также комбинировать несколько фильтров.

Пример 6: Поиск файлов через glob с рекурсией (не всегда переносимо)

Пример

// Работает, если система поддерживает **
$phpFiles = glob('/var/www/**/*.php');
print_r($phpFiles);
Array
(
    [0] => /var/www/index.php
    [1] => /var/www/subdir/test.php
)

Пояснение: Двойная звездочка ** обозначает любое количество вложенных директорий. Однако эта возможность зависит от реализации glob в системе (GLOB_BRACE, GLOB_ONLYDIR). На Windows может не работать.

- Php текстовый файл (текстовый файл php)
- Index php file 1 (работа с файлами и папками на php)
- Php получить файл (получение файла в php)
- Php удалить файл (удаление файла в php)
- Php сделать файл (создание файла в php)
- Php размер файла (размер файла php)
- найти файл php (поиск файла php)
- Php file (работа с файлами в php)
- массив файлов php (массив файлов в php)
- Php include server (include сервера php)
- файлы пользователя php (файлы пользователя в php)
- Php папка файла (папка файла php)
- проверка файлов php (проверка файлов php)
- Php корневой каталог (корневой каталог сайта в php)
- Php база в файле (хранение данных в файлах в php (flat-file database))
- Php get extension (получение информации о файлах в php)
- Php файл с сервера (файл с сервера php)
- Php изменить файл (изменение файла в php)
- Php записать в файл (запись в файл php)
- Php несколько файлов (несколько файлов в php)
- Php включить файл (включение файла в php)

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

En
найти файл php (php)