├── examples ├── storage │ └── .gitignore ├── config.example.php └── test.php ├── .gitignore ├── src ├── PathManager.php ├── GoogleDriveServiceProvider.php ├── GoogleSheetsPathManager.php └── GoogleDriveAdapter.php ├── composer.json ├── LICENSE └── README.md /examples/storage/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /examples/config.example.php: -------------------------------------------------------------------------------- 1 | '', 4 | 'clientSecret' => '', 5 | 'refreshToken' => '', 6 | 'folderId' => '', 7 | 'sheetId' => '', 8 | ]; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor/ 3 | node_modules/ 4 | npm-debug.log 5 | 6 | # Laravel 4 specific 7 | bootstrap/compiled.php 8 | app/storage/ 9 | 10 | # Laravel 5 & Lumen specific 11 | public/storage 12 | public/hot 13 | storage/*.key 14 | .env.*.php 15 | .env.php 16 | .env 17 | Homestead.yaml 18 | Homestead.json 19 | 20 | # Rocketeer PHP task runner and deployment package. https://github.com/rocketeers/rocketeer 21 | .rocketeer/ 22 | 23 | examples/config.php 24 | composer.lock -------------------------------------------------------------------------------- /src/PathManager.php: -------------------------------------------------------------------------------- 1 | setClientId($config['clientId']); 23 | $client->setClientSecret($config['clientSecret']); 24 | $client->refreshToken($config['refreshToken']); 25 | 26 | 27 | // Example for saved file paths 28 | $sheetService = new \Google_Service_Sheets($client); 29 | $pathManager = new GoogleSheetsPathManager($sheetService, $sheetId, $localStorage); 30 | $pathManager->updateCacheFile(); 31 | 32 | // Use Google Drive adapter 33 | $gdService = new \Google_Service_Drive($client); 34 | $gdAdapter = new GoogleDriveAdapter($gdService, $config['folderId']); 35 | $gdAdapter->setPathManager($pathManager); 36 | 37 | 38 | $emptyConfig = new \League\Flysystem\Config(); 39 | 40 | $dir = 'test/222/333'; 41 | $fileName = $dir . '/new-file-1.txt'; 42 | 43 | echo 'Open for watch:' . PHP_EOL; 44 | echo $gdAdapter->getUrl($sheetId); 45 | echo PHP_EOL; 46 | echo 'Document must be publish for reading.' . PHP_EOL; 47 | echo PHP_EOL; 48 | 49 | echo '1. Create folder' . PHP_EOL; 50 | var_dump($gdAdapter->createDir($dir, $emptyConfig)); 51 | echo PHP_EOL; 52 | 53 | echo '2. Create file' . PHP_EOL; 54 | var_dump($gdAdapter->write($fileName, 'Hello world!', $emptyConfig)); 55 | echo PHP_EOL; 56 | 57 | echo '3. Delete file' . PHP_EOL; 58 | var_dump($gdAdapter->delete($fileName)); 59 | echo PHP_EOL; 60 | 61 | echo '4. Delete folder' . PHP_EOL; 62 | var_dump($gdAdapter->deleteDir($dir)); 63 | echo PHP_EOL; 64 | -------------------------------------------------------------------------------- /src/GoogleDriveServiceProvider.php: -------------------------------------------------------------------------------- 1 | extend(Google_Client::class, function ($client) 21 | { 22 | $config = config('filesystems.disks.googleDrive'); 23 | /** @var Google_Client $client */ 24 | $client->setClientId($config['clientId']); 25 | $client->setClientSecret($config['clientSecret']); 26 | $client->refreshToken($config['refreshToken']); 27 | 28 | return $client; 29 | }); 30 | 31 | app()->bind(GoogleSheetsPathManager::class, function () 32 | { 33 | $config = config('filesystems.disks.googleDrive'); 34 | /** @var Google_Client $client */ 35 | $client = app()->make(Google_Client::class); 36 | $sheetService = new \Google_Service_Sheets($client); 37 | $pathManager = new GoogleSheetsPathManager($sheetService, $config['sheetId'], Storage::disk('local')); 38 | $pathManager->updateCacheFile(); 39 | 40 | return $pathManager; 41 | }); 42 | 43 | if ( ! app()->bound(PathManager::class)) { 44 | app()->bind(PathManager::class, GoogleSheetsPathManager::class); 45 | } 46 | 47 | Storage::extend('googleDrive', function ($app, $config) 48 | { 49 | /** @var Google_Client $client */ 50 | $client = app()->make(Google_Client::class); 51 | /** @var PathManager $client */ 52 | $pathManager = app()->make(PathManager::class); 53 | 54 | $gdService = new \Google_Service_Drive($client); 55 | $gdAdapter = new GoogleDriveAdapter($gdService, $config['folderId']); 56 | $gdAdapter->setPathManager($pathManager); 57 | 58 | return new FilesystemAdapter( 59 | new \League\Flysystem\Filesystem($gdAdapter), 60 | $gdAdapter, 61 | $config 62 | ); 63 | }); 64 | } 65 | 66 | /** 67 | * Register the application services. 68 | * 69 | * @return void 70 | */ 71 | public function register() 72 | { 73 | // 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flysystem-google-drive 2 | FlySystem adapter for Google Drive (work with path) 3 | 4 | This project is wrapper of [nao-pon/flysystem-google-drive](https://github.com/nao-pon/flysystem-google-drive) 5 | 6 | Read more information [this](https://github.com/nao-pon/flysystem-google-drive) 7 | 8 | 9 | ## Installation 10 | 11 | ```bash 12 | composer require private-it/flysystem-google-drive:dev-master 13 | ``` 14 | 15 | ## Config 16 | 17 | * [Getting your Client ID and Secret](https://github.com/ivanvermeyen/laravel-google-drive-demo/blob/master/README/1-getting-your-dlient-id-and-secret.md) 18 | * [Getting your Refresh Token](https://github.com/ivanvermeyen/laravel-google-drive-demo/blob/master/README/2-getting-your-refresh-token.md) 19 | * [Getting your Root Folder ID](https://github.com/ivanvermeyen/laravel-google-drive-demo/blob/master/README/3-getting-your-root-folder-id.md) 20 | 21 | 22 | Config params: 23 | 24 | ```php 25 | [ 26 | 'clientId' => 'xxxxxxxxxxx.apps.googleusercontent.com', 27 | 'clientSecret' => 'xxxxxxxxxxx', 28 | 'refreshToken' => 'xxxxxxxxxxx', 29 | 'folderId' => 'xxxxxxxxxxx', 30 | 'sheetId' => 'xxxxxxxxxxx', 31 | ]; 32 | ``` 33 | 34 | **folderId** - uses as root folder for upload/read. 35 | 36 | **sheetId** - file id of "Google Sheets" document. Uses for save path-fileId. This document must be shared for public read. 37 | 38 | 39 | ## Usage example 40 | 41 | See `examples/test.php` 42 | 43 | ```bash 44 | git clone https://github.com/private-it/flysystem-google-drive.git 45 | composer install 46 | ``` 47 | 48 | Copy `examples/config.example.php` to `examples/config.php` 49 | 50 | ```bash 51 | php examples/test.php 52 | ``` 53 | 54 | ## Usage with Laravel 55 | 56 | 57 | Configuration google drive `config/filesystems.php` 58 | 59 | ```php 60 | 'disks' => [ 61 | ... 62 | 'googleDrive' => [ 63 | 'driver' => 'googleDrive', 64 | 'clientId' => env('GOOGLE_DRIVE_CLIENT_ID'), 65 | 'clientSecret' => env('GOOGLE_DRIVE_CLIENT_SECRET'), 66 | 'refreshToken' => env('GOOGLE_DRIVE_REFRESH_TOKEN'), 67 | 'folderId' => env('GOOGLE_DRIVE_FOLDER_ID'), 68 | 'sheetId' => env('GOOGLE_DRIVE_PATH_MANAGER_SHEET_ID'), 69 | ], 70 | ... 71 | ], 72 | ``` 73 | 74 | [Laravel v4] Add ServiceProvider to `config/app.php` 75 | 76 | ```php 77 | 'providers' => [ 78 | ... 79 | PrivateIT\FlySystem\GoogleDrive\GoogleDriveServiceProvider::class 80 | ... 81 | ] 82 | ``` 83 | 84 | *For custom `PathManager`* you can set binding in file `bootstrap/app.php` 85 | 86 | ```php 87 | $app->bind(\PrivateIT\FlySystem\GoogleDrive\PathManager::class, \PrivateIT\FlySystem\GoogleDrive\GoogleSheetsPathManager::class); 88 | ``` 89 | 90 | 91 | Usage: 92 | 93 | ```php 94 | $disk = \Storage::disk('googleDrive'); 95 | $adapter = $disk->getDriver()->getAdapter(); 96 | 97 | $dir = 'test/sub1/sub2'; 98 | $fileName = 'test/sub1/sub2/new-file-1.txt'; 99 | 100 | var_dump($disk->makeDirectory($dir)); 101 | var_dump($disk->put($fileName, 'test content')); 102 | var_dump($adapter->getUrl($fileName)); 103 | var_dump($disk->deleteDir($dir)); 104 | ``` 105 | -------------------------------------------------------------------------------- /src/GoogleSheetsPathManager.php: -------------------------------------------------------------------------------- 1 | service = $service; 44 | $this->spreadsheetId = $spreadsheetId; 45 | $this->storage = $storage; 46 | } 47 | 48 | public function readPath($path) 49 | { 50 | if (isset($this->cache[$path])) return $this->cache[$path]; 51 | 52 | $result = $this->findPath($path); 53 | if (isset($result[0]['fileId'])) { 54 | return $this->cache[$path] = $result[0]['fileId']; 55 | } 56 | return false; 57 | } 58 | 59 | public function findPath($path, $asDir = false) 60 | { 61 | $output = []; 62 | exec('grep -ni ",' . $path . ($asDir ? '' : ',') . '" ' . $this->storage->path($this->cacheFile), $output); 63 | if (!empty($output) && sizeof($output)) { 64 | $results = []; 65 | foreach ($output as $item) { 66 | list($index, $path, $fileId) = explode(',', $output[0]); 67 | $index = explode(':', $index); 68 | $index = array_shift($index); 69 | $results[] = compact('index', 'path', 'fileId'); 70 | } 71 | return $results; 72 | } 73 | return false; 74 | } 75 | 76 | public function writePath($path, $fileId) 77 | { 78 | $range = 'A1:C1'; 79 | $response = $this->service->spreadsheets_values->append( 80 | $this->spreadsheetId, 81 | $range, 82 | new \Google_Service_Sheets_ValueRange( 83 | [ 84 | "range" => $range, 85 | "majorDimension" => "ROWS", 86 | 'values' => [ 87 | ['#', $path, $fileId] 88 | ] 89 | ] 90 | ), 91 | [ 92 | "valueInputOption" => "USER_ENTERED", 93 | ] 94 | ); 95 | if (!isset($response->updates)) { 96 | return false; 97 | } 98 | if (!isset($response->updates->updatedRows)) { 99 | return false; 100 | } 101 | if ($response->updates->updatedRows != 1) { 102 | return false; 103 | } 104 | return $this->updateCacheFile(); 105 | } 106 | 107 | public function removePath($path) 108 | { 109 | $results = $this->findPath($path, true); 110 | if (!$results) return null; 111 | 112 | foreach ($results as $result) { 113 | $response = $this->service->spreadsheets->batchUpdate($this->spreadsheetId, 114 | new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest([ 115 | 'requests' => 116 | [[ 117 | 'deleteDimension' => [ 118 | 'range' => [ 119 | 'sheetId' => 0, 120 | 'dimension' => 'ROWS', 121 | 'startIndex' => $result['index'] - 1, 122 | 'endIndex' => $result['index'] 123 | ] 124 | ] 125 | ]] 126 | 127 | ]) 128 | ); 129 | if (!$response) { 130 | return false; 131 | } 132 | } 133 | return $this->updateCacheFile(); 134 | } 135 | 136 | public function updateCacheFile() 137 | { 138 | return $this->storage->put( 139 | $this->cacheFile, 140 | file_get_contents( 141 | 'https://docs.google.com/spreadsheets/u/0/d/' . $this->spreadsheetId . 142 | '/export?format=csv&id=' . $this->spreadsheetId . 143 | '&gid=0' 144 | ) 145 | ); 146 | } 147 | } 148 | 149 | -------------------------------------------------------------------------------- /src/GoogleDriveAdapter.php: -------------------------------------------------------------------------------- 1 | pathManager = $manager; 28 | } 29 | 30 | /** 31 | * @param $path 32 | * 33 | * @return string 34 | */ 35 | public function replacePath($path) 36 | { 37 | if ($this->pathManager->readPath($path)) { 38 | return $this->pathManager->readPath($path); 39 | } 40 | 41 | $paths = explode('/', $path); 42 | $fileName = array_pop($paths); 43 | 44 | if ($fileName) { 45 | $fileId = $this->pathManager->readPath($path); 46 | $path = $fileName; 47 | if ($fileId) { 48 | $path = $fileId; 49 | } 50 | } 51 | 52 | $dirPath = implode('/', $paths); 53 | if ($dirPath) { 54 | $dirId = $this->pathManager->readPath($dirPath); 55 | if ($dirId) { 56 | $dirId = explode('/', $dirId); 57 | $dirId = array_pop($dirId); 58 | $path = $dirId . '/' . $path; 59 | } 60 | else { 61 | $path = $dirPath . '/' . $path; 62 | } 63 | } 64 | 65 | return $path; 66 | } 67 | 68 | /** 69 | * @param $path 70 | * @param $results 71 | * 72 | * @return array|false 73 | */ 74 | public function processPath($path, $results) 75 | { 76 | if ($results && isset($results['path'])) { 77 | if ( ! $this->pathManager->readPath($path)) { 78 | $fileId = explode('/', $results['path']); 79 | $fileId = array_pop($fileId); 80 | if ($path != $fileId) { 81 | $this->pathManager->writePath($path, $fileId); 82 | } 83 | } 84 | } 85 | 86 | return $results; 87 | 88 | } 89 | 90 | /** 91 | * @inheritdoc 92 | */ 93 | public function upload($path, $contents, Config $config) 94 | { 95 | if ( ! $this->has(dirname($path))) { 96 | $this->createDir(dirname($path), $config); 97 | } 98 | 99 | return $this->processPath($path, parent::upload($this->replacePath($path), $contents, $config)); 100 | } 101 | 102 | /** 103 | * @inheritdoc 104 | */ 105 | public function delete($path) 106 | { 107 | if (parent::delete($this->replacePath($path))) { 108 | return $this->pathManager->removePath($path); 109 | } 110 | 111 | return false; 112 | } 113 | 114 | /** 115 | * @inheritdoc 116 | */ 117 | public function has($path) 118 | { 119 | return parent::has($this->replacePath($path)); 120 | } 121 | 122 | /** 123 | * @inheritdoc 124 | */ 125 | public function createDir($path, Config $config) 126 | { 127 | while (sizeof($target = explode('/', $this->replacePath($path))) > 2) { 128 | $this->createDir($target[0] . '/' . $target[1], $config); 129 | } 130 | 131 | return $this->processPath($path, parent::createDir($this->replacePath($path), $config)); 132 | } 133 | 134 | /** 135 | * @inheritdoc 136 | */ 137 | public function getUrl($path) 138 | { 139 | return parent::getUrl($this->replacePath($path)); 140 | } 141 | 142 | /** 143 | * @inheritdoc 144 | */ 145 | public function read($path) 146 | { 147 | return parent::read($this->replacePath($path)); 148 | } 149 | 150 | /** 151 | * @inheritdoc 152 | */ 153 | public function readStream($path) 154 | { 155 | return parent::readStream($this->replacePath($path)); 156 | } 157 | 158 | /** 159 | * @inheritdoc 160 | */ 161 | public function listContents($dirname = '', $recursive = false) 162 | { 163 | return parent::listContents($this->replacePath($dirname), $recursive); 164 | } 165 | 166 | /** 167 | * @inheritdoc 168 | */ 169 | public function getMetadata($path) 170 | { 171 | return parent::getMetadata($this->replacePath($path)); 172 | } 173 | 174 | /** 175 | * @inheritdoc 176 | */ 177 | public function setVisibility($path, $visibility) 178 | { 179 | return parent::setVisibility($this->replacePath($path), $visibility); 180 | } 181 | 182 | public function getVisibility($path) 183 | { 184 | return parent::getVisibility($this->replacePath($path)); 185 | } 186 | 187 | } --------------------------------------------------------------------------------