Манипуляции с директориями: функции PHP для работы с папками
Основные операции с папками
Цель: Наиболее универсальный и безопасный способ создания папки с проверкой её существования и рекурсивным созданием вложенных директорий.
Функция mkdir с флагом recursive = true позволяет одним вызовом создать цепочку папок. Предварительная проверка is_dir исключает ошибку, если папка уже существует.
$path = '/var/www/uploads/images/2025';
if (!is_dir($path)) {
mkdir($path, 0755, true);
}
Папка images/2025 создана (если не существовала).
Пояснение: флаг true указывает создавать все недостающие родительские директории. Права доступа 0755 устанавливаются только на последнюю созданную папку.
Типичные ошибки: Забытая проверка is_dir приводит к Warning: mkdir(): File exists. Неправильный путь или недостаточные права вызывают Permission denied. Рекомендуется использовать абсолютные пути или проверять is_writable.
Как создать одну папку без рекурсии?
Цель: Простое создание одной директории, когда родительская уже существует.
$dir = './temp';
if (!is_dir($dir)) {
mkdir($dir, 0755);
}
Проблема: если родительская папка отсутствует, mkdir выдаст ошибку. Решение - либо заранее создать родителя, либо использовать рекурсивный режим.
Как удалить пустую папку?
Цель: Очистка временных директорий после завершения работы скрипта.
$dir = './cache/temp';
if (is_dir($dir) && count(scandir($dir)) == 2) { // только . и ..
rmdir($dir);
}
Папка удалена, если она пуста.
Ошибки: rmdir удаляет только пустые директории. При наличии файлов или подпапок возникает Warning: rmdir(): Directory not empty.
Как удалить папку со всем содержимым?
Цель: Полная очистка директории, например, для сброса кэша.
function deleteDir($path) {
if (!is_dir($path)) return;
$items = array_diff(scandir($path), ['.', '..']);
foreach ($items as $item) {
$itemPath = $path . DIRECTORY_SEPARATOR . $item;
is_dir($itemPath) ? deleteDir($itemPath) : unlink($itemPath);
}
rmdir($path);
}
deleteDir('./cache');
Рекурсивная функция сначала удаляет все файлы и вложенные папки, затем саму корневую директорию.
Проблемы: Символические ссылки могут вести к неожиданному удалению. Для защиты проверяйте is_link и используйте readlink.
Как переименовать или переместить папку?
Цель: Организация файловой структуры, перенос проектов.
$old = './old_name';
$new = './new_name';
if (is_dir($old) && !is_dir($new)) {
rename($old, $new);
}
Функция rename работает как для файлов, так и для папок. Перемещение в другую директорию - аналогично, указав новый путь.
Ошибки: Если целевая папка уже существует, rename вернёт false (на некоторых системах может перезаписать). Всегда проверяйте существование цели.
Как получить список файлов и подпапок?
Цель: Обход содержимого для анализа или обработки.
$files = array_diff(scandir('/path/to/dir'), ['.', '..']);
print_r($files);
Array
(
[0] => file1.txt
[1] => subdir
[2] => image.png
)
Использование scandir с фильтрацией служебных элементов. Более гибкий вариант - DirectoryIterator.
Проблемы: scandir не сортирует результаты; для больших директорий используйте FilesystemIterator.
Как рекурсивно обойти все подпапки?
Цель: Поиск файлов по маске, подсчёт размеров, архивация.
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('./data', RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
echo $file->getPathname() . PHP_EOL;
}
Класс RecursiveDirectoryIterator обходит все вложенные директории. Флаг SKIP_DOTS исключает . и ...
Ошибки: Большие структуры потребляют память; используйте RecursiveIteratorIterator::LEAVES_ONLY для вывода только файлов.
Расширенные примеры работы с папками
1. Рекурсивное копирование директории
Код:
function copyDir($src, $dst) {
if (!is_dir($dst)) {
mkdir($dst, 0755, true);
}
$items = new FilesystemIterator($src, FilesystemIterator::SKIP_DOTS);
foreach ($items as $item) {
$target = $dst . DIRECTORY_SEPARATOR . $item->getFilename();
if ($item->isDir()) {
copyDir($item->getPathname(), $target);
} else {
copy($item->getPathname(), $target);
}
}
}
copyDir('./template', './backup');
Папка backup создана с полной копией содержимого template.
Пояснение: Функция использует FilesystemIterator для обхода, рекурсивно создаёт поддиректории. Для копирования файлов применяется copy.
2. Обход с фильтрацией по расширению
Код:
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('./docs', RecursiveDirectoryIterator::SKIP_DOTS)
);
$filtered = new RegexIterator($iterator, '/\.php$/i');
foreach ($filtered as $file) {
echo $file->getPathname() . PHP_EOL;
}
./docs/index.php ./docs/includes/config.php ...
Пояснение: RegexIterator выбирает только файлы, соответствующие регулярному выражению. Подходит для поиска определённых типов файлов.
3. Использование glob для поиска папок по маске
Код:
$directories = glob('/var/log/*/error*', GLOB_ONLYDIR);
print_r($directories);
Array
(
[0] => /var/log/apache2/error
[1] => /var/log/nginx/error
)
Пояснение: glob с флагом GLOB_ONLYDIR возвращает только папки, соответствующие шаблону. Быстрый способ без рекурсии.
4. Определение размера папки рекурсивно
Код:
function dirSize($path) {
$size = 0;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
$size += $file->getSize();
}
return $size;
}
echo 'Размер папки: ' . dirSize('./data') . ' байт';
Размер папки: 1234567 байт
Пояснение: Суммируется размер каждого файла. Для больших папок может быть медленным; альтернатива - системная команда du -sb.
5. Создание временной папки с уникальным именем
Код:
$tmpDir = sys_get_temp_dir() . '/myapp_' . uniqid();
mkdir($tmpDir, 0700);
echo $tmpDir;
register_shutdown_function(function() use ($tmpDir) {
array_map('unlink', glob($tmpDir . '/*'));
rmdir($tmpDir);
});
/tmp/myapp_64f3a2b1c0d9e
Пояснение: uniqid генерирует уникальный суффикс. Функция register_shutdown_function гарантирует очистку при завершении скрипта.
6. Работа с символическими ссылками
Код:
$target = '/var/www/html';
$link = '/home/user/site';
if (!is_link($link)) {
symlink($target, $link);
}
echo readlink($link);
/var/www/html
Пояснение: symlink создаёт мягкую ссылку. readlink возвращает путь, на который указывает ссылка. При рекурсивном удалении такие ссылки следует обрабатывать отдельно (не удалять по цепочке).