Чтение и запись файлов является неотъемлемой частью любого языка программирования, но основная реализация может сильно различаться. Например, более тонкие детали записи данных в локальную файловую систему по сравнению с загрузкой по FTP сильно отличаются — но концептуально они очень похожи.
В дополнение к старым боевым лошадям, таким как FTP, онлайн-хранилище становится все более вездесущим и недорогим — с множеством доступных сервисов, таких как Dropbox, Amazon S3 и Rackspace Cloud Files, — но все они используют слегка разные методы для чтения и записи.
Вот где приходит flysystem . Она обеспечивает уровень абстракции для нескольких файловых систем, что означает, что вам не нужно беспокоиться о том, где находятся файлы, как они хранятся, или вам нужно заниматься операциями ввода-вывода низкого уровня. Все, что вам нужно беспокоиться, это операции высокого уровня, такие как чтение, запись и организация в каталоги.
Такая абстракция также упрощает переключение с одной системы на другую без необходимости переписывать обширные фрагменты кода приложения. Он также обеспечивает логический подход к перемещению или копированию данных из одной системы хранения в другую, не беспокоясь о базовой реализации.
Вы можете использовать Dropbox, S3, Cloud Files, FTP или SFTP, как если бы они были локальными; сохранение файла становится тем же процессом, независимо от того, сохраняется ли он локально или передается по сети. Вы можете обращаться с zip-архивами так, как если бы они были кучей папок, не беспокоясь о тщательности создания и сжатия самих архивов.
Установка и основное использование
Как всегда, Composer — лучший способ установить:
"league/flysystem": "0.2.*"
Теперь вы можете просто создать один или несколько экземпляров League\Flysystem\Filesystem
, передав соответствующий адаптер .
Например, чтобы использовать локальный каталог:
use League\Flysystem\Filesystem; use League\Flysystem\Adapter\Local as Adapter; $filesystem = new Filesystem(new Adapter('/path/to/directory'));
Для использования корзины Amazon S3 требуется немного больше настроек:
use Aws\S3\S3Client; use League\Flysystem\Adapter\AwsS3 as Adapter; $client = S3Client::factory(array( 'key' => '[your key]', 'secret' => '[your secret]', )); $filesystem = new Filesystem(new Adapter($client, 'bucket-name', 'optional-prefix'));
Чтобы использовать Dropbox:
use Dropbox\Client; use League\Flysystem\Adapter\Dropbox as Adapter; $client = new Client($token, $appName); $filesystem = new Filesystem(new Adapter($client, 'optional/path/prefix'));
(Чтобы получить токен и имя приложения, создайте приложение с помощью консоли приложения Dropbox .)
Вот пример для SFTP — вам могут не понадобиться все опции, перечисленные здесь:
use League\Flysystem\Adapter\Sftp as Adapter; $filesystem = new Filesystem(new Adapter(array( 'host' => 'example.com', 'port' => 21, 'username' => 'username', 'password' => 'password', 'privateKey' => 'path/to/or/contents/of/privatekey', 'root' => '/path/to/root', 'timeout' => 10, )));
Для других адаптеров, таких как обычный FTP, Predis или WebDAV, обратитесь к документации .
Чтение и запись в файловую систему
Что касается кода вашего приложения, вам просто нужно заменить вызовы, такие как file_exists()
, fopen()
/ fclose()
, fread
/ fwrite
и mkdir()
их эквивалентами flysystem.
Например, возьмите следующий устаревший код, который копирует локальный файл в корзину S3:
$filename = "/usr/local/something.txt" ;
if ( file_exists ( $filename )) { $handle = fopen ( $filename , "r" ); $contents = fread ( $handle , filesize ( $filename )); fclose ( $handle ); $aws = Aws :: factory ( '/path/to/config.php' ); $s3 = $aws -> get ( 's3' ); $s3 -> putObject ( array (
'Bucket' => 'my-bucket' ,
'Key' => 'data.txt' ,
'Body' => $content ,
'ACL' => 'public-read' ,
));
}
Используя flysystem, это может выглядеть примерно так:
$local = new Filesystem ( new Adapter ( '/usr/local/' )); $remote = new Filesystem ( S3Client :: factory ( array (
'key' => '[your key]' ,
'secret' => '[your secret]' ,
)),
'my-bucket'
);
if ( $local -> has ( 'something.txt' )) { $contents = $local -> read ( 'something.txt' ); $remote -> write ( 'data.txt' , $contents , [ 'visibility' : 'public' ]);
}
Обратите внимание, как мы используем терминологию, такую как чтение и запись , локальные и удаленные абстракции высокого уровня, не беспокоясь о таких вещах, как создание и уничтожение файловых дескрипторов.
Вот краткое изложение наиболее важных методов класса League\Flysystem\Filesystem
:
метод | пример |
---|---|
чтение | $filesystem->read('filename.txt') |
Письмо | $filesystem->write('filename.txt', $contents) |
обновление | $filesystem->update('filename.txt') |
Написание или обновление | $filesystem->put('filename.txt') |
Проверка существования | $filesystem->has('filename.txt') |
Удаление | $filesystem->delete('filename.txt') |
Переименование | $filesystem->rename('old.txt', 'new.txt') |
Чтение файлов | $filesystem->read('filename.txt') |
Получение информации о файле | $filesystem->getMimetype('filename.txt') |
$filesystem->getSize('filename.txt') |
|
$filesystem->getTimestamp('filename.txt') |
|
Создание каталогов | $filesystem->createDir('path/to/directory') |
Удаление каталогов | $filesystem->deleteDir('path/to/directory') |
Автоматическое создание каталогов
Когда вы вызываете $filesystem->write()
, он гарантирует, что каталог, в который вы пытаетесь записать, существует, а если нет, рекурсивно создает его для вас.
Так что это …
$filesystem->write('/path/to/a/directory/somewhere/somefile.txt', $contents);
… в основном эквивалентно:
$path = '/path/to/a/directory/somewhere/somefile.txt'; if (!file_exists(dirname($path))) { mkdir(dirname($path), 0755, true); } file_put_contents($path, $contents);
Управление видимостью
Видимость — то есть разрешения — могут различаться в реализации или семантике в разных механизмах хранения, но flysystem абстрагирует их как «частные» или «публичные». Таким образом, вам не нужно беспокоиться о специфике chmod
, ACL-списков S3 или любой другой терминологии, которую использует конкретный механизм.
Вы можете установить видимость при вызове write()
:
$filesystem->write('filename.txt', $data, ['visibility' : 'private']);
До 5.4 или в соответствии с предпочтениями:
$filesystem->write('filename.txt', $data, array('visibility' => 'private'));
Кроме того, вы можете установить видимость существующего объекта, используя setVisibility
:
$filesystem->setVisibility('filename.txt', 'private');
Вместо того, чтобы устанавливать его для каждого файла отдельно, вы можете установить видимость по умолчанию для данного экземпляра в его конструкторе:
$filesystem = new League\Flysystem\Filesystem($adapter, $cache, [ 'visibility' => AdapterInterface::VISIBILITY_PRIVATE ]);
Вы также можете использовать getVisibility
для определения getVisibility
к файлу:
if ($filesystem->getVisibility === 'private') { // file is secret }
Список файлов и каталогов
Вы можете получить список всех файлов и каталогов в данном каталоге следующим образом:
$filesystem->listContents();
Вывод будет выглядеть примерно так;
[0] => array(8) { 'dirname' => string(0) "" 'basename' => string(11) "filters.php" 'extension' => string(3) "php" 'filename' => string(7) "filters" 'path' => string(11) "filters.php" 'type' => string(4) "file" 'timestamp' => int(1393246029) 'size' => int(2089) } [1] => array(5) { 'dirname' => string(0) "" 'basename' => string(4) "lang" 'filename' => string(4) "lang" 'path' => string(4) "lang" 'type' => string(3) "dir" }
Если вы хотите включить дополнительные свойства в возвращаемый массив, вы можете использовать listWith()
:
$flysystem->listWith(['mimetype', 'size', 'timestamp']);
Чтобы получить рекурсивные списки каталогов, второй параметр должен быть установлен в TRUE:
$filesystem->listContents(null, true);
null
просто означает, что мы начинаем с корневого каталога.
Чтобы получить только пути:
$filesystem->listPaths();
Монтирование файловых систем
Монтирование файловых систем — это концепция, традиционно используемая в операционных системах, но она также может применяться к вашему приложению. По сути, это похоже на создание ссылок — ярлыков, в некотором смысле — на файловые системы, используя какой-то идентификатор.
Для этого Flysystem предоставляет Mount Manager. Вы можете передать один или несколько адаптеров при создании экземпляра, используя строки в качестве ключей:
$ftp = new League\Flysystem\Filesystem($ftpAdapter); $s3 = new League\Flysystem\Filesystem($s3Adapter); $manager = new League\Flysystem\MountManager(array( 'ftp' => $ftp, 's3' => $s3, ));
Вы также можете смонтировать файловую систему позже:
$local = new League\Flysystem\Filesystem($localAdapter); $manager->mountFilesystem('local', $local);
Теперь вы можете использовать идентификаторы, как если бы они были протоколами в URI:
// Get the contents of a local file… $contents = $manager->read('local://path/to/file.txt'); // …and upload to S3 $manager->write('s3://path/goes/here/filename.txt', $contents);
Возможно, более полезно использовать идентификаторы общего характера, например:
$s3 = new League\Flysystem\Filesystem($s3Adapter); $manager = new League\Flysystem\MountManager(array( 'remote' => new League\Flysystem\Filesystem($s3Adapter), )); // Save some data to remote storage $manager->write('remote://path/to/filename', $data);
Кэширование
Flysystem также поддерживает ряд технологий для кэширования метаданных файлов. По умолчанию он использует кэш в памяти, но вы также можете использовать Redis или Memcached.
Вот пример использования Memcached; адаптер кеша передается конструктору Filesystem
в качестве необязательного второго параметра:
use League\Flysystem\Adapter\Local as Adapter; use League\Flysystem\Cache\Memcached as Cache; $memcached = new Memcached; $memcached->addServer('localhost', 11211); $filesystem = new Filesystem(new Adapter(__DIR__.'/path/to/root'), new Cache($memcached, 'storageKey', 300)); // Storage Key and expire time are optional
Как и в случае с adpaters файловой системы, если вы хотите создать свой собственный, просто расширьте League\Flysystem\Cache\AbstractCache
.
Резюме
В этой статье я представил flysystem, пакет, который обеспечивает уровень абстракции для различных форм хранения файлов. Хотя я не охватил все доступные адаптеры, документация должна помочь заполнить пробелы, представить несколько других функций и документировать любые новые адаптеры в будущем.