Что такое Flysystem и зачем он нужен?
Flysystem — это мощная библиотека для PHP, которая предоставляет единый, унифицированный интерфейс для работы с различными файловыми системами. Разработанная Frank de Jonge, она решает фундаментальную проблему: в реальных проектах код часто жестко привязан к конкретной файловой системе (локальный диск, FTP, Amazon S3, Dropbox и т.д.). Если завтра потребуется перенести хранение файлов с локального сервера на облачное хранилище, придется переписывать значительную часть кода.
Flysystem абстрагирует эту сложность. Вы пишете код один раз, используя единый API, и можете менять "адаптер" (драйвер) файловой системы без изменения бизнес-логики приложения. Это делает ваш код:
- Гибким — легко переключаться между хранилищами.
- Тестируемым — можно использовать "фейковую" файловую систему в тестах.
- Портируемым — код работает одинаково на разных окружениях.
Библиотека используется в таких известных проектах, как Laravel (как основа для диска хранения), Symfony, Drupal и многих других. Flysystem поддерживает десятки адаптеров: Local, FTP/SFTP, Amazon S3, Google Cloud Storage, Azure Blob Storage, WebDAV, Dropbox и даже шифрованные и Zip-архивы.
Установка
Flysystem устанавливается через Composer. Для базовой работы с локальной файловой системой достаточно двух пакетов:
composer require league/flysystem
composer require league/flysystem-local
Важно: Начиная с версии 3.x, Flysystem использует раздельную архитектуру. Основной пакет league/flysystem содержит только интерфейсы и базовые классы. Адаптеры (драйверы) устанавливаются отдельно. Это позволяет подключать только то, что реально нужно.
Для других файловых систем:
composer require league/flysystem-ftp— для FTP/SFTPcomposer require league/flysystem-aws-s3-v3— для Amazon S3composer require league/flysystem-google-cloud-storage— для Google Cloudcomposer require league/flysystem-memory— для тестов (виртуальная in-memory ФС)
Быстрый старт
Создадим простой пример: запись, чтение и удаление файла на локальном диске.
<?php
require 'vendor/autoload.php';
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
// 1. Создаем адаптер для локальной файловой системы
// Указываем корневую директорию, где будут храниться файлы
$adapter = new LocalFilesystemAdapter(__DIR__ . '/storage');
// 2. Создаем экземпляр Filesystem
$filesystem = new Filesystem($adapter);
// 3. Пишем файл
$filesystem->write('hello.txt', 'Привет, мир!');
// 4. Читаем файл
$content = $filesystem->read('hello.txt');
echo $content; // Выведет: Привет, мир!
// 5. Проверяем, существует ли файл
if ($filesystem->fileExists('hello.txt')) {
echo "Файл существует!";
}
// 6. Удаляем файл
$filesystem->delete('hello.txt');
// 7. Проверяем, что файла больше нет
echo $filesystem->fileExists('hello.txt') ? 'Есть' : 'Нет'; // Выведет: Нет
?>
Обратите внимание: мы не используем file_put_contents(), fopen() или другие нативные PHP-функции. Весь код работает через единый интерфейс Filesystem.
Основные методы/функции
Рассмотрим ключевые методы Flysystem. Все примеры предполагают, что у вас уже создан объект $filesystem.
1. write() — Запись нового файла
Что делает: Создает новый файл или перезаписывает существующий.
Параметры:
string $path— путь к файлуstring|resource $contents— содержимое файла (строка или ресурс)array $config— опциональные настройки (например, visibility: 'public' или 'private')
Пример:
$filesystem->write('documents/report.txt', 'Ежемесячный отчет за январь');
$filesystem->write('images/logo.png', file_get_contents('local_logo.png'), [
'visibility' => 'public'
]);
2. read() — Чтение содержимого файла
Что делает: Возвращает содержимое файла в виде строки.
Параметры:
string $path— путь к файлу
Пример:
$content = $filesystem->read('documents/report.txt');
echo $content;
3. fileExists() — Проверка существования файла
Что делает: Проверяет, существует ли файл по указанному пути.
Параметры:
string $path— путь к файлу
Пример:
if ($filesystem->fileExists('config.json')) {
echo "Конфигурация найдена";
} else {
echo "Файл конфигурации отсутствует";
}
4. delete() — Удаление файла
Что делает: Удаляет файл. Если файла не существует, выбрасывает исключение FileNotFoundException.
Параметры:
string $path— путь к файлу
Пример:
try {
$filesystem->delete('temp/cache.dat');
} catch (\League\Flysystem\FileNotFoundException $e) {
echo "Файл не найден: " . $e->getMessage();
}
5. createDirectory() — Создание директории
Что делает: Создает новую директорию. Автоматически создает все родительские директории, если их нет.
Параметры:
string $path— путь к директорииarray $config— опциональные настройки
Пример:
$filesystem->createDirectory('photos/2024/january');
// Создаст три вложенные директории: photos, 2024, january
6. deleteDirectory() — Удаление директории
Что делает: Удаляет директорию и все её содержимое (рекурсивно).
Параметры:
string $path— путь к директории
Пример:
$filesystem->deleteDirectory('temp'); // Удалит temp/ и всё внутри
7. listContents() — Список содержимого директории
Что делает: Возвращает массив объектов FileAttributes или DirectoryAttributes, представляющих содержимое директории.
Параметры:
string $path— путь к директории (по умолчанию корень '/')bool $deep— рекурсивно ли просматривать поддиректории (по умолчанию false)
Пример:
$listing = $filesystem->listContents('documents', true);
foreach ($listing as $item) {
if ($item->isFile()) {
echo "Файл: " . $item->path() . " (" . $item->fileSize() . " байт)\n";
} elseif ($item->isDir()) {
echo "Директория: " . $item->path() . "\n";
}
}
8. move() — Перемещение/переименование файла
Что делает: Перемещает файл из одного места в другое (или переименовывает).
Параметры:
string $source— исходный путьstring $destination— целевой путьarray $config— опциональные настройки
Пример:
$filesystem->move('incoming/report.csv', 'processed/report_2024.csv');
// Файл будет перемещен и переименован
9. copy() — Копирование файла
Что делает: Копирует файл из одного места в другое. Исходный файл остается нетронутым.
Параметры:
string $source— исходный путьstring $destination— целевой путьarray $config— опциональные настройки
Пример:
$filesystem->copy('templates/email.html', 'backups/email_backup.html');
10. writeStream() / readStream() — Работа с потоками
Что делает: Позволяют работать с файлами как с потоками данных. Критически важно для больших файлов (видео, архивы), чтобы не держать их целиком в оперативной памяти.
Параметры: Аналогичны write() и read(), но вместо строки принимают/возвращают ресурс.
Пример:
// Запись большого файла через поток
$stream = fopen('/tmp/large_video.mp4', 'r');
$filesystem->writeStream('videos/large_video.mp4', $stream);
fclose($stream);
// Чтение большого файла через поток
$stream = $filesystem->readStream('videos/large_video.mp4');
while (!feof($stream)) {
echo fread($stream, 1024); // Читаем по 1 КБ
}
fclose($stream);
11. setVisibility() — Управление видимостью
Что делает: Устанавливает видимость файла (public или private). Работает не для всех адаптеров (например, для локальной ФС это права доступа Unix).
Параметры:
string $path— путь к файлуstring $visibility— 'public' или 'private'
Пример:
$filesystem->setVisibility('public/style.css', 'public');
$filesystem->setVisibility('config/db_passwords.php', 'private');
Реальный практический пример: Система загрузки аватаров
Представим, что мы разрабатываем сайт, где пользователи могут загружать свои аватары. Мы хотим хранить их в облаке (S3), но на локальном сервере разработки — на диске. Flysystem позволяет легко переключаться между ними.
<?php
class AvatarService {
private Filesystem $filesystem;
private string $avatarPrefix = 'avatars/';
public function __construct(Filesystem $filesystem) {
$this->filesystem = $filesystem;
}
/**
* Сохраняет аватар пользователя
*/
public function uploadAvatar(int $userId, string $sourcePath): string {
$extension = pathinfo($sourcePath, PATHINFO_EXTENSION);
$avatarPath = $this->avatarPrefix . $userId .