PHP: Как правильно использовать fopen с флагами a (дозапись) и w (перезапись) в зависимости от существования файла?
Функция `fopen()` в PHP открывает файл или URL и возвращает дескриптор ресурса. Правильный выбор флага (режима открытия) критически важен для корректной работы с файлами.
## Основные флаги
**Флаг `w` (перезапись):**
— Открывает файл для записи.
— Если файл существует — **полностью очищает его содержимое** и начинает запись с начала.
— Если файл не существует — создаёт новый.
— Указатель устанавливается в начало файла.
**Флаг `a` (дозапись / append):**
— Открывает файл для записи.
— Если файл существует — **сохраняет существующее содержимое** и добавляет новые данные в конец.
— Если файл не существует — создаёт новый.
— Указатель всегда устанавливается в конец файла.
## Выбор флага в зависимости от существования файла
Типичная задача: если файл уже есть — дозаписать строку, если нет — создать и записать (например, с заголовком CSV).
php
$filename = ‘data.csv’;
$fileExists = file_exists($filename);
// Если файл не существует — используем ‘w’ и пишем заголовок
// Если существует — используем ‘a’ и только дозаписываем
$mode = $fileExists ? ‘a’ : ‘w’;
$handle = fopen($filename, $mode);
if ($handle === false) {
die(‘Не удалось открыть файл’);
}
// Если файл новый — добавляем заголовок CSV
if (!$fileExists) {
fputcsv($handle, [‘ID’, ‘Имя’, ‘Email’, ‘Дата’]);
}
// Дозаписываем строку данных
$row = [1, ‘Иван Петров’, ‘ivan@example.com’, date(‘Y-m-d’)];
fputcsv($handle, $row);
fclose($handle);
## Важные нюансы
1. **Гонка условий (race condition):** Между вызовом `file_exists()` и `fopen()` другой процесс может создать файл. Для критичных сценариев используйте блокировку через `flock()`.
2. **Флаг `x` как альтернатива:** Флаг `x` создаёт файл только если он НЕ существует, иначе возвращает `false`. Это атомарная операция, безопаснее для конкурентной среды.
3. **Права доступа:** Убедитесь, что PHP-процесс имеет права на запись в директорию.
4. **Буферизация:** После записи всегда вызывайте `fclose()` или `fflush()`, чтобы данные гарантированно попали на диск.
5. **Альтернатива — `file_put_contents()`:** Для простых случаев можно использовать флаги `FILE_APPEND` (аналог `a`) или без флага (аналог `w`):
php
// Дозапись
file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);
// Перезапись
file_put_contents($filename, $data, LOCK_EX);
## Итог
Используйте `file_exists()` перед `fopen()`, чтобы динамически выбирать режим: `’w’` для новых файлов (с записью заголовков) и `’a’` для существующих (дозапись данных). Для продакшн-кода добавляйте `flock()` для защиты от параллельной записи.
