Chapter 12: Files, Streams, and IO
PHP provides comprehensive tools for file and stream operations. You can read and write data, traverse directories, handle uploads, and work with wrappers for protocols like php:// and http://. This chapter explores the file system API, stream abstraction, structured data formats, temporary file handling, serialization, and key security practices for input and storage.
Working with Files and Directories
PHP offers high level functions for file reading, writing, and directory traversal. Always verify file existence and handle permissions carefully. Prefer built in helpers like file_get_contents() and file_put_contents() for simplicity when you do not need fine control.
Reading and writing entire files
Use file_get_contents() to read and file_put_contents() to write complete files in one call. These are efficient for small and medium sized data.
$text = file_get_contents("notes.txt");
file_put_contents("backup.txt", $text);
Processing files line by line
For large files, open a handle and read incrementally with fopen(), fgets(), and fclose(). Always check for false return values when opening.
$handle = fopen("log.txt", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo $line;
}
fclose($handle);
}
Listing and managing directories
Use scandir() or directory handles to enumerate files. Combine with is_dir() and is_file() for filtering.
$entries = scandir("/var/www");
foreach ($entries as $entry) {
if (is_dir($entry)) {
echo "[DIR] $entry" . PHP_EOL;
} else {
echo " $entry" . PHP_EOL;
}
}
SplFileInfo or DirectoryIterator for object oriented directory iteration with metadata access.
Streams and Wrappers
Streams abstract file, network, and memory IO behind a unified interface. Wrappers extend the concept to protocols such as HTTP, FTP, ZIP, and data URIs. This consistency means you can use the same functions on many sources and destinations.
Opening and writing to stream resources
Use fopen() with wrappers to access different transports. For example, php://memory provides a temporary in-memory buffer.
$stream = fopen("php://memory", "r+");
fwrite($stream, "Example data");
rewind($stream);
echo stream_get_contents($stream);
fclose($stream);
Working with remote and compressed data
When URL wrappers are enabled, the same functions work for remote resources and compressed files.
$html = file_get_contents("https://example.com");
$gz = gzopen("archive.gz", "rb");
while (!gzeof($gz)) {
echo gzread($gz, 4096);
}
gzclose($gz);
Creating custom filters
Stream filters let you transform data as it is read or written. PHP includes built in filters for compression, string operations, and conversions. You can register your own for specialized processing.
$fp = fopen("data.txt", "r");
stream_filter_append($fp, "string.toupper");
echo stream_get_contents($fp);
fclose($fp);
allow_url_fopen. Disable it in production if you do not require network IO to prevent arbitrary fetches.
Reading and Writing CSV and JSON
Structured text formats are common for configuration and data exchange. PHP includes native functions for CSV and JSON processing that handle encoding and escaping safely.
Parsing and generating CSV files
Use fgetcsv() to parse and fputcsv() to write rows. Both respect quoted fields and delimiters.
$fp = fopen("people.csv", "r");
while (($row = fgetcsv($fp)) !== false) {
[$name, $email] = $row;
echo "$name <$email>" . PHP_EOL;
}
fclose($fp);
$fp = fopen("out.csv", "w");
fputcsv($fp, ["Name", "Email"]);
fputcsv($fp, ["Ada Lovelace", "ada@example.com"]);
fclose($fp);
Encoding and decoding JSON
PHP’s json_encode() and json_decode() convert between arrays or objects and JSON text. Always check json_last_error() after decoding to detect malformed input.
$data = ["title" => "Example", "active" => true];
$json = json_encode($data, JSON_PRETTY_PRINT);
file_put_contents("config.json", $json);
$decoded = json_decode(file_get_contents("config.json"), true);
if (json_last_error() === JSON_ERROR_NONE) {
print_r($decoded);
}
JSON_THROW_ON_ERROR flag in modern PHP to automatically raise exceptions for invalid data.
Uploads and tmp Handling
When users upload files via HTTP forms, PHP writes them to temporary storage. You can access details in the $_FILES array and move them to a permanent location after validation.
Processing uploaded files safely
Check size, MIME type, and upload errors before moving files. Always use move_uploaded_file() to prevent directory traversal or overwriting unintended files.
if ($_FILES["photo"]["error"] === UPLOAD_ERR_OK) {
$tmp = $_FILES["photo"]["tmp_name"];
$dest = __DIR__ . "/uploads/" . basename($_FILES["photo"]["name"]);
move_uploaded_file($tmp, $dest);
}
Creating and cleaning temporary files
Use tmpfile() or tempnam() for scratch storage. tmpfile() deletes automatically on close; tempnam() returns a persistent path you can manage manually.
$temp = tmpfile();
fwrite($temp, "Session data");
rewind($temp);
echo fread($temp, 1024);
fclose($temp);
Serialization and var_export
Serialization turns data structures into strings for storage or transmission. PHP provides serialize() and unserialize(), and safer alternatives like json_encode() or var_export() for code generation.
Serializing and unserializing PHP data
serialize() encodes mixed structures with type information. Use only for trusted data; it can execute code during unserialization if objects define magic methods.
$a = ["x" => 1, "y" => [2, 3]];
$s = serialize($a);
file_put_contents("data.ser", $s);
$restored = unserialize(file_get_contents("data.ser"));
Exporting data as PHP code
var_export() returns valid PHP code that recreates a value. Combine with eval() or include for configuration patterns.
$config = ["debug" => true, "host" => "localhost"];
$code = "<?php\nreturn " . var_export($config, true) . ";\n";
file_put_contents("config.php", $code);
$loaded = include "config.php";
var_export() for configuration snapshots or caching known structures. Avoid unserializing untrusted input.
Permissions and Security Considerations
File and stream operations can expose sensitive data or enable injection if handled carelessly. Apply strict permissions, validate paths, and restrict writable locations to controlled directories.
Setting and checking file permissions
Use chmod(), fileperms(), and related functions to inspect and modify access rights. In shared environments, prefer read only where possible.
$file = "config.ini";
chmod($file, 0640);
printf("Permissions: %o", fileperms($file) & 0777);
Avoiding path traversal and injection
Never concatenate user input directly into paths. Use basename() or whitelist directories to ensure safe access. When including files dynamically, restrict to known roots.
$safe = basename($_GET["file"]);
include __DIR__ . "/pages/" . $safe;
Restricting wrapper and stream access
Disable or limit wrappers that you do not use. For critical systems, set open_basedir to restrict file operations to specific paths. Review stream filters to prevent injection through php://filter abuse.