dir()
Работа с директориями в PHP: открытие, чтение, создание и удаление папок, а также замена устаревшей функции dir() современными инструментами.
Введение
В этой главе рассматривается работа с директориями в PHP: их открытие, чтение, создание и удаление, а также упразднённая функция dir() и её современные замены. PHP поставляется с полным набором встроенных функций для этих задач, поэтому вы можете получить список содержимого папки, обойти дерево директорий или удалить временные файлы без обращения к операционной системе.
Функции для работы с директориями чаще всего нужны при создании менеджера загрузок, формировании списка файлов для страницы скачивания, очистке временных файлов или сканировании папки с шаблонами или изображениями во время выполнения программы.
Работа с функциями директорий в PHP
PHP объединяет операции с директориями в несколько процедурных функций, а также предоставляет объектно-ориентированный класс DirectoryIterator. Наиболее распространённые из них:
opendir()— открывает директорию и возвращает дескриптор (ресурс, из которого выполняется чтение)readdir()— читает следующий элемент из открытого дескриптора директорииclosedir()— закрывает дескриптор директории и освобождает ресурсscandir()— считывает все элементы в array за один вызовglob()— возвращает пути, соответствующие шаблону подстановочных символовmkdir()— создаёт новую директориюrmdir()— удаляет пустую директориюis_dir()— проверяет, является ли путь директорией
Каждый листинг директории в PHP включает специальные записи . (сама директория) и .. (её родительская директория). Их почти всегда нужно пропускать — забыть об этом является распространённой причиной ошибок.
Использование opendir() и readdir() для чтения директории
opendir() открывает директорию и возвращает дескриптор директории. Затем вы передаёте этот дескриптор в readdir(), которая возвращает имя следующего элемента при каждом вызове и false, когда элементы заканчиваются. Всегда закрывайте дескриптор с помощью closedir() после завершения работы.
Поскольку readdir() может законно возвращать "0" (файл с именем 0), сравнивайте результат с !== false, а не с помощью нестрогой проверки, чтобы ложное имя файла не было принято за конец списка.
Пример использования opendir() и readdir() в PHP
<?php
$dir = "/path/to/directory";
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if ($file === "." || $file === "..") {
continue; // skip self and parent
}
echo "filename: " . $file . PHP_EOL;
}
closedir($dh);
}
}Для директории, содержащей a.txt, b.log и report.csv, вывод будет следующим:
filename: b.log
filename: report.csv
filename: a.txtПорядок не является алфавитным — readdir() возвращает элементы в том порядке, в котором их хранит файловая система. Если нужен предсказуемый порядок, используйте scandir() (который сортирует результаты) или отсортируйте их самостоятельно.
Использование scandir() для получения списка директории за один раз
scandir() считывает всё содержимое директории в array за один вызов и — в отличие от readdir() — по умолчанию сортирует результат в алфавитном порядке. Это наиболее удобный способ получить отсортированный список файлов. Он по-прежнему включает . и .., поэтому фильтруйте их, когда нужны только реальные файлы.
Использование функции scandir() в PHP
<?php
$dir = "/path/to/directory";
$files = scandir($dir);
print_r($files);Для директории, содержащей a.txt, b.log и report.csv, вывод будет следующим:
Array
(
[0] => .
[1] => ..
[2] => a.txt
[3] => b.log
[4] => report.csv
)Передайте SCANDIR_SORT_DESCENDING в качестве третьего аргумента для сортировки в обратном порядке или SCANDIR_SORT_NONE для отключения сортировки (что быстрее для очень больших директорий).
Поиск файлов с помощью glob()
Когда нужны только файлы, соответствующие шаблону — все файлы .txt или всё, что начинается с report — glob() является наиболее удобным вариантом. Функция принимает шаблон подстановочных символов и возвращает array соответствующих путей:
<?php
foreach (glob("/path/to/directory/*.txt") as $file) {
echo $file . PHP_EOL;
}Если только a.txt соответствует нашей тестовой директории, вывод будет таким:
/path/to/directory/a.txtВ отличие от scandir(), glob() не включает . и .. и возвращает полные пути, а не просто имена файлов.
Создание директорий с помощью mkdir()
Функция mkdir() создаёт новую директорию. Первый аргумент — путь, второй устанавливает права доступа (восьмеричное значение, например 0755), а необязательный третий аргумент, равный true, рекурсивно создаёт отсутствующие родительские директории.
Использование функции mkdir() в PHP
mkdir("/path/to/my/new/directory", 0755, true);Без флага true функция mkdir() завершится с предупреждением, если родительская директория ещё не существует. В Unix-подобных системах фактические права доступа также зависят от umask процесса.
Удаление директорий с помощью rmdir()
Функция rmdir() удаляет директорию. Она принимает путь к директории, которую нужно удалить.
Использование функции rmdir() в PHP
rmdir("/path/to/my/new/directory");Примечание: rmdir() удаляет только пустые директории. Чтобы удалить директорию, содержащую файлы, сначала удалите файлы (и все поддиректории) — например, перебрав содержимое с помощью scandir() и вызвав unlink() для каждого файла.
Современная замена: DirectoryIterator
Для объектно-ориентированного кода класс SPL DirectoryIterator является рекомендуемым способом обхода директории. Он поддерживает итерацию с foreach и предоставляет подробную информацию о каждом элементе — имя, размер, тип и время изменения — без отдельных вызовов функций:
<?php
foreach (new DirectoryIterator("/path/to/directory") as $entry) {
if ($entry->isDot()) {
continue; // skip "." and ".."
}
echo $entry->getFilename() . PHP_EOL;
}Для директории, содержащей a.txt, b.log и report.csv, вывод будет следующим:
b.log
report.csv
a.txtМетод isDot() удобно пропускает . и .. в одной проверке. Для обхода всего дерева директорий, включая подпапки, используйте RecursiveDirectoryIterator вместе с RecursiveIteratorIterator.
Устаревшая функция dir()
Устарело: Функция
dir()была объявлена устаревшей в PHP 7.4 и удалена в PHP 8.0. Вместо неё используйтеDirectoryIteratorилиscandir(). Пример ниже приведён только для поддержки старого кода.
Функция dir() возвращает object Directory, предоставляющий объектно-ориентированный способ чтения содержимого директории. В отличие от scandir(), возвращающего простой array, функция dir() возвращает object с методами read(), rewind() и close(). Обратите внимание, что dir() не является псевдонимом scandir() — они служат разным целям и возвращают разные типы данных.
Использование функции dir() в PHP (устаревший вариант)
<?php
$dir = dir("/path/to/directory");
while (($file = $dir->read()) !== false) {
echo "filename: " . $file . PHP_EOL;
}
$dir->close();Заключение
PHP предлагает несколько способов работы с директориями. Используйте scandir() или glob() для быстрого получения отсортированных списков, набор opendir()/readdir()/closedir() для потоковой обработки элементов по одному, а DirectoryIterator — для чистого объектно-ориентированного обхода. Создавайте и удаляйте папки с помощью mkdir() и rmdir(), а при необходимости спуска в поддиректории используйте RecursiveDirectoryIterator. Для более широкого ознакомления с работой с файловой системой обратитесь к главам PHP Directory и PHP Filesystem.