From d93c343ae2fb6c0f12d34ea046828edc7974490d Mon Sep 17 00:00:00 2001 From: Erik Niebla Date: Thu, 20 Jun 2024 13:59:28 -0500 Subject: [PATCH] nao-pon/flysystem-google-drive replacement --- .env.example | 7 + README.md | 12 +- app/Providers/GoogleDriveServiceProvider.php | 49 ++ bootstrap/providers.php | 1 + composer.json | 14 +- composer.lock | 574 ++++++++++++++++++- config/filesystems.php | 9 + routes/web.php | 251 ++++++++ 8 files changed, 906 insertions(+), 11 deletions(-) create mode 100644 app/Providers/GoogleDriveServiceProvider.php diff --git a/.env.example b/.env.example index f4b2e59..faf3aed 100644 --- a/.env.example +++ b/.env.example @@ -62,3 +62,10 @@ AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" + +#FILESYSTEM_DRIVER=google +GOOGLE_DRIVE_CLIENT_ID=xxx.apps.googleusercontent.com +GOOGLE_DRIVE_CLIENT_SECRET=xxx +GOOGLE_DRIVE_REFRESH_TOKEN=xxx +GOOGLE_DRIVE_FOLDER_ID= +#GOOGLE_DRIVE_TEAM_DRIVE_ID= diff --git a/README.md b/README.md index 7572079..6c64954 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ I have included [GoogleDriveServiceProvider](app/Providers/GoogleDriveServicePro 'clientId' => env('GOOGLE_DRIVE_CLIENT_ID'), 'clientSecret' => env('GOOGLE_DRIVE_CLIENT_SECRET'), 'refreshToken' => env('GOOGLE_DRIVE_REFRESH_TOKEN'), - 'folder' => env('GOOGLE_DRIVE_FOLDER'), + 'folderId' => env('GOOGLE_DRIVE_FOLDER_ID'), // 'teamDriveId' => env('GOOGLE_DRIVE_TEAM_DRIVE_ID'), ], @@ -60,7 +60,7 @@ FILESYSTEM_DRIVER=google GOOGLE_DRIVE_CLIENT_ID=xxx.apps.googleusercontent.com GOOGLE_DRIVE_CLIENT_SECRET=xxx GOOGLE_DRIVE_REFRESH_TOKEN=xxx -GOOGLE_DRIVE_FOLDER=folder_name +GOOGLE_DRIVE_FOLDER_ID=folder-id-xxx #GOOGLE_DRIVE_TEAM_DRIVE_ID=xxx ``` @@ -72,12 +72,12 @@ If you want to use multiple Google Drive accounts in a single Laravel app, you n MAIN_GOOGLE_DRIVE_CLIENT_ID=xxx.apps.googleusercontent.com MAIN_GOOGLE_DRIVE_CLIENT_SECRET=xxx MAIN_GOOGLE_DRIVE_REFRESH_TOKEN=xxx -MAIN_GOOGLE_DRIVE_FOLDER= +MAIN_GOOGLE_DRIVE_FOLDER_ID= BACKUP_GOOGLE_DRIVE_CLIENT_ID=xxx.apps.googleusercontent.com BACKUP_GOOGLE_DRIVE_CLIENT_SECRET=xxx BACKUP_GOOGLE_DRIVE_REFRESH_TOKEN=xxx -BACKUP_GOOGLE_DRIVE_FOLDER= +BACKUP_GOOGLE_DRIVE_FOLDER_ID= ``` Then you should add a disk in `config/filesystems.php` for each account using the `google` driver and the account specific keys: @@ -88,7 +88,7 @@ Then you should add a disk in `config/filesystems.php` for each account using th 'clientId' => env('MAIN_GOOGLE_DRIVE_CLIENT_ID'), 'clientSecret' => env('MAIN_GOOGLE_DRIVE_CLIENT_SECRET'), 'refreshToken' => env('MAIN_GOOGLE_DRIVE_REFRESH_TOKEN'), - 'folder' => env('MAIN_GOOGLE_DRIVE_FOLDER'), + 'folderId' => env('MAIN_GOOGLE_DRIVE_FOLDER_ID'), ], 'backup_google' => [ @@ -96,7 +96,7 @@ Then you should add a disk in `config/filesystems.php` for each account using th 'clientId' => env('BACKUP_GOOGLE_DRIVE_CLIENT_ID'), 'clientSecret' => env('BACKUP_GOOGLE_DRIVE_CLIENT_SECRET'), 'refreshToken' => env('BACKUP_GOOGLE_DRIVE_REFRESH_TOKEN'), - 'folder' => env('BACKUP_GOOGLE_DRIVE_FOLDER'), + 'folderId' => env('BACKUP_GOOGLE_DRIVE_FOLDER_ID'), ], ``` diff --git a/app/Providers/GoogleDriveServiceProvider.php b/app/Providers/GoogleDriveServiceProvider.php new file mode 100644 index 0000000..dd0b7bb --- /dev/null +++ b/app/Providers/GoogleDriveServiceProvider.php @@ -0,0 +1,49 @@ +setClientId($config['clientId']); + $client->setClientSecret($config['clientSecret']); + $client->refreshToken($config['refreshToken']); + $service = new \Google\Service\Drive($client); + + $options = [ + 'useDisplayPaths' => false, // as nao-pon/flysystem-google-drive replacement + ]; + if(isset($config['teamDriveId'])) { + $options['teamDriveId'] = $config['teamDriveId']; + } + + $adapter = new GoogleDriveAdapter($service, $config['folderId'] ?? null, $options); + $driver = new Filesystem($adapter); + return new FilesystemAdapter($driver, $adapter); + }); + } + + /** + * Register the application services. + * + * @return void + */ + public function register() + { + // + } +} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 38b258d..3fd0bb7 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -2,4 +2,5 @@ return [ App\Providers\AppServiceProvider::class, + App\Providers\GoogleDriveServiceProvider::class, ]; diff --git a/composer.json b/composer.json index 10d7526..a4c8c3f 100644 --- a/composer.json +++ b/composer.json @@ -6,14 +6,18 @@ "license": "MIT", "require": { "php": "^8.2", - "laravel/framework": "^11.9" + "laravel/framework": "^11.9", + "masbug/flysystem-google-drive-ext": "^2.0" }, "require-dev": { }, "extra": { "laravel": { "dont-discover": [] - } + }, + "google/apiclient-services": [ + "Drive" + ] }, "autoload": { "psr-4": { @@ -31,10 +35,12 @@ "@php artisan package:discover --ansi" ], "post-update-cmd": [ - "@php artisan vendor:publish --tag=laravel-assets --ansi --force" + "@php artisan vendor:publish --tag=laravel-assets --ansi --force", + "Google\\Task\\Composer::cleanup" ], "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"", + "Google\\Task\\Composer::cleanup" ], "post-create-project-cmd": [ "@php artisan key:generate --ansi", diff --git a/composer.lock b/composer.lock index 6467ff4..00e232c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a1fdb66e15f7386586dbeb8b85aadf06", + "content-hash": "07108bc5f7825b9de5923f5d3c47c896", "packages": [ { "name": "brick/math", @@ -506,6 +506,69 @@ ], "time": "2023-10-06T06:47:41+00:00" }, + { + "name": "firebase/php-jwt", + "version": "v6.10.1", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "500501c2ce893c824c801da135d02661199f60c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/500501c2ce893c824c801da135d02661199f60c5", + "reference": "500501c2ce893c824c801da135d02661199f60c5", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.10.1" + }, + "time": "2024-05-18T18:05:11+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.3.0", @@ -577,6 +640,179 @@ ], "time": "2023-10-12T05:21:21+00:00" }, + { + "name": "google/apiclient", + "version": "v2.16.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client.git", + "reference": "017400f609c1fb71ab5ad824c50eabd4c3eaf779" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/017400f609c1fb71ab5ad824c50eabd4c3eaf779", + "reference": "017400f609c1fb71ab5ad824c50eabd4c3eaf779", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~6.0", + "google/apiclient-services": "~0.350", + "google/auth": "^1.37", + "guzzlehttp/guzzle": "^6.5.8||^7.4.5", + "guzzlehttp/psr7": "^1.9.1||^2.2.1", + "monolog/monolog": "^2.9||^3.0", + "php": "^7.4|^8.0", + "phpseclib/phpseclib": "^3.0.36" + }, + "require-dev": { + "cache/filesystem-adapter": "^1.1", + "composer/composer": "^1.10.23", + "phpcompatibility/php-compatibility": "^9.2", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.8", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/aliases.php" + ], + "psr-4": { + "Google\\": "src/" + }, + "classmap": [ + "src/aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client/issues", + "source": "https://github.com/googleapis/google-api-php-client/tree/v2.16.0" + }, + "time": "2024-04-24T00:59:47+00:00" + }, + { + "name": "google/apiclient-services", + "version": "v0.360.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client-services.git", + "reference": "e48813050e660c7dcbe48cb6556461efe6381a54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/e48813050e660c7dcbe48cb6556461efe6381a54", + "reference": "e48813050e660c7dcbe48cb6556461efe6381a54", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "Google\\Service\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client-services/issues", + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.360.0" + }, + "time": "2024-06-17T01:06:20+00:00" + }, + { + "name": "google/auth", + "version": "v1.40.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-auth-library-php.git", + "reference": "bff9f2d01677e71a98394b5ac981b99523df5178" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/bff9f2d01677e71a98394b5ac981b99523df5178", + "reference": "bff9f2d01677e71a98394b5ac981b99523df5178", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.4.5", + "php": "^8.0", + "psr/cache": "^2.0||^3.0", + "psr/http-message": "^1.1||^2.0" + }, + "require-dev": { + "guzzlehttp/promises": "^2.0", + "kelvinmo/simplejwt": "0.7.1", + "phpseclib/phpseclib": "^3.0.35", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "sebastian/comparator": ">=1.2.3", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^6.0||^7.0", + "webmozart/assert": "^1.11" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "http://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "support": { + "docs": "https://googleapis.github.io/google-auth-library-php/main/", + "issues": "https://github.com/googleapis/google-auth-library-php/issues", + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.40.0" + }, + "time": "2024-05-31T19:16:15+00:00" + }, { "name": "graham-campbell/result-type", "version": "v1.1.2", @@ -1749,6 +1985,66 @@ ], "time": "2024-01-28T23:22:08+00:00" }, + { + "name": "masbug/flysystem-google-drive-ext", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/masbug/flysystem-google-drive-ext.git", + "reference": "549c3675f24e6495b6b29dd1bd1782a6a58d6876" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/masbug/flysystem-google-drive-ext/zipball/549c3675f24e6495b6b29dd1bd1782a6a58d6876", + "reference": "549c3675f24e6495b6b29dd1bd1782a6a58d6876", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "google/apiclient": "^2.2", + "guzzlehttp/guzzle": "^6.3 | ^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "league/flysystem": "^2.1.1|^3.0", + "php": "^7.2 | ^8.0" + }, + "require-dev": { + "league/flysystem-adapter-test-utilities": "^2.0|^3.0", + "phpunit/phpunit": "^8.0 | ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Masbug\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Naoki Sawada", + "email": "hypweb@gmail.com" + }, + { + "name": "Mitja Spes", + "email": "mitja@lxnav.com" + } + ], + "description": "Flysystem adapter for Google Drive with seamless virtual<=>display path translation", + "keywords": [ + "Flysystem", + "extended", + "google-drive", + "laravel", + "translated" + ], + "support": { + "issues": "https://github.com/masbug/flysystem-google-drive-ext/issues", + "source": "https://github.com/masbug/flysystem-google-drive-ext/tree/v2.3.0" + }, + "time": "2023-10-02T06:52:18+00:00" + }, { "name": "monolog/monolog", "version": "3.6.0", @@ -2192,6 +2488,123 @@ ], "time": "2024-03-06T16:17:14+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:36:18+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.2", @@ -2267,6 +2680,165 @@ ], "time": "2023-11-12T21:59:55+00:00" }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.38", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "b18b8788e51156c4dd97b7f220a31149a0052067" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/b18b8788e51156c4dd97b7f220a31149a0052067", + "reference": "b18b8788e51156c4dd97b7f220a31149a0052067", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.38" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-06-17T10:11:32+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "psr/clock", "version": "1.0.0", diff --git a/config/filesystems.php b/config/filesystems.php index c5f244d..229db63 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -56,6 +56,15 @@ 'throw' => false, ], + 'google' => [ + 'driver' => 'google', + 'clientId' => env('GOOGLE_DRIVE_CLIENT_ID'), + 'clientSecret' => env('GOOGLE_DRIVE_CLIENT_SECRET'), + 'refreshToken' => env('GOOGLE_DRIVE_REFRESH_TOKEN'), + 'folderId' => env('GOOGLE_DRIVE_FOLDER_ID'), + // 'teamDriveId' => env('GOOGLE_DRIVE_TEAM_DRIVE_ID'), + ], + ], /* diff --git a/routes/web.php b/routes/web.php index 86a06c5..00cd563 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,7 +1,258 @@ put('test.txt', 'Hello World'); + return 'File was saved to Google Drive'; +}); + +Route::get('put-existing', function() { + $filename = 'laravel.png'; + $filePath = public_path($filename); + $fileData = File::get($filePath); + + Storage::disk('google')->put($filename, $fileData); + return 'File was saved to Google Drive'; +}); + +Route::get('list-files', function() { + $recursive = false; // Get subdirectories also? + $contents = collect(Storage::disk('google')->listContents('/', $recursive)); + + //return $contents->where('type', 'dir'); // directories + return $contents->where('type', 'file')->mapWithKeys(fn (\League\Flysystem\StorageAttributes $file) => + [$file->path() => $file->extraMetadata()['name'] ?? $file->path()] + ); +}); + +Route::get('list-team-drives', function () { + $service = Storage::disk('google')->getAdapter()->getService(); + $teamDrives = collect($service->teamdrives->listTeamdrives()->getTeamDrives()); + + return $teamDrives->mapWithKeys(fn ($drive) => + [$drive->id => $drive->name] + ); +}); + +Route::get('get', function() { + $filename = 'test.txt'; + $file = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'file' && $file->extraMetadata()['name'] === $filename + ); // There could be duplicate directory names! + + $rawData = Storage::disk('google')->get($file->path()); // raw content + + return response($rawData, 200) + ->header('ContentType', $file->mimeType()) + ->header('Content-Disposition', "attachment; filename=$filename"); +}); + +Route::get('put-get-stream', function() { + // Use a stream to upload and download larger files + // to avoid exceeding PHP's memory limit. + + // Thanks to @Arman8852's comment: + // https://github.com/ivanvermeyen/laravel-google-drive-demo/issues/4#issuecomment-331625531 + // And this excellent explanation from Freek Van der Herten: + // https://murze.be/2015/07/upload-large-files-to-s3-using-laravel-5/ + + // Assume this is a large file... + $filename = 'laravel.png'; + $filePath = public_path($filename); + + // Upload using a stream... + Storage::disk('google')->put($filename, fopen($filePath, 'r+')); + + // Get file details... + $file = collect(Storage::disk('google')->listContents('/', 'false')) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'file' && $file->extraMetadata()['name'] === $filename + ); // There could be duplicate directory names! + + // Store the file locally... + //$readStream = Storage::disk('google')->getDriver()->readStream($filename); + //$targetFile = storage_path("downloaded-{$filename}"); + //file_put_contents($targetFile, stream_get_contents($readStream), FILE_APPEND); + + // Stream the file to the browser... + $readStream = Storage::disk('google')->getDriver()->readStream($file->path()); + + return response()->stream(function () use ($readStream) { + fpassthru($readStream); + }, 200, [ + 'Content-Type' => $file->mimeType(), + //'Content-disposition' => 'attachment; filename='.$filename, // force download? + ]); +}); + +Route::get('create-dir', function() { + Storage::disk('google')->makeDirectory('Test Dir'); + return 'Directory was created in Google Drive'; +}); + +Route::get('create-sub-dir', function() { + // Find parent dir for reference + $dir = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'dir' && $file->extraMetadata()['name'] === 'Test Dir' + ); // There could be duplicate directory names! + + if (! $dir) { + return 'Directory "Test Dir" does not exist!'; + } + + // Create sub dir + Storage::disk('google')->makeDirectory($dir->path().'/Sub Dir'); + + return 'Sub Directory was created in Google Drive'; +}); + +Route::get('put-in-dir', function() { + $dir = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'dir' && $file->extraMetadata()['name'] === 'Test Dir' + ); // There could be duplicate directory names! + + if (! $dir) { + return 'Directory "Test Dir" does not exist!'; + } + + Storage::disk('google')->put($dir->path().'/test.txt', 'Hello World'); + + return 'File was created in the sub directory in Google Drive'; +}); + +Route::get('list-folder-contents', function() { + // The human readable folder name to get the contents of... + // For simplicity, this folder is assumed to exist in the root directory. + $folder = 'Test Dir'; + $dir = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'dir' && $file->extraMetadata()['name'] === $folder + ); // There could be duplicate directory names! + + if (! $dir) { + return 'Directory "'.$folder.'" does not exist!'; + } + + // Get directory contents... + $contents = collect(Storage::disk('google')->listContents($dir->path(), false)); + + return $contents->mapWithKeys(fn (\League\Flysystem\StorageAttributes $content) => + [$content->path() => $folder.'/'.($content->extraMetadata()['name'] ?? $content->path())] + ); +}); + +Route::get('newest', function() { + $filename = 'test.txt'; + Storage::disk('google')->put($filename, \Carbon\Carbon::now()->toDateTimeString()); + + $file = collect(Storage::disk('google')->listContents('/', false)) + ->filter(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'file' && $file->extraMetadata()['name'] === $filename + ) + ->sortBy('lastModified') + ->last(); + + return Storage::disk('google')->get($file->path()); +}); + +Route::get('delete', function() { + $filename = 'test.txt'; + + $file = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'file' && $file->extraMetadata()['name'] === $filename + ); // there can be duplicate file names! + + if (! $file) { + return 'File ".$filename." does not exist!'; + } + + Storage::disk('google')->delete($file->path()); + + return 'File was deleted from Google Drive'; +}); + +Route::get('delete-dir', function() { + $directoryName = 'Test Dir'; + + $dir = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'dir' && $file->extraMetadata()['name'] === $directoryName + ); // there can be duplicate file names! + + if (! $dir) { + return 'Directory "'.$directoryName.'" does not exist!'; + } + + Storage::disk('google')->deleteDirectory($dir->path()); + + return 'Directory was deleted from Google Drive'; +}); + +Route::get('rename-dir', function() { + $directoryName = 'test'; + + // First we need to create a directory to rename + Storage::disk('google')->makeDirectory($directoryName); + + // Now find that directory and use its ID (path) to rename it + $dir = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'dir' && $file->extraMetadata()['name'] === $directoryName + ); // there can be duplicate file names! + + if (! $dir) { + return 'Directory "'.$directoryName.'" does not exist!'; + } + + Storage::disk('google')->move($dir->path(), 'new-test'); + + return 'Directory was renamed in Google Drive'; +}); + +Route::get('share', function() { + $filename = 'test.txt'; + + // Store a demo file + Storage::disk('google')->put($filename, 'Hello World'); + + // Get the file to find the ID + $file = collect(Storage::disk('google')->listContents('/', false)) + ->first(fn (\League\Flysystem\StorageAttributes $file) => + $file->type() === 'file' && $file->extraMetadata()['name'] === $filename + ); // there can be duplicate file names! + + // Change permissions + // - https://developers.google.com/drive/v3/web/about-permissions + // - https://developers.google.com/drive/v3/reference/permissions + $service = Storage::disk('google')->getAdapter()->getService(); + $permission = new \Google_Service_Drive_Permission(); + $permission->setRole('reader'); + $permission->setType('anyone'); + $permission->setAllowFileDiscovery(false); + $permissions = $service->permissions->create($file->path(), $permission); + + return Storage::disk('google')->url($file->path()); +}); + +Route::get('export/{filename}', function ($filename) { + $service = Storage::disk('google')->getAdapter()->getService(); + $file = Storage::disk('google')->getAdapter()->getMetadata($filename); + + $mimeType = 'application/pdf'; + $export = $service->files->export($file->path(), $mimeType); + + return response($export->getBody(), 200, [ + 'Content-Type' => $mimeType, + 'Content-disposition' => 'attachment; filename='.$filename.'.pdf', + ]); +});