Как создать папку в PHP, если она еще не существует?
Использование is_dir() и mkdir() с рекурсивным режимом
Ваш подход в целом правильный, но есть несколько улучшений, которые сделают код более надежным и элегантным. Главная проблема вашего кода — использование file_exists() вместо is_dir(). Дело в том, что file_exists() возвращает true не только для папок, но и для файлов. Если по какому-то совпадению в системе уже есть файл с именем, совпадающим с именем будущей папки, вы получите ошибку.
Правильный вариант:
<?php
$user_id = 123;
$upload_dir = wp_upload_dir();
$user_folder = $upload_dir['basedir'] . '/user_' . $user_id . '/';
if (!is_dir($user_folder)) {
mkdir($user_folder, 0755, true); // 0755 — права доступа, true — рекурсивное создание
}
// Теперь можно безопасно копировать файл
move_uploaded_file($temp_file, $user_folder . '/avatar.jpg');
?>
Ключевые моменты:
is_dir()— проверяет, существует ли именно директория, а не просто файл с таким именем.mkdir($path, $permissions, $recursive)— третий параметрtrueвключает рекурсивное создание. Это значит, что если нужно создать/uploads/user_123/, а папки/uploads/нет, она тоже будет создана автоматически.- Права доступа 0755 — стандартные права для веб-директорий: владелец может всё, остальные — читать и выполнять.
Как создать вложенные папки (например, по дате)
Если вам нужно создавать структуру вида /uploads/2023/12/, рекурсивный режим справится с этим одной строкой:
<?php
$year = date('Y');
$month = date('m');
$path = $upload_dir['basedir'] . '/' . $year . '/' . $month . '/';
if (!is_dir($path)) {
mkdir($path, 0755, true);
}
?>
Дополнительные рекомендации для WordPress
В WordPress есть встроенная функция wp_mkdir_p(), которая делает то же самое, но с учетом особенностей CMS:
<?php
if (!wp_mkdir_p($user_folder)) {
// Обработка ошибки, если папку не удалось создать
wp_die('Не удалось создать директорию для загрузок.');
}
?>
Также рекомендую проверять, удалось ли создать папку, с помощью проверки возвращаемого значения mkdir() или wp_mkdir_p(). Если функция вернула false, значит, что-то пошло не так (нет прав на запись, превышен лимит inode и т.д.).
Почему не стоит подавлять ошибки через @?
Оператор @ подавляет все ошибки, включая критические. Если у вас закончилось место на диске или нет прав, вы не узнаете об этом и будете думать, что всё работает. Всегда лучше явно проверять условие и обрабатывать ошибки.
Альтернативный подход: использование исключений (для современных проектов)
Если вы работаете с PHP 7+ и предпочитаете современный стиль, можно использовать исключения вместо условных операторов. Это особенно удобно в ООП-проектах:
<?php
function ensureDirectoryExists(string $path, int $permissions = 0755): void {
if (is_dir($path)) {
return; // Папка уже существует
}
// Пытаемся создать папку
if (!mkdir($path, $permissions, true) && !is_dir($path)) {
throw new \RuntimeException(sprintf(
'Не удалось создать директорию "%s". Проверьте права доступа.',
$path
));
}
}
// Использование:
try {
ensureDirectoryExists('/path/to/user_123/');
// Дальнейшая работа с файлами...
} catch (\RuntimeException $e) {
echo 'Ошибка: ' . $e->getMessage();
// Логирование ошибки
}
?>
Плюсы этого подхода:
- Код становится чище и читаемее.
- Ошибки обрабатываются централизованно через
try-catch. - Легко добавить дополнительную логику (например, уведомление администратора).
Минус: для простых скриптов может быть избыточным. Выбирайте подход под свою задачу.