File Handling
PHP can read and write files directly on the server — text logs, CSV exports, cache files,
or small notes like the demo below. This page covers opening files with fopen(),
reading and writing content, checking whether a file exists before touching it, and cleaning up
with fclose() or unlink().
demo-data/ below) so a
visitor can never read or overwrite an arbitrary file on your server.1) Opening a File with fopen()
fopen() opens a file and returns a file handle (a resource) you use for
subsequent reads/writes. The second argument is the mode:
| Mode | Meaning |
|---|---|
r | Read only. Pointer starts at the beginning. Fails if file doesn't exist. |
w | Write only. Erases existing content (or creates the file). |
a | Write only, appends to the end. Creates the file if missing. |
r+ | Read and write. Pointer starts at the beginning; doesn't erase content. |
<?php
$handle = fopen('log.txt', 'a');
if ($handle === false) {
die('Could not open file.');
}
fwrite($handle, "New line\n");
fclose($handle); // always close what you open
?>
2) Reading Files
For most small/medium files, the simplest approach is file_get_contents() —
it opens, reads the whole file, and closes it in one call.
<?php
$contents = file_get_contents('log.txt');
echo $contents;
?>
<?php
$handle = fopen('log.txt', 'r');
while ($handle && !feof($handle)) {
$line = fgets($handle);
echo $line;
}
fclose($handle);
?>
<?php
// Each element is one line, without the trailing newline
$lines = file('log.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$lastFive = array_slice($lines, -5);
?>
3) Writing & Appending with file_put_contents()
file_put_contents() is a shortcut that opens, writes, and closes the file for you
in one call — no need to manage a handle manually.
<?php
// Overwrite the file completely
file_put_contents('log.txt', "Fresh start\n");
// Append instead of overwrite, and lock while writing
file_put_contents('log.txt', "Another line\n", FILE_APPEND | LOCK_EX);
?>
FILE_APPEND keeps old content and adds to the end (same idea
as opening with mode a). Without it, file_put_contents() behaves like mode
w and erases what was there.4) Checking Before You Touch a File
Always check a file's state before reading, writing, or deleting it — this avoids warnings and lets you handle "file not found" gracefully.
<?php
$path = __DIR__ . '/demo-data/notes.txt';
if (!file_exists($path)) {
echo 'No notes saved yet.';
} elseif (!is_readable($path)) {
echo 'Notes file exists but cannot be read.';
} else {
echo file_get_contents($path);
}
?>
| Function | Returns |
|---|---|
file_exists($path) | true if a file or directory exists at that path |
is_readable($path) | true if PHP has permission to read it |
is_writable($path) | true if PHP has permission to write to it |
5) Deleting a File with unlink()
<?php
$path = __DIR__ . '/demo-data/notes.txt';
if (file_exists($path)) {
unlink($path); // permanently removes the file
}
?>
6) Working Demo: Save & Read Notes (Real File I/O)
Type a short note below and click Save Note. The server appends it (with a timestamp) to
a demo file at php/demo-data/notes.txt using file_put_contents(), then
the page reads that file back and shows the last 5 notes — a real, working, server-side
file operation, safely contained in its own folder.
Last 5 Notes
7) Best Practices & Common Mistakes
| Issue | Problem | Fix |
|---|---|---|
| Using raw user input in a path | Path traversal (../../etc/passwd) | Restrict to a fixed folder; never trust $_GET/$_POST for file paths |
Forgetting FILE_APPEND | Mode w-style writes silently erase old data | Use FILE_APPEND or open with mode a |
Not checking file_exists() | Warnings / crashes on first run | Check existence before fopen()/file_get_contents() |
| Concurrent writes without a lock | Corrupted/interleaved lines | Add LOCK_EX to file_put_contents() |
| Leaving handles open | Resource leaks on busy servers | Always fclose(), or prefer file_get_contents/file_put_contents |
8) Practice Tasks
- Write a script that appends a visitor's IP address and timestamp to a log file on every load.
- Read a log file back and count how many lines it has using
count(file($path)). - Write a function
safe_read($path)that returns an empty string if the file doesn't exist or isn't readable. - Add a "download notes" link that streams the demo file's contents as a plain-text response.