Получение списка файлов и директорий с помощью PHP
Получение списка файлов и директорий с помощью PHP
Листинг директорий - это получение информации о каталогах и файлах для заданной родительской директории, а также возможность применить к этим данным различные фильтры для коррекции вывода.
В данном примере мы попробуем справиться с типовой задачей, которая появляется почти в каждом PHP проекте - получение списка директорий и(или) файлов. В примере используются несколько базовых и более сложный подход, с обозначением плюсов и минусов каждого приема. Первые три решения используют типовые функции PHP. Последнее более надежное решение с применением PHP итераторов SPL.
Для более наглядного представления используем структуру директорий, которая имеет следующий вид:
Базовые решения
Первый набор примеров использует функции glob() и комбинации функций opendir(), readdir(), closedir(), а также функцию scandir().
Использование glob()
Пример использования php функции glob(), которая позволяет выполнять поиск пути по шаблону.
Функция glob($pattern,$flags) оперирует двумя аргументами:
$pattern (обязательный): строка шаблона поиска
$flags (не обязательный): один или несколько флагов
GLOB_MARK - Добавляет слеш к каждой возвращаемой директории.
GLOB_NOSORT - Возвращает файлы в том виде, в котором они содержатся в директории (без сортировки). Если этот флаг не указан, то имена сортируются по алфавиту.
GLOB_NOCHECK - Возвращает шаблон поиска, если с его помощью не был найден ни один файл.
GLOB_NOESCAPE - Обратные слеши не экранируют мета символы.
GLOB_BRACE - Раскрывает {a,b,c} для совпадения с 'a', 'b' или 'c'.
GLOB_ONLYDIR - Возвращает только директории, совпадающие с шаблоном.
GLOB_ERR - Останавливается при ошибках чтения (например, директории без права чтения), по умолчанию ошибки игнорируются.
Для поиска в директории всех файлов и директорий, имена которых заканчиваются на .txt, следует используется код:
<?php
$arFileList = glob("*.txt");
//Выводим результат
var_dump($arFileList);
?>
Получение в списке только директорий с именами, содержащими "er":
<?php
$arFileList = glob("*er*", GLOB_ONLYDIR);
//Выводим результат
var_dump($arFileList);
?>
В выводе получим такой результат:
array(1) {
[0]=>
string(4) "User"
}
В последнем примере использован флаг GLOB_ONLYDIR в качестве второго аргумента функции. Поэтому в список попала, только директория "User" в имени, которой встречается "er". Функция glob() очень проста в использовании, но иногда она недостаточно гибкая. Нет флага для получения только файлов (без директорий), которые соответствуют шаблону.
Использование opendir(), readdir(), и closedir().
Следующий метод получения списка файлов и директорий, заключается в использовании PHP функций opendir(), readdir() и closedir().
Функция opendir() возвращает дескриптор открытой директории. После того как дескриптор получен, можно использовать функцию readdir(). При обращении к дескриптору функция readdir() выдает имя следующего файла или директории. Если все элементы содержащиеся в дескрипторе уже были перечислены, функция readdir() вернет false. Для закрытия дескриптора используем функцию closedir().
В отличие от использования php функции glob(), данный подход немного сложнее. Отсутствует возможность задать параметры фильтрации, которые помогают заранее формировать список возвращаемых имен файлов и директорий. Для получения необходимого списка файлов и директорий, фильтрацию должна быть выполнена самостоятельно.
Приведенный пример возвращает список имен файлов и директорий начинающихся на "Us":
Для завершения посмотрим пример использования php функции scandir(). У нее есть только один обязательный атрибут - путь к директории для чтения. Результатом работы функции является массив файлов и директорий, расположенных по заданному в аргументе пути. Как и в предыдущем примере для получения отфильтрованного списка файлов и директорий необходимо выполнить ее самостоятельно. Визуально решение получается более коротким и не требуется управление дескрипторами.
Пример показывает, как получить список файлов и каталогов, имена которых начинаются на "te":
<?php
$arFileName = scandir(".");
$arFileList = array();
foreach($arFileName as $FileName):
if(strpos($FileName,"te")===0):
$arFileList[] = $FileName;
endif;
endforeach;
//Выводим результат
var_dump($arFileList);
?>
Продвинутое решение c использованием PHP SPL
Более надежное решение с применением SPL итераторов FilesystemIterator, RecursiveDirectoryIterator и GlobIterator.
Использование итераторов SPL.
Рассмотрим использование итераторов SPL.
До того как приступить к решению задачи, немного познакомимся с php библиотекой SPL и итераторами. SPL библиотека предоставляет из себя специализированные наборы классов для объектно ориентированных структур данных, итераторов, дескрипторов файлов и прочее.
Основное преимущество итераторов заключается в том, что они являются классами и их можно расширить используя стандартный механизм php наследования классов. Еще один плюс заключается в том, что итераторы имеют собственные методы, которые могут быть полезны при решении типовых задач и все они расположены в одном месте.
Посмотрим на примере использования FilesystemIterator и сравним с readdir(). Оба метода используют цикл, но в случае readdir() получится обрабатывать только строку, а FilesystemIterator может работать с объектом. В котором может содержатся дополнительная информацию о файле или директории такие как владелец, размер, права доступа и так далее.
Разумеется у PHP есть возможности для получения этой информации с помощью функций, filesize(), fileowner() и других. Но PHP как и любой язык программирования имеет свойства меняться. В PHP5 все больше прослеживается стремление задействовать концепции ООП. Поэтому лучше использовать современные методы работы с языком программирования.
Рассмотрим использование FilesystemIterator, RecursiveDirectoryIterator и GlobIterator. Первый итератор наследуется от DirectoryIterator, а остальные от FilesystemIterator. Все они имеют один и тот же конструктор, который принимает два аргумента:
$path (обязательный): путь к пункту файловой системы, над которым совершаются операции
$flags (не обязательный): один или несколько флагов
FilesystemIterator::CURRENT_AS_PATHNAME Заставляет метод FilesystemIterator::current() вернуть путь.
FilesystemIterator::CURRENT_AS_FILEINFO Заставляет метод FilesystemIterator::current() вернуть экземпляр SplFileInfo.
FilesystemIterator::CURRENT_AS_SELF Заставляет метод FilesystemIterator::current() вернуть $this (FilesystemIterator).
Пример использования другого итератора RegexIterator для поиска всех файлов и каталогов, имена которых заканчиваются на "t.js" или "t.php".
Итератор RegexIterator используется для фильтрации результата и использует механизм регулярных выражений.
<?php
$obIterator = new FilesystemIterator(".");
$rxIterator = new RegexIterator($obIterator,'/t\.(php|js)$/');
$arFileList = array();
foreach($rxIterator as $obFile):
$arFileList[] = $obFile->getFilename();
endforeach;
//Выводим результат
var_dump($arFileList);
?>
Итератор RecursiveDirectoryIterator обеспечивает интерфейс для рекурсивного прохода по директориям файловой системы. Он имеет несколько полезных методов, таких как getChildren() и hasChildren(), которые возвращают итератор для текущего места, если это директория, и проверяют, является ли текущая точка входа директорией.
Пример демонстрирует использование RecursiveDirectoryIterator и getChildren().
<?php
$obIterator = new RecursiveDirectoryIterator('.');
$rxIterator = new RegexIterator($obIterator->getChildren(), '/t\.(txt|css)$/');
$arFileList = array();
foreach($rxIterator as $obFile):
$arFileList[] = $obFile->getFilename();
endforeach;
//Выводим результат
var_dump($arFileList);
?>
В выводе получим такой результат в данном случае - это файл из директории "User":
array(1) {
[0]=>
string(8) "test.txt"
}
GlobIterator
Итератор GlobIterator выполняет проход по файловой аналогично функции glob(). Первый атрибут может включать шаблон имени.
Пример демонстрирует использование GlobIterator с тем же результатом, что и ранее.
<?php
$obIterator = new GlobIterator("te*");
$arFileList = array();
foreach($obIterator as $obFile):
$arFileList[] = $obFile->getFilename();
endforeach;
//Выводим результат
var_dump($arFileList);
?>