Php как найти все файлы в папке. Получение списка файлов и директорий с помощью PHP. Использование итераторов SPL

В данном уроке мы разберемся с типовой задачей, которая возникает во время работы над проектом PHP: получение списка файлов и директорий. Обсудим несколько базовых и более изощренных подходов, с перечисление плюсов и минусов каждого. Первые три решения будут использовать типовые функции PHP, а затем представим более надежное с применением итераторов SPL.

Для предметного обсуждения решения и демонстраций предположим, что структура директорий имеет следующий вид:

\---manager | \---user | \---document.txt | \---data.dat | \---style.css |---article.txt |---master.dat |---script.php |---test.dat |---text.txt

Базовые решения

Первый набор решений основан на использовании функции glob() , комбинации функций opendir() , readdir() и closedir() , и также функции scandir() .

Использование glob()

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

  • $pattern (обязательный): шаблон поиска
  • $flags (опциональный): один или несколько флагов, описание которых можно найти в документации

Рассмотрим примеры. Для поиска в директории всех файлов и директорий, имена которых заканчиваются на .txt , следует использовать код:

Если вывести переменную $filelist , то получим:

Array (0 => "article.txt", 1 => "text.txt")

Если нужен список файлов и директорий, имена которых начинаются на “te”, то код будет выглядеть так:

А вывод имеет вид:

Array (0 => "test.dat", 1 => "text.txt")

А для получения списка только директорий с именами, содержащих “ma”, используем код:

Последний пример выведет:

Array (0 => "manager")

Обратите внимание, что в последнем примере использован флаг GLOB_ONLYDIR в качестве второго параметра функции. Поэтому файл master.dat исключен из списка. Хотя функция glob() очень проста в использовании, иногда она недостаточно гибкая. Например, нет флага для получения только файлов (без директорий), которые соответствуют шаблону.

Используем opendir() , readdir() , и closedir() .

Второй подход к получению списка файлов и директорий, который мы обсудим, заключается в использовании функций opendir() , readdir() , и closedir() .

Функция opendir() открывает директорию и возвращает дескриптор соединения. Как только дескриптор получен, можно использовать функцию readdir() . С каждым обращением данная функция выдает имя следующего файла или директории внутри открытого каталога. Если все имена уже были перечислены, функция возвращает false . Для закрытия дескриптора используется функция closedir() .

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

Ниже приведенный пример возвращает список имен файлов и директорий начинающихся на “te”:

При выполнении выше приведенного кода, переменная $entry будет содержать такие включения, как “.” и “..”. Это две виртуальные директории, которые имеются в каждом каталоге файловой системы. Они представляют текущий каталог и родительский каталог соответственно.

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

Пример выдаст следующее:

Array (0 => "article.txt", 1 => "master.dat", 2 => "script.php", 3 => "test.dat", 4 => "text.txt")

Использование scandir()

В завершение представим функцию scandir() . Она имеет только один обязательный параметр: путь для чтения. Функция возвращает массив файлов и директорий, расположенных по указанному пути. Для получения списка файлов и директорий по определенному критерию нужно выполнить дополнительную фильтрацию. С другой стороны, решение получается более кратким и не требует управления дескрипторами.

Данный пример показывает, как получить список файлов и каталогов, имена которых начинаются на “te”:

Воспользуемся итераторами SPL

Теперь рассмотрим использование итераторов SPL . Но прежде, чем приступить к решению нашей задачи, проведем введение в библиотеку SPL и итераторы. Библиотека SPL предоставляет серию классов для объектно ориентированных структур данных, итераторов, дескрипторов файлов и прочее.

Одно из преимуществ итераторов заключается в том, что они являются классами и их можно расширить для удовлетворения собственных нужд. Другой плюс состоит в том, что итераторы имеют собственные методы, которые являются полезными при решении множества типовых задач и располагаются в одном месте. Посмотрите на пример использования FilesystemIterator в сравнении с readdir() . Оба метода применяют цикл, но в случае readdir() вы обрабатываете только строку, а FilesystemIterator работает с объектом, который может содержать дополнительную информацию о файле или директории (размер, владелец, права доступа и так далее).

Конечно, PHP представляет возможность для получения такой информации с помощью функций,например filesize() и fileowner(). Но PHP5 основан на использовании концепции ООП. Поэтому лучше использовать современные методы работы с языком программирования. На нашем сайте есть уроки, посвященные работе с итераторами .

Как уже сообщалось во водной части урока, мы рассмотрим использование FilesystemIterator , RecursiveDirectoryIterator и GlobIterator . Первый наследуется от DirectoryIterator , а остальные от FilesystemIterator . Они все имеют один и тот же конструктор, который принимает два параметра:

  • $path (обязательный): путь к пункту файловой системы, над которым совершаются операции
  • $flags (опциональный): один или несколько флагов, перечисленных в документации

Реальное различие в данных итераторах заключается в их использовании для навигации по заданному пути.

FilesystemIterator

Использовать FilesystemIterator очень просто. Рассмотрим в действии. Представляем два примера. Первый показывает поиск всех файлов и каталогов, имена которых начинаются на “te”. Второй пример использует другой итератор RegexIterator для поиска всех файлов и каталогов, имена которых заканчиваются на “t.dat” или “t.php”. Итератор RegexIterator используется для фильтрации результата на основе регулярных выражений.

getFilename(), "te") === 0) { $filelist = $entry->getFilename(); } }

Выше приведенный код выдаст результат, аналогичный предыдущим примерам.

Второй пример с применением RegexIterator:

getFilename(); }

Он будет выводить:

Array (0 => "script.php", 1 => "test.dat")

RecursiveDirectoryIterator

Итератор RecursiveDirectoryIterator обеспечивает интерфейс для рекурсивного прохода по директориям файловой системы. Он имеет несколько полезных методов, таких как getChildren() и hasChildren() , которые возвращают итератор для текущего места, если это директория, и проверяют, является ли текущая точка входа директорией. Следующий пример демонстрирует использование RecursiveDirectoryIterator и getChildren() . Результат будет такой же, как и в предыдущих примерах.

getChildren(), "/t\.(php|dat)$/"); $filelist = array(); foreach($filter as $entry) { $filelist = $entry->getFilename(); }

GlobIterator

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

getFilename(); }

Заключение

В данном уроке демонстрируется использование различных подходов для достижение одинаковой цели: получение списка файлов и директорий. Следует запомнить следующие ключевые моменты:

  • Функция glob() является встроенным решением, но она недостаточно гибкая.
  • Решение на основе opendir() , readdir() , и closedir() более сложное и требует дополнительной фильтрации, но оно более гибкое.
  • Функция scandir() требует дополнительной фильтрации, но работает без обработки дескриптора.
  • Если вы используете подход ООП, то следует применять библиотеку SPL. Дополнительно вы можете расширить классы своим функционалом.
  • Итератор GlobIterator имеет функцию предварительной фильтрации, а другие используют RegexIterator .

Reg.ru: домены и хостинг

Крупнейший регистратор и хостинг-провайдер в России.

Более 2 миллионов доменных имен на обслуживании.

Продвижение, почта для домена, решения для бизнеса.

Более 700 тыс. клиентов по всему миру уже сделали свой выбор.

*Наведите курсор мыши для приостановки прокрутки.

Назад Вперед

Получение списка папок с помощью PHP

Список каталогов средствами PHP, или листинг директорий

Листингом директорий мы будем называть запрос общего вида, формирующий список всех, либо некоторых файлов и каталогов родительской директории - процесс похожий на работу индексной страницы, обеспечиваемой большинством веб-серверов, но с бо льшим контролем над контентом и форматированием оного же.

Ещё одно преимущество данного скрипта - возможность выполнять определённые действия с файлами, используя PHP. В любом случае, первый шаг, который нам нужно сделать - это запрос к файловой системе - вернуть список файлов и каталогов.

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

Замечание: в PHP5 есть функция scandir , которая "возвращает список файлов и каталогов, внутри директории, по заданному пути", однако она не выводит какую-либо дополнительную информацию о находящихся внутри директории файлах.

Листинг одной директории

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

read())) { // пропустить скрытые файлы if($entry == ".") continue; if(is_dir("$dir$entry")) { $retval = array("name" => "$dir$entry/", "size" => 0, "lastmod" => filemtime("$dir$entry")); } elseif(is_readable("$dir$entry")) { $retval = array("name" => "$dir$entry", "size" => filesize("$dir$entry"), "lastmod" => filemtime("$dir$entry")); } } $d->close(); return $retval; } ?>

Вы можете использовать эту функцию как ниже:

Возвращаемое значение является ассоциативным массивом файлов, включающим в себя информацию о пути к файлу, размер и дату последней модификации, кроме случая, когда файл является директорией, в этом случае строка "(dir)" возникает вместо размера файла.

Пример 1:

",print_r($dirlist),""; /* пример вывода Array ( => Array ( => images/background0.jpg => image/jpeg => 86920 => 1077461701) => ...) */ ?>

Пример 2:

",print_r($dirlist),""; /* пример вывода Array ( => Array ( => ./images/background0.jpg => image/jpeg => 86920 => 1077461701) => ...) */ ?>

Вывод списка файлов через HTML

Чтобы получить результаты вывода на странице в HTML, мы прокрутим возвращаемый массив через цикл

\n"; echo "NameTypeSizeLast Mod.\n"; foreach($dirlist as $file) { echo "\n"; echo "{$file["name"]}\n"; echo "{$file["type"]}\n"; echo "{$file["size"]}\n"; echo "\n"; echo "\n"; } echo "\n\n"; ?>

Этот код довольно просто модифицировать, например:

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

Например, для вывода только PNG-файлов, добавьте простое условие в цикл вывода:

\n"; echo "NameTypeSizeLast Mod.\n"; foreach($dirlist as $file) { //проверка на принадлежность файла к PNG if(!preg_match("/\.png$/", $file["name"])) continue; echo "\n"; echo "{$file["name"]}\n"; echo "{$file["type"]}\n"; echo "{$file["size"]}\n"; echo "",date("r", $file["lastmod"]),"\n"; echo "\n"; } echo "\n\n"; ?>

В этом примере будут пропущены и скрыты все файлы, чьи имена заканчиваются на .png . Вы также можете применить дополнительные условия, основанные на типе файла, его размере или дате последнего изменения.

Если вы, например, хотите отобразить миниатюру, ссылкой на картинку большего размера, или даже видео, просто задайте этим 2-м файлам одинаковые имена и в скрипте выше используйте str_replace или похожую функцию, чтобы модифицировать содержимое ссылок.

Рекурсивный листинг директории

И раз уж мы зашли так далеко, здесь будут только незначительные изменения в функции вызова рекурсивного списка и субкатегорий. Добавляя второй параметр в функцию, мы сохраняем предыдущий функционал листинга одиночной директории.

read())) { // пропустить скрытые файлы if($entry == ".") continue; if(is_dir("$dir$entry")) { $retval = array("name" => "$dir$entry/", "size" => 0, "lastmod" => filemtime("$dir$entry")); if($recurse && is_readable("$dir$entry/")) { $retval = array_merge($retval, getFileList("$dir$entry/", true)); } } elseif(is_readable("$dir$entry")) { $retval = array("name" => "$dir$entry", "size" => filesize("$dir$entry"), "lastmod" => filemtime("$dir$entry")); } } $d->close(); return $retval; } ?>

Чтобы новый функционал заработал, вам нужно ввести значение true (или 1) в качестве второго параметра.

Перед рекурсингом скрипта проверьте, являются ли поддиректории читабельными а также ознакомьтесь с последним пунктом данного урока, дабы избежать ошибок доступа.

Как и раньше, возвращаемая величина - это массив, ассоциативный массивов. Фактически, единственное дополнение - это ещё одна дополнительная опция для рекурсивного листинга.

Ограничение глубины рекурсии

Этот финальный пример добавляет ещё одно свойство - способность к определению, как "глубоко" должна проходить рекурсия. Предыдущий код будет продолжать исследовать вложенные директории, до тех пор пока они не закончатся. Этот скрипт поможет установить ограничение, по количеству уровней вложенных директорий.

read())) { // пропустить скрытые файлы if($entry == ".") continue; if(is_dir("$dir$entry")) { $retval = array("name" => "$dir$entry/", "size" => 0, "lastmod" => filemtime("$dir$entry")); if($recurse && is_readable("$dir$entry/")) { if($depth === false) { $retval = array_merge($retval, getFileList("$dir$entry/", true)); } elseif($depth > 0) { $retval = array_merge($retval, getFileList("$dir$entry/", true, $depth-1)); } } } elseif(is_readable("$dir$entry")) { $retval = array("name" => "$dir$entry", "size" => filesize("$dir$entry"), "lastmod" => filemtime("$dir$entry")); } } $d->close(); return $retval; } ?>

Как и раньше, мы добавили всего 1 новый параметр и пару строк кода. Если значение по умолчанию, отвечающее за глубину рекурсинга, не задано, то оно устанавливается в false . Это позволяет нам быть уверенными в том, что предыдущие особенности остаются и последующий код не "поломается" при изменении функции.

scandir — Получает список файлов и каталогов, расположенных по указанному пути

Описание

Array scandir (string $directory [, int $sorting_order = SCANDIR_SORT_ASCENDING [, resource $context ]])

Возвращает array , содержащий имена файлов и каталогов, расположенных по пути, переданном в параметре directory .

Список параметров

Сканируемый каталог.

Sorting_order

По умолчанию, сортировка производится в алфавитном порядке по возрастанию. Если необязательный параметр sorting_order установлен в значение SCANDIR_SORT_DESCENDING , сортировка производится в алфавитном порядке по убыванию. Если же он установлен в значение SCANDIR_SORT_NONE , то сортировка не производится.

Context

За описанием параметра context обратитесь к разделу "Потоки " данного руководства.

Возвращаемые значения

Возвращает array имен файлов в случае успеха или FALSE в случае ошибки. Если directory не является каталогом, возвращается FALSE и генерируется сообщение об ошибке уровня E_WARNING .

Список изменений

Примеры

Пример #1 Простой пример использования функции scandir()

$dir = "/tmp" ;
$files1 = scandir ($dir );
$files2 = scandir ($dir , 1 );

Print_r ($files1 );
print_r ($files2 );
?>

Результатом выполнения данного примера будет что-то подобное:

Array ( => . => .. => bar.php => foo.txt => somedir) Array ( => somedir => foo.txt => bar.php => .. => .)

Пример #2 Альтернативный вариант функции scandir() для PHP 4

$dir = "/tmp" ;
$dh = opendir ($dir );
while (false !== ($filename = readdir ($dh ))) {
$files = $filename ;
}

Sort ($files );

Print_r ($files );

Rsort ($files );

Print_r ($files );

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

В данном примере мы попробуем справиться с типовой задачей, которая появляется почти в каждом PHP проекте - получение списка директорий и(или) файлов. В примере используются несколько базовых и более сложный подход, с обозначением плюсов и минусов каждого приема. Первые три решения используют типовые функции PHP. Последнее более надежное решение с применением PHP итераторов SPL.


Для более наглядного представления используем структуру директорий, которая имеет следующий вид:


\-Application | \-User | \-data.apk | \-style.css | \-test.txt |-readme.txt |-script.php |-serial.txt |-test.html |-test.js

Базовые решения
Первый набор примеров использует функции 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, следует используется код: В выводе получим такой результат: array(2) { => string(10) "readme.txt" => string(10) "serial.txt" } Если необходимо получить список файлов и директорий, имена которых начинаются на "te": В выводе получим такой результат: array(2) { => string(9) "test.html" => string(7) "test.js" } Получение в списке только директорий с именами, содержащими "er": В выводе получим такой результат: array(1) { => string(4) "User" }

В последнем примере использован флаг GLOB_ONLYDIR в качестве второго аргумента функции. Поэтому в список попала, только директория "User" в имени, которой встречается "er". Функция glob() очень проста в использовании, но иногда она недостаточно гибкая. Нет флага для получения только файлов (без директорий), которые соответствуют шаблону.

Использование opendir(), readdir(), и closedir().

Следующий метод получения списка файлов и директорий, заключается в использовании PHP функций opendir() , readdir() и closedir() .

Функция opendir() возвращает дескриптор открытой директории. После того как дескриптор получен, можно использовать функцию readdir() . При обращении к дескриптору функция readdir() выдает имя следующего файла или директории. Если все элементы содержащиеся в дескрипторе уже были перечислены, функция readdir() вернет false . Для закрытия дескриптора используем функцию closedir() .


В отличие от использования php функции , данный подход немного сложнее. Отсутствует возможность задать параметры фильтрации, которые помогают заранее формировать список возвращаемых имен файлов и директорий. Для получения необходимого списка файлов и директорий, фильтрацию должна быть выполнена самостоятельно.


Приведенный пример возвращает список имен файлов и директорий начинающихся на "Us": В выводе получим такой результат: array(1) { => string(4) "User" } Следующий пример выведет только файлы, содержащиеся в заданном каталоге. В выводе получим такой результат: array(5) { => string(10) "script.php" => string(7) "test.js" => string(9) "test.html" => string(10) "serial.txt" => string(10) "readme.txt" }

Использование scandir().

Для завершения посмотрим пример использования php функции scandir() . У нее есть только один обязательный атрибут - путь к директории для чтения. Результатом работы функции является массив файлов и директорий, расположенных по заданному в аргументе пути. Как и в предыдущем примере для получения отфильтрованного списка файлов и директорий необходимо выполнить ее самостоятельно. Визуально решение получается более коротким и не требуется управление дескрипторами.


Пример показывает, как получить список файлов и каталогов, имена которых начинаются на "te": В выводе получим такой результат: array(2) { => string(9) "test.html" => string(7) "test.js" }

Продвинутое решение 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).
    • FilesystemIterator::CURRENT_MODE_MASK Маскирует FilesystemIterator::current()
    • FilesystemIterator::KEY_AS_PATHNAME Заставляет метод FilesystemIterator::key() вернуть путь.
    • FilesystemIterator::KEY_AS_FILENAME Заставляет метод FilesystemIterator::key() вернуть имя файла.
    • FilesystemIterator::FOLLOW_SYMLINKS Заставляет метод RecursiveDirectoryIterator::hasChildren() следовать символическим ссылкам.
    • FilesystemIterator::KEY_MODE_MASK Маскирует FilesystemIterator::key()
    • FilesystemIterator::NEW_CURRENT_AND_KEY Тоже, что FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::CURRENT_AS_FILEINFO.
    • FilesystemIterator::SKIP_DOTS Пропускает точечные файлы (. and ..).
    • FilesystemIterator::UNIX_PATHS Заставляет все пути использовать обратный слеш в Unix-стиле, независимо от настроек системы по умолчанию.

Различие в данных итераторах заключается в их использовании для навигации по заданному пути.

FilesystemIterator

Использовать FilesystemIterator очень просто.
Пример показывает поиск всех файлов и каталогов, имена которых начинаются на "te".

getFilename(),"te")===0): $arFileList = $obFile->getFilename(); endif; endforeach; //Выводим результат var_dump($arFileList); ?> В выводе получим такой результат: array(2) { => string(7) "test.js" => string(9) "test.html" }

Пример использования другого итератора RegexIterator для поиска всех файлов и каталогов, имена которых заканчиваются на "t.js" или "t.php". Итератор RegexIterator используется для фильтрации результата и использует механизм регулярных выражений.

getFilename(); endforeach; //Выводим результат var_dump($arFileList); ?> В выводе получим такой результат: array(2) { => string(10) "script.php" => string(7) "test.js" }

RecursiveDirectoryIterator

Итератор RecursiveDirectoryIterator обеспечивает интерфейс для рекурсивного прохода по директориям файловой системы. Он имеет несколько полезных методов, таких как getChildren() и hasChildren() , которые возвращают итератор для текущего места, если это директория, и проверяют, является ли текущая точка входа директорией.


RecursiveDirectoryIterator и getChildren() . getChildren(), "/t\.(txt|css)$/"); $arFileList = array(); foreach($rxIterator as $obFile): $arFileList = $obFile->getFilename(); endforeach; //Выводим результат var_dump($arFileList); ?> В выводе получим такой результат в данном случае - это файл из директории "User": array(1) { => string(8) "test.txt" }

GlobIterator

Итератор GlobIterator выполняет проход по файловой аналогично функции . Первый атрибут может включать шаблон имени.


Пример демонстрирует использование GlobIterator с тем же результатом, что и ранее. getFilename(); endforeach; //Выводим результат var_dump($arFileList); ?> В выводе получим такой результат: array(2) { => string(10) "/test.html" => string(8) "/test.js" }

Заключение

В приведенных выше примерах были рассмотрены различные методы PHP для достижения одной и той же цели: получение списка файлов и директорий.

Из примеров можно выделить следующие основные моменты:

В данном уроке мы разберемся с типовой задачей, которая возникает во время работы над проектом PHP: получение списка файлов и директорий. Обсудим несколько базовых и более изощренных подходов, с перечисление плюсов и минусов каждого. Первые три решения будут использовать типовые функции PHP, а затем представим более надежное с применением итераторов SPL.

Для предметного обсуждения решения и демонстраций предположим, что структура директорий имеет следующий вид:

\---manager | \---user | \---document.txt | \---data.dat | \---style.css |---article.txt |---master.dat |---script.php |---test.dat |---text.txt

Базовые решения

Первый набор решений основан на использовании функции glob() , комбинации функций opendir() , readdir() и closedir() , и также функции scandir() .

Использование glob()

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

  • $pattern (обязательный): шаблон поиска
  • $flags (опциональный): один или несколько флагов, описание которых можно найти в документации

Рассмотрим примеры. Для поиска в директории всех файлов и директорий, имена которых заканчиваются на .txt , следует использовать код:

Если вывести переменную $filelist , то получим:

Array (0 => "article.txt", 1 => "text.txt")

Если нужен список файлов и директорий, имена которых начинаются на “te”, то код будет выглядеть так:

А вывод имеет вид:

Array (0 => "test.dat", 1 => "text.txt")

А для получения списка только директорий с именами, содержащих “ma”, используем код:

Последний пример выведет:

Array (0 => "manager")

Обратите внимание, что в последнем примере использован флаг GLOB_ONLYDIR в качестве второго параметра функции. Поэтому файл master.dat исключен из списка. Хотя функция glob() очень проста в использовании, иногда она недостаточно гибкая. Например, нет флага для получения только файлов (без директорий), которые соответствуют шаблону.

Используем opendir() , readdir() , и closedir() .

Второй подход к получению списка файлов и директорий, который мы обсудим, заключается в использовании функций opendir() , readdir() , и closedir() .

Функция opendir() открывает директорию и возвращает дескриптор соединения. Как только дескриптор получен, можно использовать функцию readdir() . С каждым обращением данная функция выдает имя следующего файла или директории внутри открытого каталога. Если все имена уже были перечислены, функция возвращает false . Для закрытия дескриптора используется функция closedir() .

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

Ниже приведенный пример возвращает список имен файлов и директорий начинающихся на “te”:

При выполнении выше приведенного кода, переменная $entry будет содержать такие включения, как “.” и “..”. Это две виртуальные директории, которые имеются в каждом каталоге файловой системы. Они представляют текущий каталог и родительский каталог соответственно.

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

Пример выдаст следующее:

Array (0 => "article.txt", 1 => "master.dat", 2 => "script.php", 3 => "test.dat", 4 => "text.txt")

Использование scandir()

В завершение представим функцию scandir() . Она имеет только один обязательный параметр: путь для чтения. Функция возвращает массив файлов и директорий, расположенных по указанному пути. Для получения списка файлов и директорий по определенному критерию нужно выполнить дополнительную фильтрацию. С другой стороны, решение получается более кратким и не требует управления дескрипторами.

Данный пример показывает, как получить список файлов и каталогов, имена которых начинаются на “te”:

Воспользуемся итераторами SPL

Теперь рассмотрим использование итераторов SPL . Но прежде, чем приступить к решению нашей задачи, проведем введение в библиотеку SPL и итераторы. Библиотека SPL предоставляет серию классов для объектно ориентированных структур данных, итераторов, дескрипторов файлов и прочее.

Одно из преимуществ итераторов заключается в том, что они являются классами и их можно расширить для удовлетворения собственных нужд. Другой плюс состоит в том, что итераторы имеют собственные методы, которые являются полезными при решении множества типовых задач и располагаются в одном месте. Посмотрите на пример использования FilesystemIterator в сравнении с readdir() . Оба метода применяют цикл, но в случае readdir() вы обрабатываете только строку, а FilesystemIterator работает с объектом, который может содержать дополнительную информацию о файле или директории (размер, владелец, права доступа и так далее).

Конечно, PHP представляет возможность для получения такой информации с помощью функций,например filesize() и fileowner(). Но PHP5 основан на использовании концепции ООП. Поэтому лучше использовать современные методы работы с языком программирования. На нашем сайте есть уроки, посвященные работе с итераторами .

Как уже сообщалось во водной части урока, мы рассмотрим использование FilesystemIterator , RecursiveDirectoryIterator и GlobIterator . Первый наследуется от DirectoryIterator , а остальные от FilesystemIterator . Они все имеют один и тот же конструктор, который принимает два параметра:

  • $path (обязательный): путь к пункту файловой системы, над которым совершаются операции
  • $flags (опциональный): один или несколько флагов, перечисленных в документации

Реальное различие в данных итераторах заключается в их использовании для навигации по заданному пути.

FilesystemIterator

Использовать FilesystemIterator очень просто. Рассмотрим в действии. Представляем два примера. Первый показывает поиск всех файлов и каталогов, имена которых начинаются на “te”. Второй пример использует другой итератор RegexIterator для поиска всех файлов и каталогов, имена которых заканчиваются на “t.dat” или “t.php”. Итератор RegexIterator используется для фильтрации результата на основе регулярных выражений.

getFilename(), "te") === 0) { $filelist = $entry->getFilename(); } }

Выше приведенный код выдаст результат, аналогичный предыдущим примерам.

Второй пример с применением RegexIterator:

getFilename(); }

Он будет выводить:

Array (0 => "script.php", 1 => "test.dat")

RecursiveDirectoryIterator

Итератор RecursiveDirectoryIterator обеспечивает интерфейс для рекурсивного прохода по директориям файловой системы. Он имеет несколько полезных методов, таких как getChildren() и hasChildren() , которые возвращают итератор для текущего места, если это директория, и проверяют, является ли текущая точка входа директорией. Следующий пример демонстрирует использование RecursiveDirectoryIterator и getChildren() . Результат будет такой же, как и в предыдущих примерах.

getChildren(), "/t\.(php|dat)$/"); $filelist = array(); foreach($filter as $entry) { $filelist = $entry->getFilename(); }

GlobIterator

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

getFilename(); }

Заключение

В данном уроке демонстрируется использование различных подходов для достижение одинаковой цели: получение списка файлов и директорий. Следует запомнить следующие ключевые моменты:

  • Функция glob() является встроенным решением, но она недостаточно гибкая.
  • Решение на основе opendir() , readdir() , и closedir() более сложное и требует дополнительной фильтрации, но оно более гибкое.
  • Функция scandir() требует дополнительной фильтрации, но работает без обработки дескриптора.
  • Если вы используете подход ООП, то следует применять библиотеку SPL. Дополнительно вы можете расширить классы своим функционалом.
  • Итератор GlobIterator имеет функцию предварительной фильтрации, а другие используют RegexIterator .