Avatar ·

Как проверить существование папки в PHP: is_dir, file_exists или оба?

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

Я наткнулся на две функции: is_dir() и file_exists(). И теперь не понимаю, какую из них использовать. Вот мой код:

$path = '/uploads/images/';

// Вариант 1
if (is_dir($path)) {
    echo "Папка существует";
} else {
    mkdir($path, 0777, true);
}

// Вариант 2
if (file_exists($path)) {
    echo "Папка существует";
} else {
    mkdir($path, 0777, true);
}

Оба варианта вроде работают, но я заметил странное поведение. Если указать путь к файлу, а не к папке, file_exists() возвращает true, а is_dir() — false. Это сбивает с толку.

Ещё я читал, что file_exists() кеширует результаты, и это может привести к ошибкам. А is_dir() — нет. Но я не уверен.

Подскажите, как правильно проверять существование именно директории? Нужно ли использовать обе функции вместе? Или достаточно одной? И что делать с кешированием?

Заранее спасибо за помощь!

<<>>

Используйте is_dir() — это правильный и надёжный способ

Для проверки существования именно директории (папки) в PHP используйте функцию is_dir(). Она возвращает true только если переданный путь является существующей директорией. file_exists() же возвращает true для любого существующего элемента файловой системы — будь то файл, директория или символическая ссылка.

Почему file_exists() не подходит?

Представьте ситуацию: у вас есть файл /uploads/images.txt, а вы проверяете file_exists('/uploads/images/'). PHP может вернуть true из-за особенностей работы с путями (например, если включены магические кавычки или есть символическая ссылка). Это приведёт к тому, что вы не создадите директорию, а потом попытаетесь записать в неё файл — получите ошибку.

Надо ли использовать обе функции?

Нет, не надо. is_dir() полностью решает задачу. Однако есть один важный нюанс — кеширование результатов. PHP кеширует результаты вызовов функций file_exists(), is_dir(), is_file() и других для повышения производительности. Если в процессе выполнения скрипта вы создаёте или удаляете директорию, закешированный результат может устареть.

Пример проблемы с кешированием:

// Первая проверка — директории нет
if (!is_dir('/tmp/mydir')) {
    mkdir('/tmp/mydir', 0777, true);
}

// Вторая проверка — PHP может вернуть false, 
// потому что закешировал результат первого вызова
if (is_dir('/tmp/mydir')) {
    echo "Директория существует"; // Этот код может не выполниться!
}

Решение проблемы с кешированием

Используйте функцию clearstatcache() перед повторной проверкой:

// Создаём директорию
if (!is_dir('/tmp/mydir')) {
    mkdir('/tmp/mydir', 0777, true);
}

// Очищаем кеш
clearstatcache();

// Теперь проверка будет точной
if (is_dir('/tmp/mydir')) {
    echo "Директория успешно создана";
}

Рекомендуемый паттерн для проверки и создания директории

$path = '/uploads/images/';

// Проверяем существование директории
if (!is_dir($path)) {
    // Создаём рекурсивно (создаст все родительские папки)
    if (mkdir($path, 0755, true)) {
        echo "Директория создана: $path";
    } else {
        echo "Ошибка создания директории";
    }
} else {
    echo "Директория уже существует";
}

// Если дальше планируете работать с файлами — очистите кеш
clearstatcache();

Дополнительные советы

  • Права доступа: используйте 0755 для директорий (владелец может всё, остальные — читать и выполнять). 0777 — слишком опасно.
  • Рекурсивное создание: третий параметр true в mkdir() создаёт все промежуточные директории, если их нет.
  • Проверка после создания: всегда проверяйте результат mkdir() — он возвращает false при ошибке.
  • Безопасность: никогда не доверяйте пользовательскому вводу для путей. Используйте basename() или белые списки.

Итог

Используйте только is_dir() для проверки существования директории. file_exists() здесь не нужен. Если в скрипте несколько раз проверяется один и тот же путь, а между проверками происходят изменения — используйте clearstatcache().

<<>>

Альтернативный подход: проверка через file_exists + is_dir

Хотя is_dir() — основной инструмент, некоторые разработчики используют комбинацию для надёжности:

$path = '/uploads/images/';

if (file_exists($path) && is_dir($path)) {
    echo "Директория существует";
} else {
    mkdir($path, 0755, true);
}

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

Когда это может пригодиться?

  • Если вы ожидаете, что по пути может быть файл, а не папка, и хотите явно обработать эту ситуацию.
  • При отладке — чтобы точно знать, что вернула каждая функция.

Но помните:

Этот подход не решает проблему кеширования. Если вы создали директорию между вызовами file_exists() и is_dir(), результат может быть некорректным. В современных проектах лучше использовать только is_dir() с clearstatcache() при необходимости.

Ещё один вариант — использовать is_dir() с проверкой на ошибки через @ (подавление ошибок), но это считается плохой практикой.