Чтение и запись файлов
Простые функции
<?php
declare(strict_types=1);
// Read entire file to string
$content = file_get_contents('/tmp/data.txt');
if ($content === false) {
throw new RuntimeException('Failed to read file');
}
// Read file to array (line by line)
$lines = file('/tmp/data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// Write string to file (creates or overwrites)
file_put_contents('/tmp/output.txt', 'Hello, World!');
// Append to file
file_put_contents('/tmp/log.txt', "New entry\n", FILE_APPEND);
// Write array (each element = line)
file_put_contents('/tmp/list.txt', implode("\n", ['line1', 'line2', 'line3']));
// With locking
file_put_contents('/tmp/data.txt', 'content', LOCK_EX);
Запомни:
file_get_contents()иfile_put_contents()— простейший способ работы с файлами. Они открывают, читают/пишут и закрывают файл за один вызов. Для больших файлов используйтеfopen/fread/fclose.
Функции fopen/fread/fwrite/fclose
<?php
declare(strict_types=1);
// Open file
$handle = fopen('/tmp/data.txt', 'r');
if ($handle === false) {
throw new RuntimeException('Cannot open file');
}
// Read methods
$char = fgetc($handle); // Read one character
$line = fgets($handle); // Read one line
$line = fgets($handle, 100); // Read max 100 bytes or until newline
$data = fread($handle, 1024); // Read exactly N bytes
$csv = fgetcsv($handle, 0, ','); // Read CSV line
// Check end of file
while (!feof($handle)) {
$line = fgets($handle);
// Process line
}
fclose($handle);
// Writing
$handle = fopen('/tmp/output.txt', 'w');
fwrite($handle, "Hello\n");
fwrite($handle, "World\n");
fputs($handle, "PHP\n"); // Alias of fwrite
fclose($handle);
Режимы открытия файлов
| Режим | Описание | Создаёт? | Обрезает? | Позиция |
|---|---|---|---|---|
r |
Только чтение | Нет | Нет | Начало |
r+ |
Чтение и запись | Нет | Нет | Начало |
w |
Только запись | Да | Да | Начало |
w+ |
Чтение и запись | Да | Да | Начало |
a |
Только запись (append) | Да | Нет | Конец |
a+ |
Чтение и запись | Да | Нет | Конец |
x |
Создание и запись | Только новые | - | Начало |
x+ |
Создание, чтение и запись | Только новые | - | Начало |
c |
Только запись | Да | Нет | Начало |
c+ |
Чтение и запись | Да | Нет | Начало |
Ловушка экзамена: Режим
xвыдаст ошибку, если файл уже существует. Режимwобрезает файл до нулевой длины при открытии. Режимaвсегда пишет в конец (ignore fseek). Эти различия часто спрашивают.
Навигация по файлу
<?php
declare(strict_types=1);
$handle = fopen('/tmp/data.txt', 'r+');
// Current position
echo ftell($handle); // 0
// Move to position
fseek($handle, 10); // Absolute position
fseek($handle, 5, SEEK_CUR); // Relative to current
fseek($handle, -3, SEEK_END); // Relative to end
// Back to beginning
rewind($handle);
// Truncate file
ftruncate($handle, 100); // Keep only first 100 bytes
fclose($handle);
Операции с файлами и директориями
<?php
declare(strict_types=1);
// File existence and info
var_dump(file_exists('/tmp/data.txt')); // true/false
var_dump(is_file('/tmp/data.txt')); // true if it's a file
var_dump(is_dir('/tmp')); // true if it's a directory
var_dump(is_readable('/tmp/data.txt')); // Permission check
var_dump(is_writable('/tmp/data.txt')); // Permission check
// File size
echo filesize('/tmp/data.txt'); // Size in bytes
// File times
echo filemtime('/tmp/data.txt'); // Last modified (timestamp)
echo fileatime('/tmp/data.txt'); // Last accessed
echo filectime('/tmp/data.txt'); // Last changed (inode)
// Copy, rename, delete
copy('/tmp/source.txt', '/tmp/dest.txt');
rename('/tmp/old.txt', '/tmp/new.txt'); // Also moves files
unlink('/tmp/delete_me.txt'); // Delete file
// Directories
mkdir('/tmp/newdir', 0755, true); // recursive=true
rmdir('/tmp/emptydir'); // Only empty directories!
// Temporary files
$tmpFile = tempnam(sys_get_temp_dir(), 'php_');
$tmpHandle = tmpfile(); // Auto-deleted when closed
Права доступа (Permissions)
<?php
declare(strict_types=1);
// Get permissions
$perms = fileperms('/tmp/data.txt');
echo decoct($perms & 0777); // e.g., '644'
// Change permissions
chmod('/tmp/data.txt', 0644); // rw-r--r--
chmod('/tmp/script.sh', 0755); // rwxr-xr-x
// Change owner/group
chown('/tmp/data.txt', 'www-data');
chgrp('/tmp/data.txt', 'www-data');
// umask
$old = umask(0022); // Set default permission mask
// New files: 0666 & ~0022 = 0644
// New dirs: 0777 & ~0022 = 0755
umask($old); // Restore old umask
Ловушка экзамена: Права записываются в восьмеричной системе с ведущим нулём:
0755, а не755. Без нуля PHP интерпретирует как десятичное число (755 в десятичной != 755 в восьмеричной).
Работа с директориями
<?php
declare(strict_types=1);
// List directory contents
$files = scandir('/tmp'); // ['.', '..', 'file1.txt', ...]
// Glob pattern matching
$phpFiles = glob('/var/www/*.php');
$allRecursive = glob('/var/www/**/*.php'); // With GLOB_BRACE
// Directory iterator
$dir = new DirectoryIterator('/tmp');
foreach ($dir as $file) {
if ($file->isDot()) continue;
echo $file->getFilename() . ' (' . $file->getSize() . " bytes)\n";
}
// Recursive directory iterator
$dir = new RecursiveDirectoryIterator('/var/www');
$iterator = new RecursiveIteratorIterator($dir);
foreach ($iterator as $file) {
if ($file->isFile()) {
echo $file->getPathname() . "\n";
}
}
// Path info
$info = pathinfo('/var/www/index.php');
echo $info['dirname']; // /var/www
echo $info['basename']; // index.php
echo $info['extension']; // php
echo $info['filename']; // index
// Combine paths
echo dirname('/var/www/index.php'); // /var/www
echo basename('/var/www/index.php'); // index.php
echo realpath('./relative/path'); // Absolute path
Блокировка файлов
<?php
declare(strict_types=1);
$handle = fopen('/tmp/data.txt', 'r+');
// Exclusive lock (for writing)
if (flock($handle, LOCK_EX)) {
fwrite($handle, 'Updated content');
flock($handle, LOCK_UN); // Release lock
}
// Shared lock (for reading)
if (flock($handle, LOCK_SH)) {
$content = fread($handle, filesize('/tmp/data.txt'));
flock($handle, LOCK_UN);
}
// Non-blocking
if (flock($handle, LOCK_EX | LOCK_NB)) {
// Got lock immediately
} else {
// File is already locked
}
fclose($handle);