File Handling Overview
Almost every real PHP application eventually needs to read from or write to a file — a log, a cache, a configuration file, an uploaded document, or a report generated for a user to download. PHP's file handling functions date back to its earliest versions and follow a simple, low-level model borrowed from C: you open a file to get a "handle" (also called a resource or stream), you read or write through that handle, and then you close it. This page covers that core model — fopen(), fread(), fwrite(), fclose() — along with the file modes that control what you're allowed to do, and a preview of the simpler helper functions that cover most everyday cases without needing a handle at all.
The handle-based model
fopen() takes a file path and a mode string, and returns a resource that represents an open connection to that file. Every subsequent operation — reading, writing, checking for end-of-file — happens through that resource, not through the path directly. When you're done, fclose() releases the underlying operating system file handle. This matters more than it might seem: operating systems limit how many files a single process can have open at once, and an unclosed handle also risks losing buffered writes that haven't been flushed to disk yet.
basic-fopen.php
<?php
$handle = fopen('notes.txt', 'w');
if ($handle === false) {
die('Could not open file for writing.');
}
fwrite($handle, "First line\n");
fwrite($handle, "Second line\n");
fclose($handle);
echo 'Done writing.';Done writing.
File modes
The second argument to fopen() is a mode string that controls both the type of access you get and what happens to any existing content. Getting this wrong is one of the most common file-handling mistakes in PHP — opening in the wrong mode can silently erase a file you meant to append to.
r— read-only. The file must already exist, and the cursor starts at the beginning.w— write-only. Creates the file if it doesn't exist, and truncates it to zero bytes if it does.a— append-only. Creates the file if needed; the cursor starts at the end, and existing content is preserved.r+— read and write, without truncating. The file must exist.w+— read and write, but truncates the file first, just likew.a+— read and append, preserving existing content, with reads able to start from the beginning.x— likew, but fails instead of overwriting if the file already exists.
Reading with fread()
fread($handle, $length) reads up to $length bytes from the current position of the file pointer and advances the pointer by that amount. To read an entire file this way, you typically loop until feof() reports that the pointer has reached the end.
fread-example.php
<?php
$handle = fopen('notes.txt', 'r');
if ($handle === false) {
die('Could not open file for reading.');
}
$contents = '';
while (!feof($handle)) {
$contents .= fread($handle, 8192);
}
fclose($handle);
echo $contents;First line Second line
Always check fopen()'s return value
fopen() doesn't throw an exception when it fails — a missing directory, a permissions problem, or a locked file all cause it to return false while emitting a warning. Code that assumes the handle is valid and immediately calls fwrite() or fread() on it will produce confusing follow-on errors, because those functions expect a resource, not false. Checking the return value explicitly turns a cryptic failure two lines later into a clear, actionable error at the point where things actually went wrong.
check-fopen.php
<?php
$path = '/var/log/app/does-not-exist/log.txt';
$handle = fopen($path, 'a');
if ($handle === false) {
error_log("Failed to open log file: $path");
exit(1);
}
fwrite($handle, 'Started up' . PHP_EOL);
fclose($handle);Simpler helpers: a preview
The fopen/fread/fwrite/fclose sequence gives you fine control — reading in chunks, writing incrementally, seeking to a specific position — but for the common case of "read this whole file" or "write this whole string to a file," PHP offers file_get_contents() and file_put_contents(). They wrap the same handle-based mechanics internally, open and close the handle for you, and return either the file's contents or the number of bytes written. The following two pages, on reading and writing files, cover these helpers in depth.
helpers-preview.php
<?php
// Equivalent to the fopen/fread/fclose loop above
$contents = file_get_contents('notes.txt');
// Equivalent to fopen/fwrite/fclose with mode 'w'
file_put_contents('notes.txt', "Overwritten content\n");
echo $contents;