Файлы в PHP: что нужно знать до первой записи на диск
Прежде чем читать и писать файлы в PHP, разберитесь с путями, правами и режимами открытия. Один неверный флаг — и вы затрёте данные или получите пустой ответ без ошибки.

Работа с файлами в PHP выглядит просто: file_get_contents, file_put_contents, и готово. Но именно здесь новички теряют данные молча: файл не открылся, а функция вернула false, которое никто не проверил. К концу этой статьи вы будете уметь читать и писать файлы, понимать разницу между режимами открытия и не удивляться, почему скрипт «ничего не делает». Разберём на PHP 8.x — примеры рабочие и на 7.4, но проверять ошибки в 8.x стало строже.
Что нужно иметь до начала
- PHP 8.x (проверьте командой
php -v) — установленный локально или на хостинге; - доступ к каталогу, в который вы будете писать: у процесса PHP должны быть права на запись. На хостинге это обычно каталог вашего сайта, на локальной машине — любая ваша папка;
- понимание, где физически лежит ваш скрипт: от этого зависят относительные пути;
- текстовый редактор и возможность запустить скрипт — через
php script.phpв терминале или открыв в браузере.
Проверьте права заранее. Если PHP не может писать в каталог, вы узнаете об этом не текстом ошибки, а тихим false из функции записи.
Чтение файла целиком
Самый частый случай — прочитать текстовый файл в строку. Для этого есть file_get_contents.
<?php
// PHP 8.x
$path = __DIR__ . '/data.txt';
$content = file_get_contents($path);
if ($content === false) {
// Файла нет, нет прав на чтение или путь неверный
echo "Не удалось прочитать файл: $path\n";
exit(1);
}
echo $content;
Обратите внимание на две вещи. Первая — __DIR__ вместо голого 'data.txt'. Это константа с абсолютным путём к каталогу текущего скрипта, и она избавляет от главной боли новичка: относительный путь считается не от файла скрипта, а от рабочего каталога процесса, который может быть каким угодно.
Вторая — строгая проверка === false. Пустой файл вернёт пустую строку '', которая в мягком сравнении равна false. Если написать просто if (!$content), вы спутаете пустой файл с ошибкой чтения.
Читаем построчно, а не целиком
Если файл большой (логи, выгрузки на сотни мегабайт), file_get_contents загонит его весь в память. Читайте построчно через дескриптор:
<?php
// PHP 8.x
$path = __DIR__ . '/big.log';
$handle = fopen($path, 'r'); // 'r' — только чтение
if ($handle === false) {
echo "Не открылся файл: $path\n";
exit(1);
}
while (($line = fgets($handle)) !== false) {
// fgets возвращает строку с символом переноса в конце
echo rtrim($line) . "\n";
}
fclose($handle); // дескриптор нужно закрывать вручную
Здесь важна проверка !== false: пустая строка в файле — это валидная строка, а конец файла fgets отмечает именно false.
Запись в файл
Для записи целой строки в файл есть file_put_contents. По умолчанию она перезаписывает файл целиком:
<?php
// PHP 8.x
$path = __DIR__ . '/out.txt';
$bytes = file_put_contents($path, "Первая строка\n");
if ($bytes === false) {
echo "Не удалось записать: $path\n";
exit(1);
}
echo "Записано байт: $bytes\n";
Если файл уже существовал, его прежнее содержимое пропало без предупреждения. Чтобы дописывать в конец, а не затирать, передайте флаг FILE_APPEND:
<?php
// PHP 8.x — дописываем строку в конец
$path = __DIR__ . '/out.txt';
file_put_contents($path, "Ещё строка\n", FILE_APPEND);
Режимы открытия файла — главная развилка
Когда вы работаете через fopen, второй аргумент решает всё: затрёте вы файл или допишете, создастся ли он, упадёт ли открытие. Путаница в режимах — причина большинства «данные исчезли» у новичков.
| Режим | Что делает | Если файла нет | Указатель |
|---|---|---|---|
r | только чтение | ошибка | в начале |
r+ | чтение и запись | ошибка | в начале |
w | только запись, обнуляет файл | создаёт | в начале |
w+ | чтение и запись, обнуляет файл | создаёт | в начале |
a | только запись в конец | создаёт | в конце |
a+ | чтение и запись в конец | создаёт | в конце |
Главная ловушка — режим w. Он обнуляет файл в момент открытия, ещё до того, как вы что-то записали. Открыли на w, а потом решили сначала прочитать старое содержимое — поздно, его уже нет.
Если вы не уверены, какой режим взять, начните с вопроса: должно ли старое содержимое сохраниться? Если да — этоaилиa+, но неw.
Проверки перед работой
Перед тем как открыть файл, полезно спросить у системы, что с ним вообще:
file_exists($path)— существует ли файл или каталог;is_readable($path)— можно ли читать;is_writable($path)— можно ли писать;is_file($path)— это именно файл, а не каталог.
Но не превращайте проверку в защиту. Между file_exists и fopen файл может исчезнуть или измениться (гонка состояний). Проверка помогает выдать понятное сообщение, а не заменяет обработку ошибки при самом открытии.
Если не получилось
Вот что вы реально увидите и что с этим делать.
- Warning: file_get_contents(...): failed to open stream: No such file or directory — путь неверный. В 90% случаев виноват относительный путь. Замените на
__DIR__ . '/имя'и выведите итоговый путь черезecho, чтобы увидеть, куда PHP реально смотрит. - failed to open stream: Permission denied — у процесса PHP нет прав на чтение или запись. На Linux-хостинге проверьте владельца и права каталога; для записи каталогу обычно нужен доступ на запись для пользователя, под которым работает PHP.
- Функция вернула
false, но ошибки нет — скорее всего, ошибки подавлены (оператор@перед вызовом или отключённый вывод предупреждений). Уберите@и включите отображение ошибок на время отладки. - Записали, но файл пустой — если работаете через
fopen/fwrite, забылиfclose. Часть данных остаётся в буфере и не попадает на диск. Всегда закрывайте дескриптор. - Кракозябры вместо русского текста — это не ошибка файлов, а кодировка. PHP читает байты как есть. Убедитесь, что файл в UTF-8 и отдаётся с заголовком
Content-Type: text/plain; charset=utf-8, если выводите в браузер.
Что делать дальше
Когда базовое чтение и запись работают, следующий шаг — блокировки. Если два процесса пишут в один файл одновременно, данные перемешаются. За это отвечает flock — отдельная тема, здесь мы её не разворачивали. Также посмотрите на функции fread для чтения бинарных данных порциями и SplFileObject — объектную обёртку над файлом, которая удобнее для построчной обработки. Полный список файловых функций и точное поведение каждого режима смотрите в разделе Filesystem официальной документации PHP для вашей версии.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: PHP Manual — Filesystem Functions, PHP Manual — fopen
Частые вопросы
У меня PHP 7.4, а не 8. Примеры сработают?
Почему мой файл затёрся, хотя я хотел дописать?
Что вернёт file_get_contents для пустого файла?
Нужно ли всегда закрывать файл через fclose?
Скрипт пишет 'Permission denied' на хостинге, что делать?
Как узнать, по какому пути PHP на самом деле ищет файл?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.