КаталогBuilderPHPDocs

Глава 7. Файлы и файловая система в PHP

Работа с файлами нужна почти в каждом PHP-проекте: загрузка изображений, кеширование, импорт CSV и XML, генерация логов, хранение временных данных. Ошибки в этой области часто приводят не только к сбоям, но и к проблемам безопасности.

Современное примечание. В старых скриптах часто писали напрямую в произвольные каталоги. Сегодня важно учитывать права доступа, open_basedir, временные директории, проверку расширений и защиту от загрузки исполняемых файлов.

Проверка существования файла

Перед чтением файла нужно убедиться, что он существует и доступен. Для этого используются file_exists(), is_file(), is_readable(). Если ожидается именно файл, лучше использовать is_file(), чтобы случайно не обработать каталог.

$path = __DIR__ . '/data.txt';

if (is_file($path) && is_readable($path)) {
    echo 'Файл можно читать';
}

Чтение файла

Для небольших файлов удобно использовать file_get_contents(). Для больших файлов лучше читать данные постепенно, чтобы не расходовать много памяти.

$content = file_get_contents($path);
echo htmlspecialchars($content);

Запись в файл

file_put_contents() подходит для простой записи. Флаг FILE_APPEND добавляет данные в конец файла. Для логов полезно добавлять дату и перевод строки.

$line = date('Y-m-d H:i:s') . ' Ошибка импорта' . PHP_EOL;
file_put_contents(__DIR__ . '/log.txt', $line, FILE_APPEND);

Открытие через fopen

Если нужно читать файл построчно, используется fopen(), fgets() и fclose(). Это особенно полезно для больших CSV-файлов.

$handle = fopen(__DIR__ . '/data.csv', 'r');

while (($line = fgets($handle)) !== false) {
    echo htmlspecialchars($line) . '<br>';
}

fclose($handle);

Загрузка файлов

Файл, загруженный через форму, сначала попадает во временную директорию. Его нужно проверить и переместить через move_uploaded_file(). Нельзя доверять имени файла, расширению и MIME-типу без дополнительной проверки.

if (isset($_FILES['image']) && is_uploaded_file($_FILES['image']['tmp_name'])) {
    $safeName = uniqid('img_', true) . '.jpg';
    move_uploaded_file($_FILES['image']['tmp_name'], __DIR__ . '/uploads/' . $safeName);
}

Безопасность

Самая опасная ошибка — разрешить пользователю загрузить PHP-файл в публичную директорию. Для изображений лучше проверять размер, расширение, MIME-тип и фактическое содержимое через getimagesize(). Имена файлов нужно генерировать самостоятельно, а не использовать исходное имя без очистки.

Пути и __DIR__

Относительные пути часто ломаются при подключении файлов из разных мест. Константа __DIR__ возвращает каталог текущего файла и делает путь предсказуемым.

require_once __DIR__ . '/config.php';

Файловый кеш

Простейший кеш можно хранить в файле. Главное — учитывать время жизни кеша и права на запись.

$cacheFile = __DIR__ . '/cache/menu.html';

if (is_file($cacheFile) && time() - filemtime($cacheFile) < 3600) {
    echo file_get_contents($cacheFile);
}

Типичные ошибки

  • Использование относительных путей без __DIR__.
  • Запись в каталог без проверки прав доступа.
  • Загрузка файлов без ограничения расширений и размера.
  • Вывод содержимого файла без экранирования.
  • Хранение временных файлов без очистки.

Итоги

Файловая система в PHP проста, но требует дисциплины. Проверяйте существование файлов, используйте безопасные пути, не доверяйте загруженным данным и не храните исполняемые файлы в публичных каталогах. Эти правила особенно важны для старых сайтов, где модули часто подключались вручную и работали с файлами напрямую.