EasyТеория4 min

Файловая система

fopen, fread, fwrite, file_get/put_contents, permissions

Чтение и запись файлов

Простые функции

<?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);

Вопросы с экзамена ZCE

Проверь себя

5 из 36

Какие из функций можно использовать для чтения одной строки файла независимо от её длины? (Выберите 2)

Выберите все правильные варианты

Можно ли удалить непустую директорию через `rmdir()`?

Какие из утверждений верны относительно этого кода? ```php ini_set("allow_url_fopen", "1"); $page = file_get_contents("http://www.codepunker.com"); if ($page!=FALSE) { echo "Successfully fetched website contents"; } else { echo "An error has occurred"; } ```

Выберите все правильные варианты

Какая функция даст тот же результат, что и `fseek($fp, 0)` в этом коде? ```php $fp = fopen('file.txt', 'r'); $string1 = fgets($fp, 512); fseek($fp, 0); ```

Что вернёт `filesize()` для файла в 0 байт?