Статьи

Абстрактные файловые системы с Flysystem

Чтение и запись файлов является неотъемлемой частью любого языка программирования, но основная реализация может сильно различаться. Например, более тонкие детали записи данных в локальную файловую систему по сравнению с загрузкой по 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, пакет, который обеспечивает уровень абстракции для различных форм хранения файлов. Хотя я не охватил все доступные адаптеры, документация должна помочь заполнить пробелы, представить несколько других функций и документировать любые новые адаптеры в будущем.