Работа с файлами: способы изменения содержимого в PHP

Раздел: Разработка на PHP -> Работа с файлами

Способы обновления содержимого файлов в PHP

При разработке на PHP часто возникает необходимость изменить данные в существующем файле – добавить новую строку, заменить часть текста или полностью перезаписать файл. В этой статье рассматриваются различные подходы, от простых до продвинутых, с примерами кода и разбором возникающих проблем.

Как выполнить полную перезапись файла с минимальным риском?

Основное эффективное решение – использование функции file_put_contents() с флагом LOCK_EX для блокировки файла во время записи. Это гарантирует целостность данных при одновременном доступе.


<?php
$file = 'log.txt';
$newContent = "Новая строка данных\n";
// Флаг LOCK_EX предотвращает одновременную запись другими процессами
if (file_put_contents($file, $newContent, LOCK_EX) !== false) {
    echo 'Файл успешно перезаписан.';
} else {
    echo 'Ошибка записи.';
}
?>
  

Index php path (пути файлов в php)

Пояснение: file_put_contents открывает файл, записывает данные и закрывает его. Флаг FILE_APPEND (не используется здесь) позволяет добавлять данные, а не перезаписывать. LOCK_EX – эксклюзивная блокировка, исключающая одновременную запись.

Возможные проблемы:

  • Файл не существует – будет создан, если каталог доступен для записи.
  • Недостаточно прав – возникает ошибка, нужно проверить chmod.
  • При большом объёме данных (сотни мегабайт) file_put_contents может потреблять много памяти, так как загружает весь контент в строку.

Как добавить данные в конец файла без перезаписи?


<?php
$file = 'access.log';
$line = date('Y-m-d H:i:s') . " - запрос\n";
// FILE_APPEND дописывает, LOCK_EX блокирует
if (file_put_contents($file, $line, FILE_APPEND | LOCK_EX) === false) {
    error_log('Не удалось записать в файл.');
}
?>
  

Php tmp files (временные файлы php)

Типичная ошибка:

Если не использовать LOCK_EX, при параллельных запросах данные могут перемешаться (гонка). Решение – комбинировать FILE_APPEND и LOCK_EX.

Как заменить определённую строку в файле по номеру?


<?php
$filename = 'config.php';
$lines = file($filename, FILE_IGNORE_NEW_LINES); // читаем в массив, удаляем переводы строк
$lineToReplace = 5; // нумерация с 0
$lines[$lineToReplace] = "новое значение";
$newContent = implode(PHP_EOL, $lines);
file_put_contents($filename, $newContent, LOCK_EX);
?>
  

Edit file php (редактирование php файла)

Пояснение: file() читает файл построчно в массив, изменяем нужный элемент и склеиваем обратно. Для больших файлов этот метод может быть ресурсоёмким.

Проблема:

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

Как выполнить замену по регулярному выражению?


<?php
$file = 'settings.ini';
$content = file_get_contents($file);
// Заменим все вхождения mail@old.com на mail@new.com
$newContent = preg_replace('/mail@old\.com/', 'mail@new.com', $content);
file_put_contents($file, $newContent, LOCK_EX);
?>
  

Php file get html (получение html файла через php)

Ошибка:

Если регулярное выражение составлено неверно или содержит незаэкранированные символы, preg_replace вернёт NULL. Проверка результата обязательна.


if (preg_replace('/pattern/', 'replacement', $content) === null) {
    echo 'Ошибка в регулярном выражении.';
}
    

Root php (корневая директория сервера в php)

Как обновить данные в большом файле без загрузки его целиком?

Используется временный файл и потоковое копирование с заменой нужных кусков.


<?php
$inputFile = 'bigdata.txt';
$outputFile = 'bigdata_new.txt';
$search = 'old_value';
$replace = 'new_value';

$in = fopen($inputFile, 'r');
$out = fopen($outputFile, 'w');

while (($line = fgets($in)) !== false) {
    $line = str_replace($search, $replace, $line);
    fwrite($out, $line);
}

fclose($in);
fclose($out);
// Заменяем оригинал
rename($outputFile, $inputFile);
?>
  

Include system php (включение системного файла)

Пояснение: построчное чтение не нагружает память. Временный файл после успешной записи заменяет оригинал. При ошибке оригинал остаётся нетронутым.

Проблема:

Если скрипт прервётся во время записи, может остаться частично записанный временный файл. Следует использовать блок try-catch и удалять временный файл при неудаче.

Как обновить данные в середине файла, не перезаписывая всё?

Такой возможности напрямую нет, так как файлы не имеют вставки произвольных данных. Решение – работать с временным файлом (как выше) или перезаписывать весь файл. Для бинарных данных можно использовать fseek() и fwrite(), но это опасно: если новые данные короче или длиннее, может возникнуть смещение.


<?php
$file = 'data.bin';
$fp = fopen($file, 'c+'); // открываем для чтения и записи, не усекаем
// Находим позицию, например, 100 байт
fseek($fp, 100);
// Записываем ровно столько же байт, сколько было (иначе сдвиг нарушит структуру)
fwrite($fp, 'NEW DATA');
fclose($fp);
?>
  

Ошибка:

Если новые данные другой длины, то после записи данные будут сдвинуты, и файл может быть повреждён. Такой подход применим только для фиксированных записей (например, в бинарных файлах).

- Ru reading php line (чтение строки из файла php)
- Php path (пути в php)
- Start php include (подключение файлов)

Расширенные примеры обновления файлов в PHP

Пример 1. Замена строки по номеру с сохранением окончаний строк (PHP_EOL)

Пример

<?php
$file = 'users.csv';
$recordNumber = 3; // нумерация с 0
$newRecord = "Иван,Иванов,25";

$handle = fopen($file, 'c+');
$currentLine = 0;
$buffer = '';

while (($line = fgets($handle)) !== false) {
    if ($currentLine == $recordNumber) {
        // заменяем строку (сохраняем её длину – но это не обязательно, так как мы будем перезаписывать весь файл)
        $buffer .= $newRecord . PHP_EOL;
    } else {
        $buffer .= $line;
    }
    $currentLine++;
}

rewind($handle);
ftruncate($handle, 0);
fwrite($handle, $buffer);
fclose($handle);
?>
Результат: в файле users.csv третья строка (индекс 3) заменена на "Иван,Иванов,25".

Пример 2. Безопасное обновление с блокировкой и проверкой ошибок

Пример

<?php
$file = 'state.json';
$dataToWrite = [
    'status' => 'active',
    'updated' => time()
];
$json = json_encode($dataToWrite, JSON_PRETTY_PRINT);

$tempFile = $file . '.tmp';
if (file_put_contents($tempFile, $json, LOCK_EX) === false) {
    throw new Exception('Не удалось записать временный файл');
}
// Атомарная замена
if (!rename($tempFile, $file)) {
    unlink($tempFile);
    throw new Exception('Не удалось переименовать временный файл');
}
?>
Результат: файл state.json обновлён атомарно. Даже если скрипт прервётся во время записи, оригинальный файл останется целым.

Пример 3. Обновление только первой строки (замена заголовка)

Пример

<?php
$file = 'report.csv';
// Читаем все строки, заменяем первую
$lines = file($file, FILE_IGNORE_NEW_LINES);
if (!empty($lines)) {
    $lines[0] = 'id,name,date'; // новый заголовок
}
file_put_contents($file, implode(PHP_EOL, $lines), LOCK_EX);
?>
Результат: первая строка файла report.csv стала 'id,name,date', остальные строки без изменений.

Пример 4. Многократное обновление с помощью потоков и фильтров (php://filter)

Пример

<?php
$file = 'text.txt';
// Заменить все вхождения "foo" на "bar" без загрузки в память
// Используем php://filter с read=convert.base64-encode? но лучше stream_filter_append
$in = fopen($file, 'r');
$out = fopen('php://temp', 'w+');
stream_filter_append($out, 'convert.base64-encode'); // пример фильтра

while (($line = fgets($in)) !== false) {
    fwrite($out, str_replace('foo', 'bar', $line));
}
rewind($out);
$newContent = stream_get_contents($out);
fclose($in);
fclose($out);
// Далее можно записать $newContent обратно, но для больших файлов лучше использовать временный файл
?>

Этот пример демонстрирует использование потоков для трансформации данных. В реальности для замены строк проще применить str_replace.

Результат: все вхождения "foo" заменены на "bar" (но текст внутри примера не показан из-за работы с php://temp).

Пример 5. Обновление сериализованных данных (например, файла сессий)

Пример

<?php
$file = 'session_data.txt';
// Чтение сериализованной структуры
$content = file_get_contents($file);
$data = unserialize($content);
// Изменяем данные
$data['counter'] = isset($data['counter']) ? $data['counter'] + 1 : 1;
// Записываем обратно
$newContent = serialize($data);
file_put_contents($file, $newContent, LOCK_EX);
?>
Результат: счётчик в данных увеличился на 1, файл обновлён. Важно: несериализованные данные могут стать причиной ошибок.

Обновление файлов в PHP - comments

En
обновление файлов php (php)