Как проверить, существует ли файл или директория в PHP
Основные подходы к проверке существования в файловой системе
Наиболее универсальное и часто используемое решение - функция file_exists(). Она возвращает true, если файл или директория существуют. Однако из-за кэширования результатов предыдущих вызовов рекомендуется перед проверкой сбрасывать кэш с помощью clearstatcache().
<?php
$filename = '/var/www/data/config.php';
clearstatcache(true, $filename);
if (file_exists($filename)) {
echo 'Файл или директория существует';
} else {
echo 'Объект не найден';
}
?>
Основное преимущество - простота и работа как с файлами, так и с директориями. Недостаток: результат может устареть, если за время между проверкой и использованием объект был удалён.
Типичная ошибка: при многократной проверке одного и того же пути в рамках одного запроса file_exists() может вернуть кэшированное значение. Решение - вызывать clearstatcache() до каждой проверки или использовать is_file()/is_dir(), которые работают по тому же принципу, но специфичны для типа объекта.
Как проверить, что по указанному пути находится именно обычный файл?
Функция is_file() возвращает true только для файлов (не директорий, не символических ссылок без учёта их цели). Пример:
<?php
clearstatcache();
$path = '/tmp/log.txt';
if (is_file($path)) {
echo 'Это файл';
} else {
echo 'Это не файл или объект не существует';
}
?>
Используется, когда требуется именно файл, а не директория или ссылка.
Ошибка: is_file() для символической ссылки на файл возвращает true (если цель существует). Для проверки самой ссылки используйте is_link().
Как проверить существование директории?
is_dir() - аналог для каталогов:
<?php
$dir = __DIR__ . '/uploads';
if (is_dir($dir)) {
echo 'Директория существует';
} else {
echo 'Директория не найдена';
}
?>
Цель: убедиться, что путь ведет к каталогу перед созданием файлов внутри.
Как проверить, существует ли файл, который может быть подключён через include?
Функция stream_resolve_include_path() проверяет, найдётся ли файл в путях include:
<?php
$filename = 'config.php';
$fullPath = stream_resolve_include_path($filename);
if ($fullPath !== false) {
echo 'Файл будет найден по пути: ' . $fullPath;
} else {
echo 'Файл не доступен для подключения';
}
?>
Полезна для автозагрузчика или проверки перед require_once.
Проблема: функция не проверяет права доступа на чтение, только существование в путях include.
Как получить информацию о файле и одновременно проверить его существование?
Использование stat() или fileatime() с последующей проверкой на false:
<?php
$stat = @stat('/etc/hosts');
if ($stat !== false) {
echo 'Файл существует, размер: ' . $stat['size'] . ' байт';
} else {
echo 'Файл не существует или недоступен';
}
?>
Подходит, если нужна дополнительная информация (размер, время изменения).
Ошибка: при отсутствии файла stat() выдаёт предупреждение, поэтому используется оператор подавления ошибок @. Решение: предварительно проверить file_exists() или использовать clearstatcache().
Как проверить существование файла и его доступность для чтения?
Попытка открыть файл через fopen() в режиме 'r':
<?php
$handle = @fopen('/var/log/syslog', 'r');
if ($handle) {
fclose($handle);
echo 'Файл существует и доступен для чтения';
} else {
echo 'Файл не существует или нет прав на чтение';
}
?>
Используется, когда необходимо не только существование, но и возможность чтения.
Минус: создаёт дескриптор файла, который нужно закрыть. При большом количестве проверок может быть накладным.
Как учесть возможное кэширование при повторных проверках?
Проблема функций файловой системы - кэширование результатов. Решение - вызов clearstatcache() перед каждой проверкой или для указанного пути:
<?php
// Первая проверка
$first = file_exists('/tmp/data.lock');
// ... какой-то код, возможно меняющий файл
clearstatcache(true, '/tmp/data.lock');
$second = file_exists('/tmp/data.lock');
?>
Обязательно для длительных скриптов.
Ошибка: забыть сбросить кэш. Решение: всегда вызывать clearstatcache() перед серией проверок одного пути.
Расширенные примеры проверки существования
Далее приведены более сложные и редкие сценарии использования проверки существования в PHP.
Пример 1. Проверка с использованием кэширования и массовых проверок
Сброс кэша только для конкретного пути, чтобы не затрагивать остальную статистику:
<?php
$paths = ['config.php', 'lib.php', 'cache/'];
$results = [];
foreach ($paths as $path) {
clearstatcache(true, $path);
if (is_file($path)) {
$results[$path] = 'file';
} elseif (is_dir($path)) {
$results[$path] = 'dir';
} else {
$results[$path] = 'not found';
}
}
print_r($results);
?>
Array
(
[config.php] => file
[lib.php] => file
[cache/] => dir
)
Пояснение: для каждого пути выполняется индивидуальный сброс кэша, что гарантирует свежесть данных.
Пример 2. Проверка существования файлов по маске (glob)
Комбинирование glob() и file_exists() для проверки наличия файлов с определённым расширением:
<?php
$pattern = __DIR__ . '/logs/*.log';
$files = glob($pattern);
if ($files) {
echo 'Найдено ' . count($files) . ' лог-файлов';
} else {
echo 'Нет файлов с расширением .log';
}
?>
Найдено 3 лог-файлов
Пояснение: функция glob() возвращает только существующие файлы, что избавляет от дополнительных проверок.
Пример 3. Проверка удалённых файлов (через URL)
Проверка существования файла на удалённом сервере (HTTP/HTTPS) с помощью get_headers():
<?php
$url = 'https://example.com/update.xml';
$headers = @get_headers($url);
if (stripos($headers[0], '200 OK') !== false) {
echo 'Файл существует на удалённом сервере';
} else {
echo 'Файл не найден (HTTP ' . $headers[0] . ')';
}
?>
Файл существует на удалённом сервере
Пояснение: используется для проверки доступности обновлений или внешних ресурсов.
Пример 4. Обход символьных ссылок
Проверка существования цели символьной ссылки с разрешением конечного файла:
<?php
$link = '/tmp/symlink_to_config';
if (is_link($link)) {
$real = realpath($link);
if ($real !== false) {
echo 'Ссылка ведёт на: ' . $real . ' - ';
echo is_file($real) ? 'файл' : (is_dir($real) ? 'директория' : 'неизвестный тип');
} else {
echo 'Цель ссылки не существует';
}
} else {
echo 'Это не символьная ссылка';
}
?>
Ссылка ведёт на: /etc/config.ini - файл
Пояснение: realpath() разрешает ссылку и проверяет существование конечного объекта.
Пример 5. Использование итератора DirectoryIterator для проверки существования
Проверка, существует ли файл в конкретной директории, с помощью итератора:
<?php
$dir = new DirectoryIterator('/var/www/images');
$targetFile = 'logo.png';
$found = false;
foreach ($dir as $fileinfo) {
if ($fileinfo->isFile() && $fileinfo->getFilename() === $targetFile) {
$found = true;
echo 'Файл найден, размер: ' . $fileinfo->getSize() . ' байт';
break;
}
}
if (!$found) {
echo 'Файл отсутствует в директории';
}
?>
Файл найден, размер: 123456 байт
Пояснение: позволяет дополнительно получить свойства файла без отдельного вызова stat().
Пример 6. Пакетная проверка с учётом прав доступа
Проверка существования и прав на запись для нескольких файлов с записью проблем в массив:
<?php
$files = ['data.csv', 'config.ini', 'temp/'];
$errors = [];
foreach ($files as $file) {
clearstatcache(true, $file);
if (!file_exists($file)) {
$errors[] = "$file не существует";
continue;
}
// Дополнительная проверка на запись
if (is_writable($file)) {
continue;
}
$errors[] = "$file недоступен для записи";
}
if (empty($errors)) {
echo 'Все объекты существуют и доступны для записи';
} else {
echo implode('\n', $errors);
}
?>
data.csv не существует config.ini недоступен для записи
Пояснение: каждая ошибка отдельно обрабатывается, что удобно для отладки.