Создать папку в PHP, если её нет: 5 лучших способов в 2025

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Создать папку в PHP, если её нет: эволюция одного вопроса

Если вы когда-нибудь писали скрипт, который загружает файлы, сохраняет кэш или генерирует отчёты, то наверняка сталкивались с ситуацией: «А папки-то нет!». Ошибка, которая валит весь скрипт, а пользователь видит белый экран или (что ещё хуже) непонятную ошибку PHP.

Вопрос «Create a folder if it doesn't already exist» на Stack Overflow собирает тысячи просмотров. И неспроста. Казалось бы, что сложного? Но дьявол, как всегда, в деталях: права доступа, рекурсия, обработка исключений, кодировка имени папки. В 2025 году, когда проекты становятся всё сложнее, а требования к безопасности — жёстче, правильное создание директорий — это база, которую обязан знать каждый PHP-разработчик.

В этой статье мы разберём 5 лучших практик создания папки в PHP, если она не существует. От простого решения для новичков до промышленного кода с защитой от race condition. Поехали!

Почему просто mkdir() — это плохо? (история одной ошибки)

В начале пути многие пишут так:

<?php
mkdir('/path/to/my/folder');
?>

И получают:

  • Warning: mkdir(): No such file or directory — если родительская папка не существует.
  • Warning: mkdir(): File exists — если папка уже есть.

Оба предупреждения — это не просто «жёлтый текст». В production-режиме они могут превратиться в фатальные ошибки, если включён строгий режим отчёта ошибок. А ещё это дыра в безопасности: злоумышленник может создать папку с тем же именем раньше вашего скрипта (race condition).

Поэтому современный подход — это всегда проверка, рекурсия и контроль прав.

Метод 1: Классика с is_dir() и mkdir() (для новичков)

Самый простой и понятный способ — сначала проверить, существует ли папка, а потом создать её.

<?php
$folder = '/var/www/uploads/images';

if (!is_dir($folder)) {
    mkdir($folder, 0755, true);
    echo "Папка создана!";
} else {
    echo "Папка уже существует.";
}
?>

Что тут важно:

  • is_dir() — возвращает true, если путь существует и является директорией.
  • mkdir($folder, 0755, true) — третий параметр true включает рекурсивное создание. Если родительской папки нет, PHP создаст всю цепочку (/var/www/uploads/images → создаст uploads, потом images).
  • 0755 — права доступа: владелец может всё, остальные — читать и выполнять.

Минус: этот код не защищён от race condition. Если два запроса одновременно проверят is_dir() и оба попытаются создать папку, второй вызовет предупреждение.

Метод 2: Промышленный подход с @mkdir() и проверкой ошибок

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

<?php
$folder = '/var/www/uploads/images';

if (!is_dir($folder)) {
    // Подавляем warning, если папка уже существует
    if (!@mkdir($folder, 0755, true) && !is_dir($folder)) {
        throw new \RuntimeException('Не удалось создать папку: ' . $folder);
    }
}
?>

Почему это лучше?

  • Мы подавляем warning, но не игнорируем ошибку — если создать не удалось, выбрасывается исключение.
  • Двойная проверка !is_dir($folder) после mkdir() защищает от race condition: если другой процесс создал папку между нашей проверкой и вызовом mkdir(), мы не упадём.

Внимание: оператор @ снижает производительность, так как PHP всё равно генерирует ошибку, но скрывает её. В высоконагруженных проектах лучше использовать метод 3.

Метод 3: Современный подход с исключениями (PHP 8+)

С выходом PHP 8.0 появилась возможность использовать try-catch с mkdir() без подавления ошибок. Просто включите строгую типизацию и используйте \Throwable.

<?php
declare(strict_types=1);

function createFolder(string $path, int $permissions = 0755): bool
{
    if (is_dir($path)) {
        return true;
    }

    try {
        if (!mkdir($path, $permissions, true) && !is_dir($path)) {
            throw new \RuntimeException('Не удалось создать директорию');
        }
        return true;
    } catch (\Throwable $e) {
        // Логируем ошибку
        error_log('Ошибка создания папки: ' . $e->getMessage());
        return false;
    }
}

// Использование
if (createFolder('/var/www/uploads/images')) {
    echo "Готово!";
} else {
    echo "Ошибка!";
}
?>

Преимущества:

  • Чистый код без @.
  • Исключения можно обрабатывать централизованно.
  • Функция возвращает bool — удобно для условных конструкций.

Метод 4: Рекурсивное создание с безопасными правами

Иногда нужно создать глубокую вложенность папок, но при этом задать разные права для разных уровней. Например, корневая папка должна быть 0755, а вложенная — 0777 (для загрузки файлов).

<?php
function createDirectoryRecursive(string $path, int $permissions = 0755): void
{
    $parent = dirname($path);
    
    // Сначала создаём родительскую папку, если её нет
    if (!is_dir($parent)) {
        createDirectoryRecursive($parent, $permissions);
    }
    
    // Теперь создаём текущую папку
    if (!is_dir($path)) {
        if (!mkdir($path, $permissions) && !is_dir($path)) {
            throw new \RuntimeException("Не удалось создать: $path");
        }
        // Принудительно устанавливаем права (на случай umask)
        chmod($path, $permissions);
    }
}

// Пример: создаём /var/www/uploads/2025/01/15
createDirectoryRecursive('/var/www/uploads/2025/01/15', 0777);
?>

Важный нюанс: mkdir() с флагом true создаёт все папки, но права доступа применяются только к последней. Если вам нужно, чтобы все папки имели одинаковые права, используйте рекурсию вручную или после создания выполните chmod().

Блоги

Рекомендаций по книгам