├── .gitignore ├── src ├── NullFilesystem.php ├── DropboxFilesystem.php ├── ZipArchiveFilesystem.php ├── GridFSFilesystem.php ├── YiiCache.php ├── LocalFilesystem.php ├── GoogleCloudFilesystem.php ├── AzureFilesystem.php ├── WebDAVFilesystem.php ├── RackspaceFilesystem.php ├── FtpFilesystem.php ├── SftpFilesystem.php ├── AwsS3Filesystem.php └── Filesystem.php ├── CHANGELOG.md ├── composer.json ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # phpstorm project files 2 | .idea 3 | 4 | # netbeans project files 5 | nbproject 6 | 7 | # zend studio for eclipse project files 8 | .buildpath 9 | .project 10 | .settings 11 | 12 | # windows thumbnail cache 13 | Thumbs.db 14 | 15 | # composer vendor dir 16 | /vendor 17 | 18 | # composer itself is not needed 19 | composer.phar 20 | 21 | # Mac DS_Store Files 22 | .DS_Store 23 | 24 | # phpunit itself is not needed 25 | phpunit.phar 26 | # local phpunit config 27 | /phpunit.xml 28 | -------------------------------------------------------------------------------- /src/NullFilesystem.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class NullFilesystem extends Filesystem 18 | { 19 | /** 20 | * @return NullAdapter 21 | */ 22 | protected function prepareAdapter() 23 | { 24 | return new NullAdapter(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 1.1.1 4 | 5 | - Added argument overrides for Local filesystem adapter 6 | 7 | ## 1.1.0 8 | 9 | - Fix Dropbox adapter not working 10 | 11 | ## 1.0.0-rc1 12 | 13 | - added `streamReads` param for AWS 14 | 15 | ## 0.10.0 16 | 17 | - Updated Dropbox adapter 18 | 19 | ## 0.9.3 20 | 21 | - AWS S3: added `credentials` for custom credential provider 22 | 23 | ## 0.9.2 24 | 25 | - AWS S3: added `pathStyleEndpoint` to allow the use of https://www.minio.io/ as storage service 26 | 27 | ## 0.9.1 28 | 29 | - all adapters: added getter for native filesystem `getFilesystem()` 30 | - AWS S3: added `endpoint` property 31 | - SFTP: added directory permission property 32 | - GoogleCloud: added adapter 33 | 34 | ## 0.9.0 35 | 36 | *see `git log`* 37 | -------------------------------------------------------------------------------- /src/DropboxFilesystem.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class DropboxFilesystem extends Filesystem 21 | { 22 | /** 23 | * @var string|array|TokenProvider 24 | */ 25 | public $token; 26 | 27 | /** 28 | * @var string|null 29 | */ 30 | public $prefix = ''; 31 | 32 | /** 33 | * @inheritdoc 34 | */ 35 | public function init() 36 | { 37 | if ($this->token === null) { 38 | throw new InvalidConfigException('The "token" property must be set.'); 39 | } 40 | 41 | parent::init(); 42 | } 43 | 44 | /** 45 | * @return DropboxAdapter 46 | */ 47 | protected function prepareAdapter() 48 | { 49 | return new DropboxAdapter( 50 | new Client($this->token), 51 | $this->prefix 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ZipArchiveFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class ZipArchiveFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $path; 25 | /** 26 | * @var string|null 27 | */ 28 | public $prefix; 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public function init() 34 | { 35 | if ($this->path === null) { 36 | throw new InvalidConfigException('The "path" property must be set.'); 37 | } 38 | 39 | $this->path = Yii::getAlias($this->path); 40 | 41 | parent::init(); 42 | } 43 | 44 | /** 45 | * @return ZipArchiveAdapter 46 | */ 47 | protected function prepareAdapter() 48 | { 49 | return new ZipArchiveAdapter( 50 | $this->path, 51 | null, 52 | $this->prefix 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/GridFSFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class GridFSFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $server; 25 | /** 26 | * @var string 27 | */ 28 | public $database; 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public function init() 34 | { 35 | if ($this->server === null) { 36 | throw new InvalidConfigException('The "server" property must be set.'); 37 | } 38 | 39 | if ($this->database === null) { 40 | throw new InvalidConfigException('The "database" property must be set.'); 41 | } 42 | 43 | parent::init(); 44 | } 45 | 46 | /** 47 | * @return GridFSAdapter 48 | */ 49 | protected function prepareAdapter() 50 | { 51 | return new GridFSAdapter((new MongoClient($this->server))->selectDB($this->database)->getGridFS()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/YiiCache.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class YiiCache extends AbstractCache 19 | { 20 | /** 21 | * @var Cache 22 | */ 23 | protected $yiiCache; 24 | /** 25 | * @var string 26 | */ 27 | protected $key; 28 | /** 29 | * @var integer 30 | */ 31 | protected $duration; 32 | 33 | /** 34 | * @param Cache $yiiCache 35 | * @param string $key 36 | * @param integer $duration 37 | */ 38 | public function __construct(Cache $yiiCache, $key = 'flysystem', $duration = 0) 39 | { 40 | $this->yiiCache = $yiiCache; 41 | $this->key = $key; 42 | $this->duration = $duration; 43 | } 44 | 45 | /** 46 | * @inheritdoc 47 | */ 48 | public function load() 49 | { 50 | $contents = $this->yiiCache->get($this->key); 51 | 52 | if ($contents !== false) { 53 | $this->setFromStorage($contents); 54 | } 55 | } 56 | 57 | /** 58 | * @inheritdoc 59 | */ 60 | public function save() 61 | { 62 | $this->yiiCache->set($this->key, $this->getForStorage(), $this->duration); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "creocoder/yii2-flysystem", 3 | "description": "The flysystem extension for the Yii framework", 4 | "keywords": [ 5 | "yii2", 6 | "flysystem", 7 | "filesystem", 8 | "files", 9 | "aws", 10 | "s3", 11 | "azure", 12 | "copy.com", 13 | "dropbox", 14 | "ftp", 15 | "gridfs", 16 | "rackspace", 17 | "sftp", 18 | "webdav" 19 | ], 20 | "type": "yii2-extension", 21 | "license": "BSD-3-Clause", 22 | "authors": [ 23 | { 24 | "name": "Alexander Kochetov", 25 | "email": "creocoder@gmail.com" 26 | } 27 | ], 28 | "require": { 29 | "yiisoft/yii2": "~2.0.0", 30 | "league/flysystem": "~1.0" 31 | }, 32 | "require-dev": { 33 | "league/flysystem-aws-s3-v3": "~1.0", 34 | "league/flysystem-azure": "~1.0", 35 | "league/flysystem-cached-adapter": "~1.0", 36 | "spatie/flysystem-dropbox": "~1.0", 37 | "league/flysystem-gridfs": "~1.0", 38 | "league/flysystem-rackspace": "~1.0", 39 | "league/flysystem-replicate-adapter": "~1.0", 40 | "league/flysystem-sftp": "~1.0", 41 | "league/flysystem-webdav": "~1.0", 42 | "league/flysystem-ziparchive": "~1.0" 43 | }, 44 | "conflict": { 45 | "league/flysystem-aws-s3-v3": "<1.0.26" 46 | }, 47 | "repositories": [ 48 | { 49 | "type": "composer", 50 | "url": "https://asset-packagist.org" 51 | } 52 | ], 53 | "autoload": { 54 | "psr-4": { 55 | "creocoder\\flysystem\\": "src" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The flysystem extension for the Yii framework is free software. 2 | It is released under the terms of the following BSD License. 3 | 4 | Copyright © 2015, Alexander Kochetov (https://github.com/creocoder) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | * Neither the name of Yii Software LLC nor the names of its 18 | contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /src/LocalFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class LocalFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $path; 25 | 26 | /** 27 | * @var int 28 | */ 29 | public $writeFlags = LOCK_EX; 30 | 31 | /** 32 | * @var int 33 | */ 34 | public $linkHandling = Local::DISALLOW_LINKS; 35 | 36 | /** 37 | * @var array 38 | */ 39 | public $permissions = []; 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public function init() 45 | { 46 | if ($this->path === null) { 47 | throw new InvalidConfigException('The "path" property must be set.'); 48 | } 49 | 50 | if (!in_array($this->writeFlags, [0, LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB], true)) { 51 | throw new InvalidConfigException('The "writeFlags" property value is invalid.'); 52 | } 53 | 54 | if ($this->linkHandling !== Local::DISALLOW_LINKS && $this->linkHandling !== Local::SKIP_LINKS) { 55 | throw new InvalidConfigException('The "linkHandling" property value is invalid.'); 56 | } 57 | 58 | $this->path = Yii::getAlias($this->path); 59 | 60 | parent::init(); 61 | } 62 | 63 | /** 64 | * @return Local 65 | */ 66 | protected function prepareAdapter() 67 | { 68 | return new Local($this->path, $this->writeFlags, $this->linkHandling, $this->permissions); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/GoogleCloudFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class GoogleCloudFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $projectId; 25 | /** 26 | * @var string 27 | */ 28 | public $keyFilePath; 29 | /** 30 | * @var string 31 | */ 32 | public $bucket; 33 | 34 | /** 35 | * @inheritdoc 36 | */ 37 | public function init() 38 | { 39 | if ($this->projectId === null) { 40 | throw new InvalidConfigException('The "projectId" property must be set.'); 41 | } 42 | 43 | if ($this->keyFilePath === null) { 44 | throw new InvalidConfigException('The "secret" property must be set.'); 45 | } 46 | 47 | if ($this->bucket === null) { 48 | throw new InvalidConfigException('The "bucket" property must be set.'); 49 | } 50 | 51 | parent::init(); 52 | } 53 | 54 | /** 55 | * @return GoogleStorageAdapter 56 | */ 57 | protected function prepareAdapter() 58 | { 59 | $config = [ 60 | 'projectId' => $this->projectId, 61 | 'keyFilePath' => \Yii::getAlias($this->keyFilePath), 62 | ]; 63 | 64 | $client = new StorageClient($config); 65 | $bucket = $client->bucket($this->bucket); 66 | return new GoogleStorageAdapter($client, $bucket); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/AzureFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class AzureFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $accountName; 25 | /** 26 | * @var string 27 | */ 28 | public $accountKey; 29 | /** 30 | * @var string 31 | */ 32 | public $container; 33 | 34 | /** 35 | * @inheritdoc 36 | */ 37 | public function init() 38 | { 39 | if ($this->accountName === null) { 40 | throw new InvalidConfigException('The "accountName" property must be set.'); 41 | } 42 | 43 | if ($this->accountKey === null) { 44 | throw new InvalidConfigException('The "accountKey" property must be set.'); 45 | } 46 | 47 | if ($this->container === null) { 48 | throw new InvalidConfigException('The "container" property must be set.'); 49 | } 50 | 51 | parent::init(); 52 | } 53 | 54 | /** 55 | * @return AzureAdapter 56 | */ 57 | protected function prepareAdapter() 58 | { 59 | return new AzureAdapter( 60 | ServicesBuilder::getInstance()->createBlobService(sprintf( 61 | 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s', 62 | base64_encode($this->accountName), 63 | base64_encode($this->accountKey) 64 | )), 65 | $this->container 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/WebDAVFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class WebDAVFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $baseUri; 25 | /** 26 | * @var string 27 | */ 28 | public $userName; 29 | /** 30 | * @var string 31 | */ 32 | public $password; 33 | /** 34 | * @var string 35 | */ 36 | public $proxy; 37 | /** 38 | * @var integer 39 | */ 40 | public $authType; 41 | /** 42 | * @var integer 43 | */ 44 | public $encoding; 45 | /** 46 | * @var string|null 47 | */ 48 | public $prefix; 49 | 50 | /** 51 | * @inheritdoc 52 | */ 53 | public function init() 54 | { 55 | if ($this->baseUri === null) { 56 | throw new InvalidConfigException('The "baseUri" property must be set.'); 57 | } 58 | 59 | parent::init(); 60 | } 61 | 62 | /** 63 | * @return WebDAVAdapter 64 | */ 65 | protected function prepareAdapter() 66 | { 67 | $config = []; 68 | 69 | foreach ([ 70 | 'baseUri', 71 | 'userName', 72 | 'password', 73 | 'proxy', 74 | 'authType', 75 | 'encoding', 76 | ] as $name) { 77 | if ($this->$name !== null) { 78 | $config[$name] = $this->$name; 79 | } 80 | } 81 | 82 | return new WebDAVAdapter( 83 | new Client($config), 84 | $this->prefix 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/RackspaceFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class RackspaceFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $endpoint; 25 | /** 26 | * @var string 27 | */ 28 | public $username; 29 | /** 30 | * @var string 31 | */ 32 | public $apiKey; 33 | /** 34 | * @var string 35 | */ 36 | public $region; 37 | /** 38 | * @var string 39 | */ 40 | public $container; 41 | /** 42 | * @var string|null 43 | */ 44 | public $prefix; 45 | 46 | /** 47 | * @inheritdoc 48 | */ 49 | public function init() 50 | { 51 | if ($this->endpoint === null) { 52 | throw new InvalidConfigException('The "endpoint" property must be set.'); 53 | } 54 | 55 | if ($this->username === null) { 56 | throw new InvalidConfigException('The "username" property must be set.'); 57 | } 58 | 59 | if ($this->apiKey === null) { 60 | throw new InvalidConfigException('The "apiKey" property must be set.'); 61 | } 62 | 63 | if ($this->region === null) { 64 | throw new InvalidConfigException('The "region" property must be set.'); 65 | } 66 | 67 | if ($this->container === null) { 68 | throw new InvalidConfigException('The "container" property must be set.'); 69 | } 70 | 71 | parent::init(); 72 | } 73 | 74 | /** 75 | * @return RackspaceAdapter 76 | */ 77 | protected function prepareAdapter() 78 | { 79 | return new RackspaceAdapter( 80 | (new Rackspace($this->endpoint, [ 81 | 'username' => $this->username, 82 | 'apiKey' => $this->apiKey] 83 | ))->objectStoreService('cloudFiles', $this->region)->getContainer($this->container), 84 | $this->prefix 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/FtpFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class FtpFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $host; 25 | /** 26 | * @var integer 27 | */ 28 | public $port; 29 | /** 30 | * @var string 31 | */ 32 | public $username; 33 | /** 34 | * @var string 35 | */ 36 | public $password; 37 | /** 38 | * @var boolean 39 | */ 40 | public $ssl; 41 | /** 42 | * @var integer 43 | */ 44 | public $timeout; 45 | /** 46 | * @var string 47 | */ 48 | public $root; 49 | /** 50 | * @var integer 51 | */ 52 | public $permPrivate; 53 | /** 54 | * @var integer 55 | */ 56 | public $permPublic; 57 | /** 58 | * @var boolean 59 | */ 60 | public $passive; 61 | /** 62 | * @var integer 63 | */ 64 | public $transferMode; 65 | /** 66 | * @var bool 67 | */ 68 | public $enableTimestampsOnUnixListings = false; 69 | 70 | /** 71 | * @inheritdoc 72 | */ 73 | public function init() 74 | { 75 | if ($this->host === null) { 76 | throw new InvalidConfigException('The "host" property must be set.'); 77 | } 78 | 79 | if ($this->root !== null) { 80 | $this->root = Yii::getAlias($this->root); 81 | } 82 | 83 | parent::init(); 84 | } 85 | 86 | /** 87 | * @return Ftp 88 | */ 89 | protected function prepareAdapter() 90 | { 91 | $config = []; 92 | 93 | foreach ([ 94 | 'host', 95 | 'port', 96 | 'username', 97 | 'password', 98 | 'ssl', 99 | 'timeout', 100 | 'root', 101 | 'permPrivate', 102 | 'permPublic', 103 | 'passive', 104 | 'transferMode', 105 | 'enableTimestampsOnUnixListings', 106 | ] as $name) { 107 | if ($this->$name !== null) { 108 | $config[$name] = $this->$name; 109 | } 110 | } 111 | 112 | return new Ftp($config); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/SftpFilesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class SftpFilesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $host; 25 | /** 26 | * @var string 27 | */ 28 | public $port; 29 | /** 30 | * @var string 31 | */ 32 | public $username; 33 | /** 34 | * @var string 35 | */ 36 | public $password; 37 | /** 38 | * @var integer 39 | */ 40 | public $timeout; 41 | /** 42 | * @var string 43 | */ 44 | public $root; 45 | /** 46 | * @var string 47 | */ 48 | public $privateKey; 49 | /** 50 | * @var integer 51 | */ 52 | public $permPrivate; 53 | /** 54 | * @var integer 55 | */ 56 | public $permPublic; 57 | /** 58 | * @var integer 59 | */ 60 | public $directoryPerm; 61 | 62 | /** 63 | * @inheritdoc 64 | */ 65 | public function init() 66 | { 67 | if ($this->host === null) { 68 | throw new InvalidConfigException('The "host" property must be set.'); 69 | } 70 | 71 | if ($this->username === null) { 72 | throw new InvalidConfigException('The "username" property must be set.'); 73 | } 74 | 75 | if ($this->password === null && $this->privateKey === null) { 76 | throw new InvalidConfigException('Either "password" or "privateKey" property must be set.'); 77 | } 78 | 79 | if ($this->root !== null) { 80 | $this->root = Yii::getAlias($this->root); 81 | } 82 | 83 | parent::init(); 84 | } 85 | 86 | /** 87 | * @return SftpAdapter 88 | */ 89 | protected function prepareAdapter() 90 | { 91 | $config = []; 92 | 93 | foreach ([ 94 | 'host', 95 | 'port', 96 | 'username', 97 | 'password', 98 | 'timeout', 99 | 'root', 100 | 'privateKey', 101 | 'permPrivate', 102 | 'permPublic', 103 | 'directoryPerm', 104 | ] as $name) { 105 | if ($this->$name !== null) { 106 | $config[$name] = $this->$name; 107 | } 108 | } 109 | 110 | return new SftpAdapter($config); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/AwsS3Filesystem.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class AwsS3Filesystem extends Filesystem 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $key; 25 | /** 26 | * @var string 27 | */ 28 | public $secret; 29 | /** 30 | * @var string 31 | */ 32 | public $region; 33 | /** 34 | * @var string 35 | */ 36 | public $baseUrl; 37 | /** 38 | * @var string 39 | */ 40 | public $version; 41 | /** 42 | * @var string 43 | */ 44 | public $bucket; 45 | /** 46 | * @var string|null 47 | */ 48 | public $prefix; 49 | /** 50 | * @var bool 51 | */ 52 | public $pathStyleEndpoint = false; 53 | /** 54 | * @var array 55 | */ 56 | public $options = []; 57 | /** 58 | * @var bool 59 | */ 60 | public $streamReads = false; 61 | /** 62 | * @var string 63 | */ 64 | public $endpoint; 65 | /** 66 | * @var array|\Aws\CacheInterface|\Aws\Credentials\CredentialsInterface|bool|callable 67 | */ 68 | public $credentials; 69 | 70 | /** 71 | * @inheritdoc 72 | */ 73 | public function init() 74 | { 75 | if ($this->credentials === null) { 76 | if ($this->key === null) { 77 | throw new InvalidConfigException('The "key" property must be set.'); 78 | } 79 | 80 | if ($this->secret === null) { 81 | throw new InvalidConfigException('The "secret" property must be set.'); 82 | } 83 | } 84 | 85 | if ($this->bucket === null) { 86 | throw new InvalidConfigException('The "bucket" property must be set.'); 87 | } 88 | 89 | parent::init(); 90 | } 91 | 92 | /** 93 | * @return AwsS3Adapter 94 | */ 95 | protected function prepareAdapter() 96 | { 97 | $config = []; 98 | 99 | if ($this->credentials === null) { 100 | $config['credentials'] = ['key' => $this->key, 'secret' => $this->secret]; 101 | } else { 102 | $config['credentials'] = $this->credentials; 103 | } 104 | 105 | 106 | if ($this->pathStyleEndpoint === true) { 107 | $config['use_path_style_endpoint'] = true; 108 | } 109 | 110 | if ($this->region !== null) { 111 | $config['region'] = $this->region; 112 | } 113 | 114 | if ($this->baseUrl !== null) { 115 | $config['base_url'] = $this->baseUrl; 116 | } 117 | 118 | if ($this->endpoint !== null) { 119 | $config['endpoint'] = $this->endpoint; 120 | } 121 | 122 | $config['version'] = (($this->version !== null) ? $this->version : 'latest'); 123 | 124 | $client = new S3Client($config); 125 | 126 | return new AwsS3Adapter($client, $this->bucket, $this->prefix, $this->options, $this->streamReads); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Filesystem.php: -------------------------------------------------------------------------------- 1 | 56 | */ 57 | abstract class Filesystem extends Component 58 | { 59 | /** 60 | * @var \League\Flysystem\Config|array|string|null 61 | */ 62 | public $config; 63 | /** 64 | * @var string|null 65 | */ 66 | public $cache; 67 | /** 68 | * @var string 69 | */ 70 | public $cacheKey = 'flysystem'; 71 | /** 72 | * @var integer 73 | */ 74 | public $cacheDuration = 3600; 75 | /** 76 | * @var string|null 77 | */ 78 | public $replica; 79 | /** 80 | * @var \League\Flysystem\FilesystemInterface 81 | */ 82 | protected $filesystem; 83 | 84 | /** 85 | * @inheritdoc 86 | */ 87 | public function init() 88 | { 89 | $adapter = $this->prepareAdapter(); 90 | 91 | if ($this->cache !== null) { 92 | /* @var Cache $cache */ 93 | $cache = Yii::$app->get($this->cache); 94 | 95 | if (!$cache instanceof Cache) { 96 | throw new InvalidConfigException('The "cache" property must be an instance of \yii\caching\Cache subclasses.'); 97 | } 98 | 99 | $adapter = new CachedAdapter($adapter, new YiiCache($cache, $this->cacheKey, $this->cacheDuration)); 100 | } 101 | 102 | if ($this->replica !== null) { 103 | /* @var Filesystem $filesystem */ 104 | $filesystem = Yii::$app->get($this->replica); 105 | 106 | if (!$filesystem instanceof Filesystem) { 107 | throw new InvalidConfigException('The "replica" property must be an instance of \creocoder\flysystem\Filesystem subclasses.'); 108 | } 109 | 110 | $adapter = new ReplicateAdapter($adapter, $filesystem->getAdapter()); 111 | } 112 | 113 | $this->filesystem = new NativeFilesystem($adapter, $this->config); 114 | } 115 | 116 | /** 117 | * @return AdapterInterface 118 | */ 119 | abstract protected function prepareAdapter(); 120 | 121 | /** 122 | * @param string $method 123 | * @param array $parameters 124 | * @return mixed 125 | */ 126 | public function __call($method, $parameters) 127 | { 128 | return call_user_func_array([$this->filesystem, $method], $parameters); 129 | } 130 | 131 | /** 132 | * @return \League\Flysystem\FilesystemInterface 133 | */ 134 | public function getFilesystem() 135 | { 136 | return $this->filesystem; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flysystem Extension for Yii 2 2 | 3 | [![Code Quality](https://img.shields.io/scrutinizer/g/creocoder/yii2-flysystem/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/creocoder/yii2-flysystem/?branch=master) 4 | [![Packagist Version](https://img.shields.io/packagist/v/creocoder/yii2-flysystem.svg?style=flat-square)](https://packagist.org/packages/creocoder/yii2-flysystem) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/creocoder/yii2-flysystem.svg?style=flat-square)](https://packagist.org/packages/creocoder/yii2-flysystem) 6 | 7 | This extension provides [Flysystem](http://flysystem.thephpleague.com/) integration for the Yii framework. 8 | [Flysystem](http://flysystem.thephpleague.com/) is a filesystem abstraction which allows you to easily swap out a local filesystem for a remote one. 9 | 10 | ## Installation 11 | 12 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 13 | 14 | Either run 15 | 16 | ```bash 17 | $ composer require creocoder/yii2-flysystem 18 | ``` 19 | 20 | or add 21 | 22 | ``` 23 | "creocoder/yii2-flysystem": "0.8.*" 24 | ``` 25 | 26 | to the `require` section of your `composer.json` file. 27 | 28 | ## Configuring 29 | 30 | ### Local filesystem 31 | 32 | Configure application `components` as follows 33 | 34 | ```php 35 | return [ 36 | //... 37 | 'components' => [ 38 | //... 39 | 'fs' => [ 40 | 'class' => 'creocoder\flysystem\LocalFilesystem', 41 | 'path' => '@webroot/files', 42 | // 'writeFlags' => LOCK_EX, 43 | // 'linkHandling' => 0002, 44 | // 'permissions' => [], 45 | ], 46 | ], 47 | ]; 48 | ``` 49 | 50 | ### FTP filesystem 51 | 52 | Configure application `components` as follows 53 | 54 | ```php 55 | return [ 56 | //... 57 | 'components' => [ 58 | //... 59 | 'ftpFs' => [ 60 | 'class' => 'creocoder\flysystem\FtpFilesystem', 61 | 'host' => 'ftp.example.com', 62 | // 'port' => 21, 63 | // 'username' => 'your-username', 64 | // 'password' => 'your-password', 65 | // 'ssl' => true, 66 | // 'timeout' => 60, 67 | // 'root' => '/path/to/root', 68 | // 'permPrivate' => 0700, 69 | // 'permPublic' => 0744, 70 | // 'passive' => false, 71 | // 'transferMode' => FTP_TEXT, 72 | ], 73 | ], 74 | ]; 75 | ``` 76 | 77 | ### NULL filesystem 78 | 79 | Configure application `components` as follows 80 | 81 | ```php 82 | return [ 83 | //... 84 | 'components' => [ 85 | //... 86 | 'nullFs' => [ 87 | 'class' => 'creocoder\flysystem\NullFilesystem', 88 | ], 89 | ], 90 | ]; 91 | ``` 92 | 93 | ### AWS S3 filesystem 94 | 95 | Either run 96 | 97 | ```bash 98 | $ composer require league/flysystem-aws-s3-v3 99 | ``` 100 | 101 | or add 102 | 103 | ``` 104 | "league/flysystem-aws-s3-v3": "~1.0" 105 | ``` 106 | 107 | to the `require` section of your `composer.json` file and configure application `components` as follows 108 | 109 | ```php 110 | return [ 111 | //... 112 | 'components' => [ 113 | //... 114 | 'awss3Fs' => [ 115 | 'class' => 'creocoder\flysystem\AwsS3Filesystem', 116 | 'key' => 'your-key', 117 | 'secret' => 'your-secret', 118 | 'bucket' => 'your-bucket', 119 | 'region' => 'your-region', 120 | // 'version' => 'latest', 121 | // 'baseUrl' => 'your-base-url', 122 | // 'prefix' => 'your-prefix', 123 | // 'options' => [], 124 | // 'endpoint' => 'http://my-custom-url' 125 | ], 126 | ], 127 | ]; 128 | ``` 129 | 130 | ### Azure filesystem 131 | 132 | Add the following to the `repositories` section of your `composer.json` 133 | 134 | ``` 135 | { 136 | "type": "pear", 137 | "url": "http://pear.php.net" 138 | } 139 | ``` 140 | 141 | Either run 142 | 143 | ```bash 144 | $ composer require league/flysystem-azure 145 | ``` 146 | 147 | or add 148 | 149 | ``` 150 | "league/flysystem-azure": "~1.0" 151 | ``` 152 | 153 | to the `require` section of your `composer.json` file and configure application `components` as follows 154 | 155 | ```php 156 | return [ 157 | //... 158 | 'components' => [ 159 | //... 160 | 'azureFs' => [ 161 | 'class' => 'creocoder\flysystem\AzureFilesystem', 162 | 'accountName' => 'your-account-name', 163 | 'accountKey' => 'your-account-key', 164 | 'container' => 'your-container', 165 | ], 166 | ], 167 | ]; 168 | ``` 169 | 170 | ### Copy filesystem 171 | 172 | Either run 173 | 174 | ```bash 175 | $ composer require league/flysystem-copy 176 | ``` 177 | 178 | or add 179 | 180 | ``` 181 | "league/flysystem-copy": "~1.0" 182 | ``` 183 | 184 | to the `require` section of your `composer.json` file and configure application `components` as follows 185 | 186 | ```php 187 | return [ 188 | //... 189 | 'components' => [ 190 | //... 191 | 'copyFs' => [ 192 | 'class' => 'creocoder\flysystem\CopyFilesystem', 193 | 'consumerKey' => 'your-consumer-key', 194 | 'consumerSecret' => 'your-consumer-secret', 195 | 'accessToken' => 'your-access-token', 196 | 'tokenSecret' => 'your-token-secret', 197 | // 'prefix' => 'your-prefix', 198 | ], 199 | ], 200 | ]; 201 | ``` 202 | 203 | ### Dropbox filesystem 204 | 205 | Either run 206 | 207 | ```bash 208 | $ composer require league/flysystem-dropbox 209 | ``` 210 | 211 | or add 212 | 213 | ``` 214 | "league/flysystem-dropbox": "~1.0" 215 | ``` 216 | 217 | to the `require` section of your `composer.json` file and configure application `components` as follows 218 | 219 | ```php 220 | return [ 221 | //... 222 | 'components' => [ 223 | //... 224 | 'dropboxFs' => [ 225 | 'class' => 'creocoder\flysystem\DropboxFilesystem', 226 | 'token' => 'your-token', 227 | 'app' => 'your-app', 228 | // 'prefix' => 'your-prefix', 229 | ], 230 | ], 231 | ]; 232 | ``` 233 | 234 | ## Google Cloud filesystem 235 | 236 | Run 237 | 238 | ```bash 239 | $ composer require "superbalist/flysystem-google-storage": "^5.0" 240 | ``` 241 | 242 | and configure application `components` as follows 243 | 244 | ```php 245 | return [ 246 | //... 247 | 'components' => [ 248 | //... 249 | 'googleCloudFs' => [ 250 | 'class' => 'creocoder\flysystem\GoogleCloudFilesystem', 251 | 'projectId' => 'GOOGLE_PROJECT_ID', 252 | 'bucket' => 'GOOGLE_BUCKET', 253 | 'keyFilePath' => 'GOOGLE_KEY_FILE_PATH', 254 | ], 255 | ], 256 | ]; 257 | ``` 258 | 259 | > Note: Credential configuration is read from the *keyFile*. 260 | 261 | ### GridFS filesystem 262 | 263 | Either run 264 | 265 | ```bash 266 | $ composer require league/flysystem-gridfs 267 | ``` 268 | 269 | or add 270 | 271 | ``` 272 | "league/flysystem-gridfs": "~1.0" 273 | ``` 274 | 275 | to the `require` section of your `composer.json` file and configure application `components` as follows 276 | 277 | ```php 278 | return [ 279 | //... 280 | 'components' => [ 281 | //... 282 | 'gridFs' => [ 283 | 'class' => 'creocoder\flysystem\GridFSFilesystem', 284 | 'server' => 'mongodb://localhost:27017', 285 | 'database' => 'your-database', 286 | ], 287 | ], 288 | ]; 289 | ``` 290 | 291 | ### Rackspace filesystem 292 | 293 | Either run 294 | 295 | ```bash 296 | $ composer require league/flysystem-rackspace 297 | ``` 298 | 299 | or add 300 | 301 | ``` 302 | "league/flysystem-rackspace": "~1.0" 303 | ``` 304 | 305 | to the `require` section of your `composer.json` file and configure application `components` as follows 306 | 307 | ```php 308 | return [ 309 | //... 310 | 'components' => [ 311 | //... 312 | 'rackspaceFs' => [ 313 | 'class' => 'creocoder\flysystem\RackspaceFilesystem', 314 | 'endpoint' => 'your-endpoint', 315 | 'region' => 'your-region', 316 | 'username' => 'your-username', 317 | 'apiKey' => 'your-api-key', 318 | 'container' => 'your-container', 319 | // 'prefix' => 'your-prefix', 320 | ], 321 | ], 322 | ]; 323 | ``` 324 | 325 | ### SFTP filesystem 326 | 327 | Either run 328 | 329 | ```bash 330 | $ composer require league/flysystem-sftp 331 | ``` 332 | 333 | or add 334 | 335 | ``` 336 | "league/flysystem-sftp": "~1.0" 337 | ``` 338 | 339 | to the `require` section of your `composer.json` file and configure application `components` as follows 340 | 341 | ```php 342 | return [ 343 | //... 344 | 'components' => [ 345 | //... 346 | 'sftpFs' => [ 347 | 'class' => 'creocoder\flysystem\SftpFilesystem', 348 | 'host' => 'sftp.example.com', 349 | // 'port' => 22, 350 | 'username' => 'your-username', 351 | 'password' => 'your-password', 352 | 'privateKey' => '/path/to/or/contents/of/privatekey', 353 | // 'timeout' => 60, 354 | // 'root' => '/path/to/root', 355 | // 'permPrivate' => 0700, 356 | // 'permPublic' => 0744, 357 | ], 358 | ], 359 | ]; 360 | ``` 361 | 362 | ### WebDAV filesystem 363 | 364 | Either run 365 | 366 | ```bash 367 | $ composer require league/flysystem-webdav 368 | ``` 369 | 370 | or add 371 | 372 | ``` 373 | "league/flysystem-webdav": "~1.0" 374 | ``` 375 | 376 | to the `require` section of your `composer.json` file and configure application `components` as follows 377 | 378 | ```php 379 | return [ 380 | //... 381 | 'components' => [ 382 | //... 383 | 'webdavFs' => [ 384 | 'class' => 'creocoder\flysystem\WebDAVFilesystem', 385 | 'baseUri' => 'your-base-uri', 386 | // 'userName' => 'your-user-name', 387 | // 'password' => 'your-password', 388 | // 'proxy' => 'your-proxy', 389 | // 'authType' => \Sabre\DAV\Client::AUTH_BASIC, 390 | // 'encoding' => \Sabre\DAV\Client::ENCODING_IDENTITY, 391 | // 'prefix' => 'your-prefix', 392 | ], 393 | ], 394 | ]; 395 | ``` 396 | 397 | ### ZipArchive filesystem 398 | 399 | Either run 400 | 401 | ```bash 402 | $ composer require league/flysystem-ziparchive 403 | ``` 404 | 405 | or add 406 | 407 | ``` 408 | "league/flysystem-ziparchive": "~1.0" 409 | ``` 410 | 411 | to the `require` section of your `composer.json` file and configure application `components` as follows 412 | 413 | ```php 414 | return [ 415 | //... 416 | 'components' => [ 417 | //... 418 | 'ziparchiveFs' => [ 419 | 'class' => 'creocoder\flysystem\ZipArchiveFilesystem', 420 | 'path' => '@webroot/files/archive.zip', 421 | // 'prefix' => 'your-prefix', 422 | ], 423 | ], 424 | ]; 425 | ``` 426 | 427 | ### Caching feature 428 | 429 | Either run 430 | 431 | ```bash 432 | $ composer require league/flysystem-cached-adapter 433 | ``` 434 | 435 | or add 436 | 437 | ``` 438 | "league/flysystem-cached-adapter": "~1.0" 439 | ``` 440 | 441 | to the `require` section of your `composer.json` file and configure `fsID` application component as follows 442 | 443 | ```php 444 | return [ 445 | //... 446 | 'components' => [ 447 | //... 448 | 'fsID' => [ 449 | //... 450 | 'cache' => 'cacheID', 451 | // 'cacheKey' => 'flysystem', 452 | // 'cacheDuration' => 3600, 453 | ], 454 | ], 455 | ]; 456 | ``` 457 | 458 | ### Replication feature 459 | 460 | Either run 461 | 462 | ```bash 463 | $ composer require league/flysystem-replicate-adapter 464 | ``` 465 | 466 | or add 467 | 468 | ``` 469 | "league/flysystem-replicate-adapter": "~1.0" 470 | ``` 471 | 472 | to the `require` section of your `composer.json` file and configure `fsID` application component as follows 473 | 474 | ```php 475 | return [ 476 | //... 477 | 'components' => [ 478 | //... 479 | 'fsID' => [ 480 | //... 481 | 'replica' => 'anotherFsID', 482 | ], 483 | ], 484 | ]; 485 | ``` 486 | 487 | ### Global visibility settings 488 | 489 | Configure `fsID` application component as follows 490 | 491 | ```php 492 | return [ 493 | //... 494 | 'components' => [ 495 | //... 496 | 'fsID' => [ 497 | //... 498 | 'config' => [ 499 | 'visibility' => \League\Flysystem\AdapterInterface::VISIBILITY_PRIVATE, 500 | ], 501 | ], 502 | ], 503 | ]; 504 | ``` 505 | 506 | ## Usage 507 | 508 | ### Writing files 509 | 510 | To write file 511 | 512 | ```php 513 | Yii::$app->fs->write('filename.ext', 'contents'); 514 | ``` 515 | 516 | To write file using stream contents 517 | 518 | ```php 519 | $stream = fopen('/path/to/somefile.ext', 'r+'); 520 | Yii::$app->fs->writeStream('filename.ext', $stream); 521 | ``` 522 | 523 | ### Updating files 524 | 525 | To update file 526 | 527 | ```php 528 | Yii::$app->fs->update('filename.ext', 'contents'); 529 | ``` 530 | 531 | To update file using stream contents 532 | 533 | ```php 534 | $stream = fopen('/path/to/somefile.ext', 'r+'); 535 | Yii::$app->fs->updateStream('filename.ext', $stream); 536 | ``` 537 | 538 | ### Writing or updating files 539 | 540 | To write or update file 541 | 542 | ```php 543 | Yii::$app->fs->put('filename.ext', 'contents'); 544 | ``` 545 | 546 | To write or update file using stream contents 547 | 548 | ```php 549 | $stream = fopen('/path/to/somefile.ext', 'r+'); 550 | Yii::$app->fs->putStream('filename.ext', $stream); 551 | ``` 552 | 553 | ### Reading files 554 | 555 | To read file 556 | 557 | ```php 558 | $contents = Yii::$app->fs->read('filename.ext'); 559 | ``` 560 | 561 | To retrieve a read-stream 562 | 563 | ```php 564 | $stream = Yii::$app->fs->readStream('filename.ext'); 565 | $contents = stream_get_contents($stream); 566 | fclose($stream); 567 | ``` 568 | 569 | ### Checking if a file exists 570 | 571 | To check if a file exists 572 | 573 | ```php 574 | $exists = Yii::$app->fs->has('filename.ext'); 575 | ``` 576 | 577 | ### Deleting files 578 | 579 | To delete file 580 | 581 | ```php 582 | Yii::$app->fs->delete('filename.ext'); 583 | ``` 584 | 585 | ### Reading and deleting files 586 | 587 | To read and delete file 588 | 589 | ```php 590 | $contents = Yii::$app->fs->readAndDelete('filename.ext'); 591 | ``` 592 | 593 | ### Renaming files 594 | 595 | To rename file 596 | 597 | ```php 598 | Yii::$app->fs->rename('filename.ext', 'newname.ext'); 599 | ``` 600 | 601 | ### Getting files mimetype 602 | 603 | To get file mimetype 604 | 605 | ```php 606 | $mimetype = Yii::$app->fs->getMimetype('filename.ext'); 607 | ``` 608 | 609 | ### Getting files timestamp 610 | 611 | To get file timestamp 612 | 613 | ```php 614 | $timestamp = Yii::$app->fs->getTimestamp('filename.ext'); 615 | ``` 616 | 617 | ### Getting files size 618 | 619 | To get file size 620 | 621 | ```php 622 | $timestamp = Yii::$app->fs->getSize('filename.ext'); 623 | ``` 624 | 625 | ### Creating directories 626 | 627 | To create directory 628 | 629 | ```php 630 | Yii::$app->fs->createDir('path/to/directory'); 631 | ``` 632 | 633 | Directories are also made implicitly when writing to a deeper path 634 | 635 | ```php 636 | Yii::$app->fs->write('path/to/filename.ext'); 637 | ``` 638 | 639 | ### Deleting directories 640 | 641 | To delete directory 642 | 643 | ```php 644 | Yii::$app->fs->deleteDir('path/to/filename.ext'); 645 | ``` 646 | 647 | ### Managing visibility 648 | 649 | Visibility is the abstraction of file permissions across multiple platforms. Visibility can be either public or private. 650 | 651 | ```php 652 | use League\Flysystem\AdapterInterface; 653 | 654 | Yii::$app->fs->write('filename.ext', 'contents', [ 655 | 'visibility' => AdapterInterface::VISIBILITY_PRIVATE 656 | ]); 657 | ``` 658 | 659 | You can also change and check visibility of existing files 660 | 661 | ```php 662 | use League\Flysystem\AdapterInterface; 663 | 664 | if (Yii::$app->fs->getVisibility('filename.ext') === AdapterInterface::VISIBILITY_PRIVATE) { 665 | Yii::$app->fs->setVisibility('filename.ext', AdapterInterface::VISIBILITY_PUBLIC); 666 | } 667 | ``` 668 | 669 | ### Listing contents 670 | 671 | To list contents 672 | 673 | ```php 674 | $contents = Yii::$app->fs->listContents(); 675 | 676 | foreach ($contents as $object) { 677 | echo $object['basename'] 678 | . ' is located at' . $object['path'] 679 | . ' and is a ' . $object['type']; 680 | } 681 | ``` 682 | 683 | By default Flysystem lists the top directory non-recursively. You can supply a directory name and recursive boolean to get more precise results 684 | 685 | ```php 686 | $contents = Yii::$app->fs->listContents('path/to/directory', true); 687 | ``` 688 | 689 | ### Listing paths 690 | 691 | To list paths 692 | 693 | ```php 694 | $paths = Yii::$app->fs->listPaths(); 695 | 696 | foreach ($paths as $path) { 697 | echo $path; 698 | } 699 | ``` 700 | 701 | ### Listing with ensured presence of specific metadata 702 | 703 | To list with ensured presence of specific metadata 704 | 705 | ```php 706 | $listing = Yii::$app->fs->listWith( 707 | ['mimetype', 'size', 'timestamp'], 708 | 'optional/path/to/directory', 709 | true 710 | ); 711 | 712 | foreach ($listing as $object) { 713 | echo $object['path'] . ' has mimetype: ' . $object['mimetype']; 714 | } 715 | ``` 716 | 717 | ### Getting file info with explicit metadata 718 | 719 | To get file info with explicit metadata 720 | 721 | ```php 722 | $info = Yii::$app->fs->getWithMetadata('path/to/filename.ext', ['timestamp', 'mimetype']); 723 | echo $info['mimetype']; 724 | echo $info['timestamp']; 725 | ``` 726 | 727 | ## Donating 728 | 729 | Support this project and [others by creocoder](https://gratipay.com/creocoder/) via [gratipay](https://gratipay.com/creocoder/). 730 | 731 | [![Support via Gratipay](https://cdn.rawgit.com/gratipay/gratipay-badge/2.3.0/dist/gratipay.svg)](https://gratipay.com/creocoder/) 732 | --------------------------------------------------------------------------------