PHP: File Handling
Databases store structured data; files store unstructured data—logs, config files, CSV reports, user-uploaded images. This lesson gives you full control over files and directories in PHP.
1. Reading Files
PHP
<?php
// Method 1: file_get_contents() — read an entire file in one line
$content = file_get_contents('hello.txt');
echo $content;
// Method 2: fopen + fread — streamed reading (for large files)
$handle = fopen('hello.txt', 'r');
$content = fread($handle, filesize('hello.txt'));
fclose($handle);
// Method 3: Read line by line (most memory-efficient)
$handle = fopen('data.txt', 'r');
while (($line = fgets($handle)) !== false) {
echo trim($line) . "<br>";
}
fclose($handle);
// Method 4: file() — read all lines into an array at once
$lines = file('data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
print_r($lines);
?>
| Method | Best For | Memory |
|---|---|---|
file_get_contents() |
Small files (config, JSON) | All at once |
fopen + fread |
Medium files | Controlled |
fopen + fgets |
Large files (logs, CSV) | Low |
file() |
Small files processed by line | All at once |
2. Writing Files
PHP
<?php
// file_put_contents() — write a file in one line
file_put_contents('notes.txt', "Today I learned PHP file handling\n");
// Append mode (third parameter: FILE_APPEND)
file_put_contents('notes.txt', "Now I can append content\n", FILE_APPEND);
// Exclusive lock for writing (prevents concurrent conflicts)
file_put_contents('counter.txt', $count, LOCK_EX);
// fwrite — fine-grained control
$handle = fopen('log.txt', 'a'); // 'a' = append mode
fwrite($handle, date("Y-m-d H:i:s") . " — User logged in\n");
fclose($handle);
?>
▶ サンプル: Simple Logging System
PHP
<?php
class Logger {
public function __construct(
private string $logFile
) {}
public function info(string $message): void {
$this->write('INFO', $message);
}
public function error(string $message): void {
$this->write('ERROR', $message);
}
public function warning(string $message): void {
$this->write('WARNING', $message);
}
private function write(string $level, string $message): void {
$time = date("Y-m-d H:i:s");
$line = "[{$time}] [{$level}] {$message}\n";
file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
public function getRecent(int $lines = 20): array {
if (!file_exists($this->logFile)) {
return [];
}
$all = file($this->logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
return array_slice($all, -$lines);
}
}
$log = new Logger('app.log');
$log->info('App started');
$log->warning('Config file not found, using defaults');
$log->error('Database connection timed out');
$log->info('App finished');
echo "<h3>Recent Logs</h3><pre>" . implode("\n", $log->getRecent(10)) . "</pre>";
?>
3. File Detection
PHP
<?php
$file = 'test.txt';
// Existence checks
var_dump(file_exists($file)); // bool
var_dump(is_file($file)); // Also check it's a file (not a directory)
var_dump(is_dir($file)); // Check if it's a directory
// Read/Write checks
var_dump(is_readable($file)); // Can it be read?
var_dump(is_writable($file)); // Can it be written to?
// File information
echo filesize($file) . " bytes<br>"; // Size
echo filemtime($file); // Last modified time (Unix timestamp)
echo date("Y-m-d H:i:s", filemtime($file)) . "<br>"; // Formatted date
echo pathinfo($file, PATHINFO_EXTENSION); // txt
?>
▶ サンプル: File Cache
PHP
<?php
class FileCache {
private string $cacheDir;
public function __construct(string $dir = 'cache') {
$this->cacheDir = $dir;
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0755, true);
}
}
public function get(string $key, int $ttl = 3600): mixed {
$file = "{$this->cacheDir}/{$key}.cache";
if (!file_exists($file)) return null;
if (time() - filemtime($file) > $ttl) {
unlink($file);
return null;
}
return unserialize(file_get_contents($file));
}
public function set(string $key, mixed $value): void {
$file = "{$this->cacheDir}/{$key}.cache";
file_put_contents($file, serialize($value), LOCK_EX);
}
}
$cache = new FileCache();
$cache->set('config', ['app_name' => 'MyBlog', 'version' => '1.0']);
print_r($cache->get('config'));
?>
4. File Operation Quick Reference
PHP
<?php
$src = 'source.txt';
$dst = 'backup.txt';
// Copy
copy($src, $dst);
// Rename / Move
rename($src, 'new-name.txt');
rename('/tmp/upload.txt', '/var/www/files/upload.txt'); // Move
// Delete
unlink('old-file.txt');
// Directory operations
mkdir('new-folder', 0755, true); // true = recursive creation
rmdir('empty-folder'); // Only deletes empty directories
// Traverse a directory
foreach (scandir('uploads') as $item) {
if ($item !== '.' && $item !== '..') {
echo "{$item} — " . (is_dir("uploads/{$item}") ? 'Directory' : 'File') . "<br>";
}
}
// Use glob for pattern-based file search
$images = glob('uploads/*.{jpg,png,gif}', GLOB_BRACE);
echo "Found " . count($images) . " images";
?>
5. CSV Reading and Writing
CSV is the universal format for data exchange—Excel can open it, and any language can read and write it:
PHP
<?php
// === Writing CSV ===
$data = [
['Name', 'Age', 'City'],
['John', 25, 'Beijing'],
['Jane', 22, 'Shanghai'],
['Bob', 28, 'Guangzhou'],
];
$handle = fopen('users.csv', 'w');
// Write UTF-8 BOM (helps Excel recognize the encoding correctly)
fwrite($handle, "\xEF\xBB\xBF");
foreach ($data as $row) {
fputcsv($handle, $row);
}
fclose($handle);
echo "CSV file generated ✅<br>";
// === Reading CSV ===
$handle = fopen('users.csv', 'r');
// Skip BOM
fseek($handle, 3);
// Read headers
$headers = fgetcsv($handle);
while (($row = fgetcsv($handle)) !== false) {
// Use headers as keys
$item = array_combine($headers, $row);
echo "{$item['Name']}, {$item['Age']} years old, lives in {$item['City']}<br>";
}
fclose($handle);
?>
▶ サンプル: CSV Data Export
PHP
<?php
function exportToCSV(array $data, string $filename): void {
header('Content-Type: text/csv; charset=utf-8');
header("Content-Disposition: attachment; filename={$filename}");
$output = fopen('php://output', 'w');
fwrite($output, "\xEF\xBB\xBF"); // BOM
// Headers
if (!empty($data)) {
fputcsv($output, array_keys($data[0]));
}
// Data
foreach ($data as $row) {
fputcsv($output, $row);
}
fclose($output);
}
// exportToCSV($usersData, 'users_export.csv');
?>
6. File Locking (Preventing Concurrent Writes)
PHP
<?php
class Counter {
private string $file;
public function __construct(string $file = 'counter.dat') {
$this->file = $file;
if (!file_exists($this->file)) {
file_put_contents($this->file, 0);
}
}
public function increment(): int {
$handle = fopen($this->file, 'c+');
// Acquire an exclusive lock (other processes wait)
if (flock($handle, LOCK_EX)) {
$count = (int)fread($handle, 100);
$count++;
// Go back to the beginning of the file
fseek($handle, 0);
ftruncate($handle, 0); // Clear it
fwrite($handle, (string)$count);
flock($handle, LOCK_UN); // Unlock
fclose($handle);
return $count;
}
fclose($handle);
return -1;
}
}
?>
❓ よくある質問
Q How do I choose between
file_get_contents() and fopen + fgets?A Use
file_get_contents() for small files (<1MB)—one line and you're done. Use fgets() to read line by line for large files (tens of thousands of log lines)—it's memory-friendly. If you don't know the size, start with fopen.Q Chinese characters appear garbled in Excel?
A Add a UTF-8 BOM (
"\xEF\xBB\xBF") at the beginning of the CSV file. Excel reads files using the local encoding by default—the BOM tells it the file is UTF-8.Q Is file locking with
flock actually necessary?A Absolutely, when multiple processes read and write the same file simultaneously. Counters, caches, and logs can all suffer from race conditions where values get read after another process has already modified them—without locking.
📖 まとめ
file_get_contents()reads a file in one line,file_put_contents()writes a file in one linefopen + fgetsreads line by line—best for large filesfile_put_contents($file, $data, FILE_APPEND | LOCK_EX)safely appendsfile_exists()/is_readable()/is_writable()—check before operating- CSV:
fputcsv()for writing,fgetcsv()for reading, BOM prevents Excel garbled text flock($handle, LOCK_EX)provides exclusive locking to prevent concurrent write conflicts
📝 練習問題
- Write a visitor counter: each page refresh increments the count by 1, storing the count in a file.
- Write a simple guestbook: a form submits a message → append to a file → read and display all messages from the file (with timestamps).
- Export your users table to a CSV file (read data from MySQL → generate a CSV file → provide a download link).