Writing & Appending Files
Writing to a file in PHP breaks down into two questions: do you want to replace the file's contents or add to them, and do you need to worry about another process writing to the same file at the same time? This page covers file_put_contents() as the everyday tool for both writing and appending, fopen('a') as the handle-based alternative, the LOCK_EX flag for safe concurrent writes, and how to write structured data like JSON and CSV to disk.
file_put_contents(): the simple case
file_put_contents($path, $data) writes a string to a file in a single call, creating the file if it doesn't exist and overwriting it completely if it does. It's the write-side equivalent of file_get_contents() — no fopen(), no fclose(), just a path and the data to write. It returns the number of bytes written, or false on failure.
put-contents-basic.php
<?php
$bytes = file_put_contents('greeting.txt', "Hello, world!\n");
if ($bytes === false) {
die('Failed to write greeting.txt');
}
echo "$bytes bytes written";14 bytes written
Appending with FILE_APPEND
Calling file_put_contents() a second time on the same path overwrites what was there before, which is rarely what you want for something like a log file. Passing the FILE_APPEND flag as the third argument changes that behavior: instead of truncating the file, PHP opens it in append mode and adds the new data to the end, leaving everything already there intact.
append-flag.php
<?php
$logLine = '[' . date('Y-m-d H:i:s') . '] User logged in' . PHP_EOL;
file_put_contents('app.log', $logLine, FILE_APPEND);fopen('a'): the handle-based alternative
file_put_contents() with FILE_APPEND is really a shortcut for opening a handle in append mode, writing, and closing it. Reaching for fopen() directly makes sense when you're appending several pieces of data across multiple fwrite() calls without wanting to reopen the file each time, or when you're combining the write with other handle operations.
fopen-append.php
<?php
$handle = fopen('app.log', 'a');
if ($handle === false) {
die('Could not open app.log for appending');
}
fwrite($handle, '[' . date('Y-m-d H:i:s') . '] Request started' . PHP_EOL);
fwrite($handle, '[' . date('Y-m-d H:i:s') . '] Request finished' . PHP_EOL);
fclose($handle);LOCK_EX: safety under concurrent writes
If two requests write to the same file at nearly the same moment — common on a busy web server, where each request may run in its own process — their writes can interleave, producing a corrupted mix of both. LOCK_EX, passed as (part of) the flags argument to file_put_contents() or via flock() on a handle, asks the operating system for an exclusive lock before writing, so the second writer waits until the first one finishes instead of writing at the same time.
lock-ex-example.php
<?php
$entry = json_encode(['event' => 'signup', 'time' => time()]) . PHP_EOL;
file_put_contents('events.log', $entry, FILE_APPEND | LOCK_EX);Writing structured data: JSON and CSV
Flat files often need to hold structured data rather than plain text. For JSON, encode the data first with json_encode() and write the resulting string like any other; JSON_PRETTY_PRINT is worth adding when a human might read the file later. For CSV, PHP's fputcsv() (covered fully on the CSV page) writes one row at a time to an open handle, correctly quoting fields that contain commas or quote characters.
write-json.php
<?php
$settings = [
'theme' => 'dark',
'notifications' => true,
'retries' => 3,
];
file_put_contents(
'settings.json',
json_encode($settings, JSON_PRETTY_PRINT)
);write-csv-preview.php
<?php
$handle = fopen('export.csv', 'w');
fputcsv($handle, ['id', 'name', 'email']);
fputcsv($handle, [1, 'Priya Shah', 'priya@example.com']);
fputcsv($handle, [2, 'Tom Lin', 'tom@example.com']);
fclose($handle);file_put_contents()— write or overwrite a file in one call.file_put_contents($path, $data, FILE_APPEND)— append instead of overwrite.fopen($path, 'a')— the handle-based alternative for multiple appends.LOCK_EX— request an exclusive lock to avoid interleaved writes from concurrent processes.json_encode()+file_put_contents()for structured JSON output;fputcsv()for CSV rows.