diff --git a/README.md b/README.md index 1011ec4..d9a869e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ This extension provides [Flysystem](http://flysystem.thephpleague.com/) integration for the Yii framework. [Flysystem](http://flysystem.thephpleague.com/) is a filesystem abstraction which allows you to easily swap out a local filesystem for a remote one. +**This version requires Flysystem 3.x and PHP 8.1+** + ## Installation The preferred way to install this extension is through [composer](http://getcomposer.org/download/). @@ -20,7 +22,7 @@ $ composer require creocoder/yii2-flysystem or add ``` -"creocoder/yii2-flysystem": "0.8.*" +"creocoder/yii2-flysystem": "^2.0" ``` to the `require` section of your `composer.json` file. @@ -37,11 +39,8 @@ return [ 'components' => [ //... 'fs' => [ - 'class' => 'creocoder\flysystem\LocalFilesystem', + 'class' => \creocoder\flysystem\LocalFilesystem::class, 'path' => '@webroot/files', - // 'writeFlags' => LOCK_EX, - // 'linkHandling' => 0002, - // 'permissions' => [], ], ], ]; @@ -49,7 +48,19 @@ return [ ### FTP filesystem -Configure application `components` as follows +Either run + +```bash +$ composer require league/flysystem-ftp +``` + +or add + +``` +"league/flysystem-ftp": "^3.0" +``` + +to the `require` section of your `composer.json` file and configure application `components` as follows ```php return [ @@ -57,24 +68,21 @@ return [ 'components' => [ //... 'ftpFs' => [ - 'class' => 'creocoder\flysystem\FtpFilesystem', + 'class' => \creocoder\flysystem\FtpFilesystem::class, 'host' => 'ftp.example.com', // 'port' => 21, // 'username' => 'your-username', // 'password' => 'your-password', // 'ssl' => true, - // 'timeout' => 60, + // 'timeout' => 90, // 'root' => '/path/to/root', - // 'permPrivate' => 0700, - // 'permPublic' => 0744, - // 'passive' => false, - // 'transferMode' => FTP_TEXT, + // 'passive' => true, ], ], ]; ``` -### NULL filesystem +### In-Memory filesystem Configure application `components` as follows @@ -83,8 +91,8 @@ return [ //... 'components' => [ //... - 'nullFs' => [ - 'class' => 'creocoder\flysystem\NullFilesystem', + 'memoryFs' => [ + 'class' => \creocoder\flysystem\InMemoryFilesystem::class, ], ], ]; @@ -101,7 +109,7 @@ $ composer require league/flysystem-aws-s3-v3 or add ``` -"league/flysystem-aws-s3-v3": "~1.0" +"league/flysystem-aws-s3-v3": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -112,42 +120,31 @@ return [ 'components' => [ //... 'awss3Fs' => [ - 'class' => 'creocoder\flysystem\AwsS3Filesystem', + 'class' => \creocoder\flysystem\AwsS3Filesystem::class, 'key' => 'your-key', 'secret' => 'your-secret', 'bucket' => 'your-bucket', 'region' => 'your-region', // 'version' => 'latest', - // 'baseUrl' => 'your-base-url', // 'prefix' => 'your-prefix', - // 'options' => [], // 'endpoint' => 'http://my-custom-url' ], ], ]; ``` -### Azure filesystem - -Add the following to the `repositories` section of your `composer.json` - -``` -{ - "type": "pear", - "url": "http://pear.php.net" -} -``` +### Azure Blob Storage filesystem Either run ```bash -$ composer require league/flysystem-azure +$ composer require league/flysystem-azure-blob-storage ``` or add ``` -"league/flysystem-azure": "~1.0" +"league/flysystem-azure-blob-storage": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -158,42 +155,10 @@ return [ 'components' => [ //... 'azureFs' => [ - 'class' => 'creocoder\flysystem\AzureFilesystem', + 'class' => \creocoder\flysystem\AzureFilesystem::class, 'accountName' => 'your-account-name', 'accountKey' => 'your-account-key', 'container' => 'your-container', - ], - ], -]; -``` - -### Copy filesystem - -Either run - -```bash -$ composer require league/flysystem-copy -``` - -or add - -``` -"league/flysystem-copy": "~1.0" -``` - -to the `require` section of your `composer.json` file and configure application `components` as follows - -```php -return [ - //... - 'components' => [ - //... - 'copyFs' => [ - 'class' => 'creocoder\flysystem\CopyFilesystem', - 'consumerKey' => 'your-consumer-key', - 'consumerSecret' => 'your-consumer-secret', - 'accessToken' => 'your-access-token', - 'tokenSecret' => 'your-token-secret', // 'prefix' => 'your-prefix', ], ], @@ -205,13 +170,13 @@ return [ Either run ```bash -$ composer require league/flysystem-dropbox +$ composer require spatie/flysystem-dropbox ``` or add ``` -"league/flysystem-dropbox": "~1.0" +"spatie/flysystem-dropbox": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -222,21 +187,20 @@ return [ 'components' => [ //... 'dropboxFs' => [ - 'class' => 'creocoder\flysystem\DropboxFilesystem', + 'class' => \creocoder\flysystem\DropboxFilesystem::class, 'token' => 'your-token', - 'app' => 'your-app', // 'prefix' => 'your-prefix', ], ], ]; ``` -## Google Cloud filesystem +### Google Cloud Storage filesystem Run ```bash -$ composer require "superbalist/flysystem-google-storage": "^5.0" +$ composer require league/flysystem-google-cloud-storage ``` and configure application `components` as follows @@ -247,16 +211,17 @@ return [ 'components' => [ //... 'googleCloudFs' => [ - 'class' => 'creocoder\flysystem\GoogleCloudFilesystem', + 'class' => \creocoder\flysystem\GoogleCloudFilesystem::class, 'projectId' => 'GOOGLE_PROJECT_ID', 'bucket' => 'GOOGLE_BUCKET', - 'keyFilePath' => 'GOOGLE_KEY_FILE_PATH', + 'keyFilePath' => '@app/config/google-credentials.json', + // 'prefix' => 'your-prefix', ], ], ]; ``` -> Note: Credential configuration is read from the *keyFile*. +> Note: Credential configuration is read from the *keyFilePath*. ### GridFS filesystem @@ -269,7 +234,7 @@ $ composer require league/flysystem-gridfs or add ``` -"league/flysystem-gridfs": "~1.0" +"league/flysystem-gridfs": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -280,43 +245,10 @@ return [ 'components' => [ //... 'gridFs' => [ - 'class' => 'creocoder\flysystem\GridFSFilesystem', - 'server' => 'mongodb://localhost:27017', + 'class' => \creocoder\flysystem\GridFSFilesystem::class, + 'uri' => 'mongodb://localhost:27017', 'database' => 'your-database', - ], - ], -]; -``` - -### Rackspace filesystem - -Either run - -```bash -$ composer require league/flysystem-rackspace -``` - -or add - -``` -"league/flysystem-rackspace": "~1.0" -``` - -to the `require` section of your `composer.json` file and configure application `components` as follows - -```php -return [ - //... - 'components' => [ - //... - 'rackspaceFs' => [ - 'class' => 'creocoder\flysystem\RackspaceFilesystem', - 'endpoint' => 'your-endpoint', - 'region' => 'your-region', - 'username' => 'your-username', - 'apiKey' => 'your-api-key', - 'container' => 'your-container', - // 'prefix' => 'your-prefix', + // 'bucketName' => 'fs', ], ], ]; @@ -327,13 +259,13 @@ return [ Either run ```bash -$ composer require league/flysystem-sftp +$ composer require league/flysystem-sftp-v3 ``` or add ``` -"league/flysystem-sftp": "~1.0" +"league/flysystem-sftp-v3": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -344,16 +276,15 @@ return [ 'components' => [ //... 'sftpFs' => [ - 'class' => 'creocoder\flysystem\SftpFilesystem', + 'class' => \creocoder\flysystem\SftpFilesystem::class, 'host' => 'sftp.example.com', // 'port' => 22, 'username' => 'your-username', 'password' => 'your-password', - 'privateKey' => '/path/to/or/contents/of/privatekey', - // 'timeout' => 60, + // 'privateKey' => '/path/to/or/contents/of/privatekey', + // 'passphrase' => 'your-passphrase', + // 'timeout' => 10, // 'root' => '/path/to/root', - // 'permPrivate' => 0700, - // 'permPublic' => 0744, ], ], ]; @@ -370,7 +301,7 @@ $ composer require league/flysystem-webdav or add ``` -"league/flysystem-webdav": "~1.0" +"league/flysystem-webdav": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -381,13 +312,11 @@ return [ 'components' => [ //... 'webdavFs' => [ - 'class' => 'creocoder\flysystem\WebDAVFilesystem', + 'class' => \creocoder\flysystem\WebDAVFilesystem::class, 'baseUri' => 'your-base-uri', // 'userName' => 'your-user-name', // 'password' => 'your-password', // 'proxy' => 'your-proxy', - // 'authType' => \Sabre\DAV\Client::AUTH_BASIC, - // 'encoding' => \Sabre\DAV\Client::ENCODING_IDENTITY, // 'prefix' => 'your-prefix', ], ], @@ -405,7 +334,7 @@ $ composer require league/flysystem-ziparchive or add ``` -"league/flysystem-ziparchive": "~1.0" +"league/flysystem-ziparchive": "^3.0" ``` to the `require` section of your `composer.json` file and configure application `components` as follows @@ -416,7 +345,7 @@ return [ 'components' => [ //... 'ziparchiveFs' => [ - 'class' => 'creocoder\flysystem\ZipArchiveFilesystem', + 'class' => \creocoder\flysystem\ZipArchiveFilesystem::class, 'path' => '@webroot/files/archive.zip', // 'prefix' => 'your-prefix', ], @@ -424,71 +353,13 @@ return [ ]; ``` -### Caching feature - -Either run - -```bash -$ composer require league/flysystem-cached-adapter -``` - -or add - -``` -"league/flysystem-cached-adapter": "~1.0" -``` - -to the `require` section of your `composer.json` file and configure `fsID` application component as follows - -```php -return [ - //... - 'components' => [ - //... - 'fsID' => [ - //... - 'cache' => 'cacheID', - // 'cacheKey' => 'flysystem', - // 'cacheDuration' => 3600, - ], - ], -]; -``` - -### Replication feature - -Either run - -```bash -$ composer require league/flysystem-replicate-adapter -``` - -or add - -``` -"league/flysystem-replicate-adapter": "~1.0" -``` - -to the `require` section of your `composer.json` file and configure `fsID` application component as follows - -```php -return [ - //... - 'components' => [ - //... - 'fsID' => [ - //... - 'replica' => 'anotherFsID', - ], - ], -]; -``` - ### Global visibility settings Configure `fsID` application component as follows ```php +use League\Flysystem\Visibility; + return [ //... 'components' => [ @@ -496,7 +367,7 @@ return [ 'fsID' => [ //... 'config' => [ - 'visibility' => \League\Flysystem\AdapterInterface::VISIBILITY_PRIVATE, + 'visibility' => Visibility::PRIVATE, ], ], ], @@ -507,52 +378,22 @@ return [ ### Writing files -To write file +To write a file ```php Yii::$app->fs->write('filename.ext', 'contents'); ``` -To write file using stream contents +To write a file using stream contents ```php $stream = fopen('/path/to/somefile.ext', 'r+'); Yii::$app->fs->writeStream('filename.ext', $stream); ``` -### Updating files - -To update file - -```php -Yii::$app->fs->update('filename.ext', 'contents'); -``` - -To update file using stream contents - -```php -$stream = fopen('/path/to/somefile.ext', 'r+'); -Yii::$app->fs->updateStream('filename.ext', $stream); -``` - -### Writing or updating files - -To write or update file - -```php -Yii::$app->fs->put('filename.ext', 'contents'); -``` - -To write or update file using stream contents - -```php -$stream = fopen('/path/to/somefile.ext', 'r+'); -Yii::$app->fs->putStream('filename.ext', $stream); -``` - ### Reading files -To read file +To read a file ```php $contents = Yii::$app->fs->read('filename.ext'); @@ -571,77 +412,83 @@ fclose($stream); To check if a file exists ```php -$exists = Yii::$app->fs->has('filename.ext'); +$exists = Yii::$app->fs->fileExists('filename.ext'); +``` + +To check if a directory exists + +```php +$exists = Yii::$app->fs->directoryExists('path/to/directory'); ``` ### Deleting files -To delete file +To delete a file ```php Yii::$app->fs->delete('filename.ext'); ``` -### Reading and deleting files +### Moving files -To read and delete file +To move a file ```php -$contents = Yii::$app->fs->readAndDelete('filename.ext'); +Yii::$app->fs->move('filename.ext', 'newname.ext'); ``` -### Renaming files +### Copying files -To rename file +To copy a file ```php -Yii::$app->fs->rename('filename.ext', 'newname.ext'); +Yii::$app->fs->copy('filename.ext', 'copy.ext'); ``` ### Getting files mimetype -To get file mimetype +To get a file mimetype ```php -$mimetype = Yii::$app->fs->getMimetype('filename.ext'); +$mimetype = Yii::$app->fs->mimeType('filename.ext'); ``` -### Getting files timestamp +### Getting files last modified timestamp -To get file timestamp +To get a file last modified timestamp ```php -$timestamp = Yii::$app->fs->getTimestamp('filename.ext'); +$timestamp = Yii::$app->fs->lastModified('filename.ext'); ``` ### Getting files size -To get file size +To get a file size ```php -$timestamp = Yii::$app->fs->getSize('filename.ext'); +$size = Yii::$app->fs->fileSize('filename.ext'); ``` ### Creating directories -To create directory +To create a directory ```php -Yii::$app->fs->createDir('path/to/directory'); +Yii::$app->fs->createDirectory('path/to/directory'); ``` Directories are also made implicitly when writing to a deeper path ```php -Yii::$app->fs->write('path/to/filename.ext'); +Yii::$app->fs->write('path/to/filename.ext', 'contents'); ``` ### Deleting directories -To delete directory +To delete a directory ```php -Yii::$app->fs->deleteDir('path/to/filename.ext'); +Yii::$app->fs->deleteDirectory('path/to/directory'); ``` ### Managing visibility @@ -649,20 +496,20 @@ Yii::$app->fs->deleteDir('path/to/filename.ext'); Visibility is the abstraction of file permissions across multiple platforms. Visibility can be either public or private. ```php -use League\Flysystem\AdapterInterface; +use League\Flysystem\Visibility; Yii::$app->fs->write('filename.ext', 'contents', [ - 'visibility' => AdapterInterface::VISIBILITY_PRIVATE + 'visibility' => Visibility::PRIVATE ]); ``` You can also change and check visibility of existing files ```php -use League\Flysystem\AdapterInterface; +use League\Flysystem\Visibility; -if (Yii::$app->fs->getVisibility('filename.ext') === AdapterInterface::VISIBILITY_PRIVATE) { - Yii::$app->fs->setVisibility('filename.ext', AdapterInterface::VISIBILITY_PUBLIC); +if (Yii::$app->fs->visibility('filename.ext') === Visibility::PRIVATE) { + Yii::$app->fs->setVisibility('filename.ext', Visibility::PUBLIC); } ``` @@ -671,12 +518,11 @@ if (Yii::$app->fs->getVisibility('filename.ext') === AdapterInterface::VISIBILIT To list contents ```php -$contents = Yii::$app->fs->listContents(); +$contents = Yii::$app->fs->listContents('', false); -foreach ($contents as $object) { - echo $object['basename'] - . ' is located at' . $object['path'] - . ' and is a ' . $object['type']; +foreach ($contents as $item) { + echo $item->path(); + echo $item->isFile() ? 'file' : 'directory'; } ``` @@ -686,42 +532,41 @@ By default Flysystem lists the top directory non-recursively. You can supply a d $contents = Yii::$app->fs->listContents('path/to/directory', true); ``` -### Listing paths +## Upgrading from v1 -To list paths +If you are upgrading from the Flysystem v1 version of this extension, please note the following breaking changes: -```php -$paths = Yii::$app->fs->listPaths(); +### Removed Features +- **Caching**: The cached adapter is no longer available in Flysystem v3 +- **Replication**: The replicate adapter is no longer available in Flysystem v3 +- **Rackspace**: The Rackspace adapter has been removed as the service is discontinued +- **NullFilesystem**: Replaced with `InMemoryFilesystem` -foreach ($paths as $path) { - echo $path; -} -``` - -### Listing with ensured presence of specific metadata - -To list with ensured presence of specific metadata +### API Changes +| v1 Method | v3 Method | +|-----------|-----------| +| `has($path)` | `fileExists($path)` / `directoryExists($path)` | +| `createDir($path)` | `createDirectory($path)` | +| `deleteDir($path)` | `deleteDirectory($path)` | +| `rename($path, $newpath)` | `move($source, $destination)` | +| `getTimestamp($path)` | `lastModified($path)` | +| `getMimetype($path)` | `mimeType($path)` | +| `getSize($path)` | `fileSize($path)` | +| `getVisibility($path)` | `visibility($path)` | +| `update()` / `put()` | `write()` | +| `updateStream()` / `putStream()` | `writeStream()` | +### Visibility Constants ```php -$listing = Yii::$app->fs->listWith( - ['mimetype', 'size', 'timestamp'], - 'optional/path/to/directory', - true -); - -foreach ($listing as $object) { - echo $object['path'] . ' has mimetype: ' . $object['mimetype']; -} -``` - -### Getting file info with explicit metadata - -To get file info with explicit metadata +// Old (v1) +use League\Flysystem\AdapterInterface; +AdapterInterface::VISIBILITY_PRIVATE; +AdapterInterface::VISIBILITY_PUBLIC; -```php -$info = Yii::$app->fs->getWithMetadata('path/to/filename.ext', ['timestamp', 'mimetype']); -echo $info['mimetype']; -echo $info['timestamp']; +// New (v3) +use League\Flysystem\Visibility; +Visibility::PRIVATE; +Visibility::PUBLIC; ``` ## Donating diff --git a/composer.json b/composer.json index dd6c4fd..7d4d4bc 100644 --- a/composer.json +++ b/composer.json @@ -9,11 +9,9 @@ "aws", "s3", "azure", - "copy.com", "dropbox", "ftp", "gridfs", - "rackspace", "sftp", "webdav" ], @@ -26,23 +24,20 @@ } ], "require": { - "yiisoft/yii2": "~2.0.0", - "league/flysystem": "~1.0" + "php": "^8.1", + "yiisoft/yii2": "^2.0", + "league/flysystem": "^3.0" }, - "require-dev": { - "league/flysystem-aws-s3-v3": "~1.0", - "league/flysystem-azure": "~1.0", - "league/flysystem-cached-adapter": "~1.0", - "spatie/flysystem-dropbox": "~1.0", - "league/flysystem-gridfs": "~1.0", - "league/flysystem-rackspace": "~1.0", - "league/flysystem-replicate-adapter": "~1.0", - "league/flysystem-sftp": "~1.0", - "league/flysystem-webdav": "~1.0", - "league/flysystem-ziparchive": "~1.0" - }, - "conflict": { - "league/flysystem-aws-s3-v3": "<1.0.26" + "suggests": { + "league/flysystem-aws-s3-v3": "^1.0", + "league/flysystem-azure-blob-storage": "^3.0", + "spatie/flysystem-dropbox": "^3.0", + "league/flysystem-gridfs": "^3.0", + "league/flysystem-sftp-v3": "^3.0", + "league/flysystem-webdav": "^3.0", + "league/flysystem-ziparchive": "^3.0", + "league/flysystem-google-cloud-storage": "^3.0", + "league/flysystem-ftp": "^3.0" }, "repositories": [ { diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..8bb7165 --- /dev/null +++ b/composer.lock @@ -0,0 +1,606 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "69d03b93cc6526668bea5a924ab2ae2a", + "packages": [ + { + "name": "bower-asset/inputmask", + "version": "5.0.9", + "source": { + "type": "git", + "url": "https://github.com/RobinHerbots/Inputmask.git", + "reference": "310a33557e2944daf86d5946a5e8c82b9118f8f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/310a33557e2944daf86d5946a5e8c82b9118f8f7", + "reference": "310a33557e2944daf86d5946a5e8c82b9118f8f7" + }, + "require": { + "bower-asset/jquery": ">=1.7" + }, + "type": "bower-asset", + "license": [ + "http://opensource.org/licenses/mit-license.php" + ] + }, + { + "name": "bower-asset/jquery", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/jquery/jquery-dist.git", + "reference": "fde1f76e2799dd877c176abde0ec836553246991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/fde1f76e2799dd877c176abde0ec836553246991", + "reference": "fde1f76e2799dd877c176abde0ec836553246991" + }, + "type": "bower-asset", + "license": [ + "MIT" + ] + }, + { + "name": "bower-asset/punycode", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/mathiasbynens/punycode.js.git", + "reference": "0fbadd6e81f3a0ce06c38998040d6db6bdfbc5c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mathiasbynens/punycode.js/zipball/0fbadd6e81f3a0ce06c38998040d6db6bdfbc5c9", + "reference": "0fbadd6e81f3a0ce06c38998040d6db6bdfbc5c9" + }, + "type": "bower-asset" + }, + { + "name": "bower-asset/yii2-pjax", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/jquery-pjax.git", + "reference": "a9298d57da63d14a950f1b94366a864bc62264fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/a9298d57da63d14a950f1b94366a864bc62264fb", + "reference": "a9298d57da63d14a950f1b94366a864bc62264fb" + }, + "require": { + "bower-asset/jquery": ">=1.8" + }, + "type": "bower-asset", + "license": [ + "MIT" + ] + }, + { + "name": "cebe/markdown", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/cebe/markdown.git", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "shasum": "" + }, + "require": { + "lib-pcre": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "cebe/indent": "*", + "facebook/xhprof": "*@dev", + "phpunit/phpunit": "4.1.*" + }, + "bin": [ + "bin/markdown" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "description": "A super fast, highly extensible markdown parser for PHP", + "homepage": "https://github.com/cebe/markdown#readme", + "keywords": [ + "extensible", + "fast", + "gfm", + "markdown", + "markdown-extra" + ], + "support": { + "issues": "https://github.com/cebe/markdown/issues", + "source": "https://github.com/cebe/markdown" + }, + "time": "2018-03-26T11:24:36+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.19.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0" + }, + "time": "2025-10-17T16:34:55+00:00" + }, + { + "name": "league/flysystem", + "version": "3.30.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277", + "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3|^2", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2|^2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.30.2" + }, + "time": "2025-11-10T17:13:11+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.30.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ab4f9d0d672f601b102936aa728801dd1a11968d", + "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.2" + }, + "time": "2025-11-10T11:23:37+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "yiisoft/yii2", + "version": "2.0.53", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-framework.git", + "reference": "6c622fb8243181d7912b62ad80821cc0e1c745db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/6c622fb8243181d7912b62ad80821cc0e1c745db", + "reference": "6c622fb8243181d7912b62ad80821cc0e1c745db", + "shasum": "" + }, + "require": { + "bower-asset/inputmask": "^5.0.8 ", + "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", + "bower-asset/punycode": "^1.4", + "bower-asset/yii2-pjax": "~2.0.1", + "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0", + "ext-ctype": "*", + "ext-mbstring": "*", + "ezyang/htmlpurifier": "^4.17", + "lib-pcre": "*", + "php": ">=7.3.0", + "yiisoft/yii2-composer": "~2.0.4" + }, + "bin": [ + "yii" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "yii\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com", + "homepage": "https://www.yiiframework.com/", + "role": "Founder and project lead" + }, + { + "name": "Alexander Makarov", + "email": "sam@rmcreative.ru", + "homepage": "https://rmcreative.ru/", + "role": "Core framework development" + }, + { + "name": "Maurizio Domba", + "homepage": "http://mdomba.info/", + "role": "Core framework development" + }, + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "https://www.cebe.cc/", + "role": "Core framework development" + }, + { + "name": "Timur Ruziev", + "email": "resurtm@gmail.com", + "homepage": "http://resurtm.com/", + "role": "Core framework development" + }, + { + "name": "Paul Klimov", + "email": "klimov.paul@gmail.com", + "role": "Core framework development" + }, + { + "name": "Dmitry Naumenko", + "email": "d.naumenko.a@gmail.com", + "role": "Core framework development" + }, + { + "name": "Boudewijn Vahrmeijer", + "email": "info@dynasource.eu", + "homepage": "http://dynasource.eu", + "role": "Core framework development" + } + ], + "description": "Yii PHP Framework Version 2", + "homepage": "https://www.yiiframework.com/", + "keywords": [ + "framework", + "yii2" + ], + "support": { + "forum": "https://forum.yiiframework.com/", + "irc": "ircs://irc.libera.chat:6697/yii", + "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "source": "https://github.com/yiisoft/yii2", + "wiki": "https://www.yiiframework.com/wiki" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2", + "type": "tidelift" + } + ], + "time": "2025-06-27T07:42:53+00:00" + }, + { + "name": "yiisoft/yii2-composer", + "version": "2.0.11", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-composer.git", + "reference": "b684b01ecb119c8287721def726a0e24fec2fef2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/b684b01ecb119c8287721def726a0e24fec2fef2", + "reference": "b684b01ecb119c8287721def726a0e24fec2fef2", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 | ^2.0" + }, + "require-dev": { + "composer/composer": "^1.0 | ^2.0@dev", + "phpunit/phpunit": "<7" + }, + "type": "composer-plugin", + "extra": { + "class": "yii\\composer\\Plugin", + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "yii\\composer\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + }, + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc" + } + ], + "description": "The composer plugin for Yii extension installer", + "keywords": [ + "composer", + "extension installer", + "yii2" + ], + "support": { + "forum": "https://www.yiiframework.com/forum/", + "irc": "ircs://irc.libera.chat:6697/yii", + "issues": "https://github.com/yiisoft/yii2-composer/issues", + "source": "https://github.com/yiisoft/yii2-composer", + "wiki": "https://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-composer", + "type": "tidelift" + } + ], + "time": "2025-02-13T20:59:36+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^8.1" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/src/AwsS3Filesystem.php b/src/AwsS3Filesystem.php index eeb87f7..964eeb5 100644 --- a/src/AwsS3Filesystem.php +++ b/src/AwsS3Filesystem.php @@ -1,4 +1,5 @@ credentials; } - if ($this->pathStyleEndpoint === true) { $config['use_path_style_endpoint'] = true; } @@ -111,18 +114,21 @@ protected function prepareAdapter() $config['region'] = $this->region; } - if ($this->baseUrl !== null) { - $config['base_url'] = $this->baseUrl; - } - if ($this->endpoint !== null) { $config['endpoint'] = $this->endpoint; } - $config['version'] = (($this->version !== null) ? $this->version : 'latest'); + $config['version'] = $this->version ?? 'latest'; $client = new S3Client($config); - return new AwsS3Adapter($client, $this->bucket, $this->prefix, $this->options, $this->streamReads); + $visibility = new PortableVisibilityConverter($this->defaultVisibility); + + return new AwsS3V3Adapter( + $client, + $this->bucket, + $this->prefix, + $visibility + ); } } diff --git a/src/AzureFilesystem.php b/src/AzureFilesystem.php index 2143477..fe13f5e 100644 --- a/src/AzureFilesystem.php +++ b/src/AzureFilesystem.php @@ -7,8 +7,8 @@ namespace creocoder\flysystem; -use League\Flysystem\Azure\AzureAdapter; -use WindowsAzure\Common\ServicesBuilder; +use League\Flysystem\AzureBlobStorage\AzureBlobStorageAdapter; +use MicrosoftAzure\Storage\Blob\BlobRestProxy; use yii\base\InvalidConfigException; /** @@ -22,15 +22,27 @@ class AzureFilesystem extends Filesystem * @var string */ public $accountName; + /** * @var string */ public $accountKey; + /** * @var string */ public $container; + /** + * @var string + */ + public $prefix = ''; + + /** + * @var string|null Custom endpoint (e.g., for Azurite or sovereign clouds) + */ + public $endpoint; + /** * @inheritdoc */ @@ -52,17 +64,26 @@ public function init() } /** - * @return AzureAdapter + * @return AzureBlobStorageAdapter */ protected function prepareAdapter() { - return new AzureAdapter( - ServicesBuilder::getInstance()->createBlobService(sprintf( - 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s', - base64_encode($this->accountName), - base64_encode($this->accountKey) - )), - $this->container + $connectionString = sprintf( + 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s', + $this->accountName, + $this->accountKey + ); + + if ($this->endpoint !== null) { + $connectionString .= sprintf(';BlobEndpoint=%s', $this->endpoint); + } + + $client = BlobRestProxy::createBlobService($connectionString); + + return new AzureBlobStorageAdapter( + $client, + $this->container, + $this->prefix ); } } diff --git a/src/DropboxFilesystem.php b/src/DropboxFilesystem.php index 66adec9..69574bb 100644 --- a/src/DropboxFilesystem.php +++ b/src/DropboxFilesystem.php @@ -20,12 +20,12 @@ class DropboxFilesystem extends Filesystem { /** - * @var string|array|TokenProvider + * @var string|array|TokenProvider Access token or token provider */ public $token; /** - * @var string|null + * @var string Path prefix within Dropbox */ public $prefix = ''; @@ -46,9 +46,8 @@ public function init() */ protected function prepareAdapter() { - return new DropboxAdapter( - new Client($this->token), - $this->prefix - ); + $client = new Client($this->token); + + return new DropboxAdapter($client, $this->prefix); } } diff --git a/src/Filesystem.php b/src/Filesystem.php index ffa82c1..fea8301 100644 --- a/src/Filesystem.php +++ b/src/Filesystem.php @@ -7,77 +7,44 @@ namespace creocoder\flysystem; -use League\Flysystem\AdapterInterface; -use League\Flysystem\Cached\CachedAdapter; +use League\Flysystem\FilesystemAdapter; use League\Flysystem\Filesystem as NativeFilesystem; -use League\Flysystem\Replicate\ReplicateAdapter; -use Yii; +use League\Flysystem\FilesystemOperator; use yii\base\Component; -use yii\base\InvalidConfigException; -use yii\caching\Cache; /** * Filesystem * - * @method \League\Flysystem\FilesystemInterface addPlugin(\League\Flysystem\PluginInterface $plugin) - * @method void assertAbsent(string $path) - * @method void assertPresent(string $path) - * @method boolean copy(string $path, string $newpath) - * @method boolean createDir(string $dirname, array $config = null) - * @method boolean delete(string $path) - * @method boolean deleteDir(string $dirname) - * @method \League\Flysystem\Handler get(string $path, \League\Flysystem\Handler $handler = null) - * @method \League\Flysystem\AdapterInterface getAdapter() - * @method \League\Flysystem\Config getConfig() - * @method array|false getMetadata(string $path) - * @method string|false getMimetype(string $path) - * @method integer|false getSize(string $path) - * @method integer|false getTimestamp(string $path) - * @method string|false getVisibility(string $path) - * @method array getWithMetadata(string $path, array $metadata) - * @method boolean has(string $path) - * @method array listContents(string $directory = '', boolean $recursive = false) - * @method array listFiles(string $path = '', boolean $recursive = false) - * @method array listPaths(string $path = '', boolean $recursive = false) - * @method array listWith(array $keys = [], $directory = '', $recursive = false) - * @method boolean put(string $path, string $contents, array $config = []) - * @method boolean putStream(string $path, resource $resource, array $config = []) - * @method string|false read(string $path) - * @method string|false readAndDelete(string $path) - * @method resource|false readStream(string $path) - * @method boolean rename(string $path, string $newpath) - * @method boolean setVisibility(string $path, string $visibility) - * @method boolean update(string $path, string $contents, array $config = []) - * @method boolean updateStream(string $path, resource $resource, array $config = []) - * @method boolean write(string $path, string $contents, array $config = []) - * @method boolean writeStream(string $path, resource $resource, array $config = []) + * @method void write(string $path, string $contents, array $config = []) + * @method void writeStream(string $path, $contents, array $config = []) + * @method string read(string $path) + * @method resource readStream(string $path) + * @method void delete(string $path) + * @method void deleteDirectory(string $path) + * @method void createDirectory(string $path, array $config = []) + * @method void move(string $source, string $destination, array $config = []) + * @method void copy(string $source, string $destination, array $config = []) + * @method bool fileExists(string $path) + * @method bool directoryExists(string $path) + * @method bool has(string $path) + * @method int lastModified(string $path) + * @method string mimeType(string $path) + * @method int fileSize(string $path) + * @method string visibility(string $path) + * @method void setVisibility(string $path, string $visibility) + * @method \League\Flysystem\DirectoryListing listContents(string $path = '', bool $deep = false) * * @author Alexander Kochetov */ abstract class Filesystem extends Component { /** - * @var \League\Flysystem\Config|array|string|null + * @var array */ - public $config; - /** - * @var string|null - */ - public $cache; - /** - * @var string - */ - public $cacheKey = 'flysystem'; - /** - * @var integer - */ - public $cacheDuration = 3600; - /** - * @var string|null - */ - public $replica; + public $config = []; + /** - * @var \League\Flysystem\FilesystemInterface + * @var FilesystemOperator */ protected $filesystem; @@ -87,34 +54,11 @@ abstract class Filesystem extends Component public function init() { $adapter = $this->prepareAdapter(); - - if ($this->cache !== null) { - /* @var Cache $cache */ - $cache = Yii::$app->get($this->cache); - - if (!$cache instanceof Cache) { - throw new InvalidConfigException('The "cache" property must be an instance of \yii\caching\Cache subclasses.'); - } - - $adapter = new CachedAdapter($adapter, new YiiCache($cache, $this->cacheKey, $this->cacheDuration)); - } - - if ($this->replica !== null) { - /* @var Filesystem $filesystem */ - $filesystem = Yii::$app->get($this->replica); - - if (!$filesystem instanceof Filesystem) { - throw new InvalidConfigException('The "replica" property must be an instance of \creocoder\flysystem\Filesystem subclasses.'); - } - - $adapter = new ReplicateAdapter($adapter, $filesystem->getAdapter()); - } - $this->filesystem = new NativeFilesystem($adapter, $this->config); } /** - * @return AdapterInterface + * @return FilesystemAdapter */ abstract protected function prepareAdapter(); @@ -129,11 +73,10 @@ public function __call($method, $parameters) } /** - * @return \League\Flysystem\FilesystemInterface + * @return FilesystemOperator */ public function getFilesystem() { return $this->filesystem; } - } diff --git a/src/FtpFilesystem.php b/src/FtpFilesystem.php index 524744f..dcf36b8 100644 --- a/src/FtpFilesystem.php +++ b/src/FtpFilesystem.php @@ -7,7 +7,10 @@ namespace creocoder\flysystem; -use League\Flysystem\Adapter\Ftp; +use League\Flysystem\Ftp\FtpAdapter; +use League\Flysystem\Ftp\FtpConnectionOptions; +use League\Flysystem\UnixVisibility\PortableVisibilityConverter; +use League\Flysystem\Visibility; use Yii; use yii\base\InvalidConfigException; @@ -22,50 +25,101 @@ class FtpFilesystem extends Filesystem * @var string */ public $host; + /** - * @var integer + * @var int */ - public $port; + public $port = 21; + /** * @var string */ - public $username; + public $username = 'anonymous'; + /** * @var string */ - public $password; + public $password = ''; + /** - * @var boolean + * @var bool */ - public $ssl; + public $ssl = false; + /** - * @var integer + * @var int */ - public $timeout; + public $timeout = 90; + /** * @var string */ - public $root; + public $root = ''; + /** - * @var integer + * @var bool */ - public $permPrivate; + public $passive = true; + /** - * @var integer + * @var int */ - public $permPublic; + public $transferMode = FTP_BINARY; + /** - * @var boolean + * @var string|null */ - public $passive; + public $systemType; + + /** + * @var bool + */ + public $utf8 = false; + /** - * @var integer + * @var bool + */ + public $ignorePassiveAddress = true; + + /** + * @var bool */ - public $transferMode; + public $timestampsOnUnixListingsEnabled = false; + /** * @var bool */ - public $enableTimestampsOnUnixListings = false; + public $recurseManually = true; + + /** + * @var int File permission for private files + */ + public $filePrivate = 0640; + + /** + * @var int File permission for public files + */ + public $filePublic = 0644; + + /** + * @var int Directory permission for private directories + */ + public $directoryPrivate = 0740; + + /** + * @var int Directory permission for public directories + */ + public $directoryPublic = 0755; + + /** + * @var string Default visibility for files + */ + public $defaultForFiles = Visibility::PRIVATE; + + /** + * @var string Default visibility for directories + */ + public $defaultForDirectories = Visibility::PRIVATE; /** * @inheritdoc @@ -76,7 +130,7 @@ public function init() throw new InvalidConfigException('The "host" property must be set.'); } - if ($this->root !== null) { + if ($this->root !== null && $this->root !== '') { $this->root = Yii::getAlias($this->root); } @@ -84,31 +138,38 @@ public function init() } /** - * @return Ftp + * @return FtpAdapter */ protected function prepareAdapter() { - $config = []; - - foreach ([ - 'host', - 'port', - 'username', - 'password', - 'ssl', - 'timeout', - 'root', - 'permPrivate', - 'permPublic', - 'passive', - 'transferMode', - 'enableTimestampsOnUnixListings', - ] as $name) { - if ($this->$name !== null) { - $config[$name] = $this->$name; - } - } + $options = FtpConnectionOptions::fromArray([ + 'host' => $this->host, + 'port' => $this->port, + 'username' => $this->username, + 'password' => $this->password, + 'ssl' => $this->ssl, + 'timeout' => $this->timeout, + 'root' => $this->root, + 'passive' => $this->passive, + 'transferMode' => $this->transferMode, + 'systemType' => $this->systemType, + 'utf8' => $this->utf8, + 'ignorePassiveAddress' => $this->ignorePassiveAddress, + 'timestampsOnUnixListingsEnabled' => $this->timestampsOnUnixListingsEnabled, + 'recurseManually' => $this->recurseManually, + ]); + + $visibility = PortableVisibilityConverter::fromArray([ + 'file' => [ + 'public' => $this->filePublic, + 'private' => $this->filePrivate, + ], + 'dir' => [ + 'public' => $this->directoryPublic, + 'private' => $this->directoryPrivate, + ], + ], $this->defaultForFiles, $this->defaultForDirectories); - return new Ftp($config); + return new FtpAdapter($options, null, $visibility); } } diff --git a/src/GoogleCloudFilesystem.php b/src/GoogleCloudFilesystem.php index 4a0264a..1097feb 100644 --- a/src/GoogleCloudFilesystem.php +++ b/src/GoogleCloudFilesystem.php @@ -8,7 +8,9 @@ namespace creocoder\flysystem; use Google\Cloud\Storage\StorageClient; -use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter; +use League\Flysystem\GoogleCloudStorage\GoogleCloudStorageAdapter; +use League\Flysystem\Visibility; +use Yii; use yii\base\InvalidConfigException; /** @@ -22,15 +24,27 @@ class GoogleCloudFilesystem extends Filesystem * @var string */ public $projectId; + /** * @var string */ public $keyFilePath; + /** * @var string */ public $bucket; + /** + * @var string + */ + public $prefix = ''; + + /** + * @var string Default visibility for files + */ + public $defaultVisibility = Visibility::PRIVATE; + /** * @inheritdoc */ @@ -41,7 +55,7 @@ public function init() } if ($this->keyFilePath === null) { - throw new InvalidConfigException('The "secret" property must be set.'); + throw new InvalidConfigException('The "keyFilePath" property must be set.'); } if ($this->bucket === null) { @@ -52,17 +66,23 @@ public function init() } /** - * @return GoogleStorageAdapter + * @return GoogleCloudStorageAdapter */ protected function prepareAdapter() { $config = [ - 'projectId' => $this->projectId, - 'keyFilePath' => \Yii::getAlias($this->keyFilePath), + 'projectId' => $this->projectId, + 'keyFilePath' => Yii::getAlias($this->keyFilePath), ]; $client = new StorageClient($config); $bucket = $client->bucket($this->bucket); - return new GoogleStorageAdapter($client, $bucket); + + return new GoogleCloudStorageAdapter( + $bucket, + $this->prefix, + null, + $this->defaultVisibility + ); } } diff --git a/src/GridFSFilesystem.php b/src/GridFSFilesystem.php index 2d3f2c0..dcc0315 100644 --- a/src/GridFSFilesystem.php +++ b/src/GridFSFilesystem.php @@ -8,7 +8,7 @@ namespace creocoder\flysystem; use League\Flysystem\GridFS\GridFSAdapter; -use MongoClient; +use MongoDB\Client; use yii\base\InvalidConfigException; /** @@ -19,23 +19,35 @@ class GridFSFilesystem extends Filesystem { /** - * @var string + * @var string MongoDB connection URI */ - public $server; + public $uri = 'mongodb://localhost:27017'; + /** * @var string */ public $database; + /** + * @var string GridFS bucket name + */ + public $bucketName = 'fs'; + + /** + * @var array MongoDB connection options + */ + public $uriOptions = []; + + /** + * @var array MongoDB driver options + */ + public $driverOptions = []; + /** * @inheritdoc */ public function init() { - if ($this->server === null) { - throw new InvalidConfigException('The "server" property must be set.'); - } - if ($this->database === null) { throw new InvalidConfigException('The "database" property must be set.'); } @@ -48,6 +60,11 @@ public function init() */ protected function prepareAdapter() { - return new GridFSAdapter((new MongoClient($this->server))->selectDB($this->database)->getGridFS()); + $client = new Client($this->uri, $this->uriOptions, $this->driverOptions); + $bucket = $client->selectDatabase($this->database)->selectGridFSBucket([ + 'bucketName' => $this->bucketName, + ]); + + return new GridFSAdapter($bucket); } } diff --git a/src/InMemoryFilesystem.php b/src/InMemoryFilesystem.php new file mode 100644 index 0000000..dc460e1 --- /dev/null +++ b/src/InMemoryFilesystem.php @@ -0,0 +1,36 @@ + + */ +class InMemoryFilesystem extends Filesystem +{ + /** + * @var string Default visibility for files + */ + public $defaultVisibility = Visibility::PUBLIC; + + /** + * @return InMemoryFilesystemAdapter + */ + protected function prepareAdapter() + { + return new InMemoryFilesystemAdapter($this->defaultVisibility); + } +} + diff --git a/src/LocalFilesystem.php b/src/LocalFilesystem.php index 0ffb744..3a283b7 100644 --- a/src/LocalFilesystem.php +++ b/src/LocalFilesystem.php @@ -7,7 +7,9 @@ namespace creocoder\flysystem; -use League\Flysystem\Adapter\Local; +use League\Flysystem\Local\LocalFilesystemAdapter; +use League\Flysystem\UnixVisibility\PortableVisibilityConverter; +use League\Flysystem\Visibility; use Yii; use yii\base\InvalidConfigException; @@ -31,12 +33,37 @@ class LocalFilesystem extends Filesystem /** * @var int */ - public $linkHandling = Local::DISALLOW_LINKS; + public $linkHandling = LocalFilesystemAdapter::DISALLOW_LINKS; /** - * @var array + * @var string Default visibility for files */ - public $permissions = []; + public $defaultForFiles = Visibility::PRIVATE; + + /** + * @var string Default visibility for directories + */ + public $defaultForDirectories = Visibility::PRIVATE; + + /** + * @var int File permission for private files + */ + public $filePrivate = 0640; + + /** + * @var int File permission for public files + */ + public $filePublic = 0644; + + /** + * @var int Directory permission for private directories + */ + public $directoryPrivate = 0740; + + /** + * @var int Directory permission for public directories + */ + public $directoryPublic = 0755; /** * @inheritdoc @@ -47,25 +74,32 @@ public function init() throw new InvalidConfigException('The "path" property must be set.'); } - if (!in_array($this->writeFlags, [0, LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB], true)) { - throw new InvalidConfigException('The "writeFlags" property value is invalid.'); - } - - if ($this->linkHandling !== Local::DISALLOW_LINKS && $this->linkHandling !== Local::SKIP_LINKS) { - throw new InvalidConfigException('The "linkHandling" property value is invalid.'); - } - $this->path = Yii::getAlias($this->path); parent::init(); } /** - * @return Local + * @return LocalFilesystemAdapter */ protected function prepareAdapter() { - return new Local($this->path, $this->writeFlags, $this->linkHandling, $this->permissions); + $visibility = PortableVisibilityConverter::fromArray([ + 'file' => [ + 'public' => $this->filePublic, + 'private' => $this->filePrivate, + ], + 'dir' => [ + 'public' => $this->directoryPublic, + 'private' => $this->directoryPrivate, + ], + ], $this->defaultForFiles, $this->defaultForDirectories); + + return new LocalFilesystemAdapter( + $this->path, + $visibility, + $this->writeFlags, + $this->linkHandling + ); } } - diff --git a/src/NullFilesystem.php b/src/NullFilesystem.php deleted file mode 100644 index 31a6b6c..0000000 --- a/src/NullFilesystem.php +++ /dev/null @@ -1,26 +0,0 @@ - - */ -class NullFilesystem extends Filesystem -{ - /** - * @return NullAdapter - */ - protected function prepareAdapter() - { - return new NullAdapter(); - } -} diff --git a/src/RackspaceFilesystem.php b/src/RackspaceFilesystem.php deleted file mode 100644 index a229fd3..0000000 --- a/src/RackspaceFilesystem.php +++ /dev/null @@ -1,87 +0,0 @@ - - */ -class RackspaceFilesystem extends Filesystem -{ - /** - * @var string - */ - public $endpoint; - /** - * @var string - */ - public $username; - /** - * @var string - */ - public $apiKey; - /** - * @var string - */ - public $region; - /** - * @var string - */ - public $container; - /** - * @var string|null - */ - public $prefix; - - /** - * @inheritdoc - */ - public function init() - { - if ($this->endpoint === null) { - throw new InvalidConfigException('The "endpoint" property must be set.'); - } - - if ($this->username === null) { - throw new InvalidConfigException('The "username" property must be set.'); - } - - if ($this->apiKey === null) { - throw new InvalidConfigException('The "apiKey" property must be set.'); - } - - if ($this->region === null) { - throw new InvalidConfigException('The "region" property must be set.'); - } - - if ($this->container === null) { - throw new InvalidConfigException('The "container" property must be set.'); - } - - parent::init(); - } - - /** - * @return RackspaceAdapter - */ - protected function prepareAdapter() - { - return new RackspaceAdapter( - (new Rackspace($this->endpoint, [ - 'username' => $this->username, - 'apiKey' => $this->apiKey] - ))->objectStoreService('cloudFiles', $this->region)->getContainer($this->container), - $this->prefix - ); - } -} diff --git a/src/SftpFilesystem.php b/src/SftpFilesystem.php index 06cd37a..3813506 100644 --- a/src/SftpFilesystem.php +++ b/src/SftpFilesystem.php @@ -7,7 +7,10 @@ namespace creocoder\flysystem; -use League\Flysystem\Sftp\SftpAdapter; +use League\Flysystem\PhpseclibV3\SftpAdapter; +use League\Flysystem\PhpseclibV3\SftpConnectionProvider; +use League\Flysystem\UnixVisibility\PortableVisibilityConverter; +use League\Flysystem\Visibility; use Yii; use yii\base\InvalidConfigException; @@ -22,42 +25,76 @@ class SftpFilesystem extends Filesystem * @var string */ public $host; + /** - * @var string + * @var int */ - public $port; + public $port = 22; + /** * @var string */ public $username; + /** - * @var string + * @var string|null */ public $password; + /** - * @var integer + * @var int */ - public $timeout; + public $timeout = 10; + /** * @var string */ - public $root; + public $root = '/'; + /** - * @var string + * @var string|null */ public $privateKey; + /** - * @var integer + * @var string|null */ - public $permPrivate; + public $passphrase; + /** - * @var integer + * @var bool */ - public $permPublic; + public $useAgent = false; + + /** + * @var int File permission for private files + */ + public $filePrivate = 0640; + /** - * @var integer + * @var int File permission for public files */ - public $directoryPerm; + public $filePublic = 0644; + + /** + * @var int Directory permission for private directories + */ + public $directoryPrivate = 0740; + + /** + * @var int Directory permission for public directories + */ + public $directoryPublic = 0755; + + /** + * @var string Default visibility for files + */ + public $defaultForFiles = Visibility::PRIVATE; + + /** + * @var string Default visibility for directories + */ + public $defaultForDirectories = Visibility::PRIVATE; /** * @inheritdoc @@ -72,8 +109,8 @@ public function init() throw new InvalidConfigException('The "username" property must be set.'); } - if ($this->password === null && $this->privateKey === null) { - throw new InvalidConfigException('Either "password" or "privateKey" property must be set.'); + if ($this->password === null && $this->privateKey === null && $this->useAgent === false) { + throw new InvalidConfigException('Either "password", "privateKey", or "useAgent" property must be set.'); } if ($this->root !== null) { @@ -88,25 +125,32 @@ public function init() */ protected function prepareAdapter() { - $config = []; - - foreach ([ - 'host', - 'port', - 'username', - 'password', - 'timeout', - 'root', - 'privateKey', - 'permPrivate', - 'permPublic', - 'directoryPerm', - ] as $name) { - if ($this->$name !== null) { - $config[$name] = $this->$name; - } - } + $connectionProvider = new SftpConnectionProvider( + $this->host, + $this->username, + $this->password, + $this->privateKey, + $this->passphrase, + $this->port, + $this->useAgent, + $this->timeout + ); + + $visibility = PortableVisibilityConverter::fromArray([ + 'file' => [ + 'public' => $this->filePublic, + 'private' => $this->filePrivate, + ], + 'dir' => [ + 'public' => $this->directoryPublic, + 'private' => $this->directoryPrivate, + ], + ], $this->defaultForFiles, $this->defaultForDirectories); - return new SftpAdapter($config); + return new SftpAdapter( + $connectionProvider, + $this->root, + $visibility + ); } } diff --git a/src/WebDAVFilesystem.php b/src/WebDAVFilesystem.php index 8176f6e..2030fcc 100644 --- a/src/WebDAVFilesystem.php +++ b/src/WebDAVFilesystem.php @@ -22,30 +22,41 @@ class WebDAVFilesystem extends Filesystem * @var string */ public $baseUri; + /** - * @var string + * @var string|null */ public $userName; + /** - * @var string + * @var string|null */ public $password; + /** - * @var string + * @var string|null */ public $proxy; + /** - * @var integer + * @var int|null */ public $authType; + /** - * @var integer + * @var int|null */ public $encoding; + /** - * @var string|null + * @var string + */ + public $prefix = ''; + + /** + * @var bool Whether to use manually set directory prefix in paths */ - public $prefix; + public $useManuallySetPrefix = true; /** * @inheritdoc diff --git a/src/YiiCache.php b/src/YiiCache.php deleted file mode 100644 index 34be594..0000000 --- a/src/YiiCache.php +++ /dev/null @@ -1,64 +0,0 @@ - - */ -class YiiCache extends AbstractCache -{ - /** - * @var Cache - */ - protected $yiiCache; - /** - * @var string - */ - protected $key; - /** - * @var integer - */ - protected $duration; - - /** - * @param Cache $yiiCache - * @param string $key - * @param integer $duration - */ - public function __construct(Cache $yiiCache, $key = 'flysystem', $duration = 0) - { - $this->yiiCache = $yiiCache; - $this->key = $key; - $this->duration = $duration; - } - - /** - * @inheritdoc - */ - public function load() - { - $contents = $this->yiiCache->get($this->key); - - if ($contents !== false) { - $this->setFromStorage($contents); - } - } - - /** - * @inheritdoc - */ - public function save() - { - $this->yiiCache->set($this->key, $this->getForStorage(), $this->duration); - } -} diff --git a/src/ZipArchiveFilesystem.php b/src/ZipArchiveFilesystem.php index 7b89137..930d15a 100644 --- a/src/ZipArchiveFilesystem.php +++ b/src/ZipArchiveFilesystem.php @@ -7,6 +7,7 @@ namespace creocoder\flysystem; +use League\Flysystem\ZipArchive\FilesystemZipArchiveProvider; use League\Flysystem\ZipArchive\ZipArchiveAdapter; use Yii; use yii\base\InvalidConfigException; @@ -22,10 +23,11 @@ class ZipArchiveFilesystem extends Filesystem * @var string */ public $path; + /** - * @var string|null + * @var string */ - public $prefix; + public $prefix = ''; /** * @inheritdoc @@ -46,9 +48,10 @@ public function init() */ protected function prepareAdapter() { + $provider = new FilesystemZipArchiveProvider($this->path); + return new ZipArchiveAdapter( - $this->path, - null, + $provider, $this->prefix ); }