.tmp
2 years ago
editors
2 years ago
libs
2 years ago
plugins
2 years ago
resources
2 years ago
MySQLStorage.sql
2 years ago
autoload.php
2 years ago
elFinder.class.php
2 years ago
elFinderConnector.class.php
2 years ago
elFinderFlysystemGoogleDriveNetmount.php
2 years ago
elFinderPlugin.php
2 years ago
elFinderSession.php
2 years ago
elFinderSessionInterface.php
2 years ago
elFinderVolumeBox.class.php
2 years ago
elFinderVolumeDriver.class.php
2 years ago
elFinderVolumeDropbox.class.php
2 years ago
elFinderVolumeDropbox2.class.php
2 years ago
elFinderVolumeFTP.class.php
2 years ago
elFinderVolumeGoogleDrive.class.php
2 years ago
elFinderVolumeGroup.class.php
2 years ago
elFinderVolumeLocalFileSystem.class.php
2 years ago
elFinderVolumeMySQL.class.php
2 years ago
elFinderVolumeOneDrive.class.php
2 years ago
elFinderVolumeSFTPphpseclib.class.php
2 years ago
elFinderVolumeTrash.class.php
2 years ago
elFinderVolumeTrashMySQL.class.php
2 years ago
index.php
2 years ago
mime.types
2 years ago
elFinderFlysystemGoogleDriveNetmount.php
381 lines
| 1 | <?php |
| 2 | |
| 3 | use League\Flysystem\Filesystem; |
| 4 | use League\Flysystem\Adapter\Local; |
| 5 | use League\Flysystem\Cached\CachedAdapter; |
| 6 | use League\Flysystem\Cached\Storage\Adapter as ACache; |
| 7 | use Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter; |
| 8 | use Hypweb\Flysystem\Cached\Extra\Hasdir; |
| 9 | use Hypweb\Flysystem\Cached\Extra\DisableEnsureParentDirectories; |
| 10 | use Hypweb\elFinderFlysystemDriverExt\Driver as ExtDriver; |
| 11 | |
| 12 | elFinder::$netDrivers['googledrive'] = 'FlysystemGoogleDriveNetmount'; |
| 13 | |
| 14 | if (!class_exists('elFinderVolumeFlysystemGoogleDriveCache', false)) { |
| 15 | class elFinderVolumeFlysystemGoogleDriveCache extends ACache |
| 16 | { |
| 17 | use Hasdir; |
| 18 | use DisableEnsureParentDirectories; |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver |
| 23 | { |
| 24 | |
| 25 | public function __construct() |
| 26 | { |
| 27 | parent::__construct(); |
| 28 | |
| 29 | $opts = array( |
| 30 | 'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#', |
| 31 | 'rootCssClass' => 'elfinder-navbar-root-googledrive', |
| 32 | 'gdAlias' => '%s@GDrive', |
| 33 | 'gdCacheDir' => __DIR__ . '/.tmp', |
| 34 | 'gdCachePrefix' => 'gd-', |
| 35 | 'gdCacheExpire' => 600 |
| 36 | ); |
| 37 | |
| 38 | $this->options = array_merge($this->options, $opts); |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Prepare driver before mount volume. |
| 43 | * Return true if volume is ready. |
| 44 | * |
| 45 | * @return bool |
| 46 | **/ |
| 47 | protected function init() |
| 48 | { |
| 49 | if (empty($this->options['icon'])) { |
| 50 | $this->options['icon'] = true; |
| 51 | } |
| 52 | if ($res = parent::init()) { |
| 53 | if ($this->options['icon'] === true) { |
| 54 | unset($this->options['icon']); |
| 55 | } |
| 56 | // enable command archive |
| 57 | $this->options['useRemoteArchive'] = true; |
| 58 | } |
| 59 | return $res; |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * Prepare |
| 64 | * Call from elFinder::netmout() before volume->mount() |
| 65 | * |
| 66 | * @param $options |
| 67 | * |
| 68 | * @return Array |
| 69 | * @author Naoki Sawada |
| 70 | */ |
| 71 | public function netmountPrepare($options) |
| 72 | { |
| 73 | if (empty($options['client_id']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTID')) { |
| 74 | $options['client_id'] = ELFINDER_GOOGLEDRIVE_CLIENTID; |
| 75 | } |
| 76 | if (empty($options['client_secret']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTSECRET')) { |
| 77 | $options['client_secret'] = ELFINDER_GOOGLEDRIVE_CLIENTSECRET; |
| 78 | } |
| 79 | |
| 80 | if (!isset($options['pass'])) { |
| 81 | $options['pass'] = ''; |
| 82 | } |
| 83 | |
| 84 | try { |
| 85 | $client = new \Google_Client(); |
| 86 | $client->setClientId($options['client_id']); |
| 87 | $client->setClientSecret($options['client_secret']); |
| 88 | |
| 89 | if ($options['pass'] === 'reauth') { |
| 90 | $options['pass'] = ''; |
| 91 | $this->session->set('GoogleDriveAuthParams', [])->set('GoogleDriveTokens', []); |
| 92 | } else if ($options['pass'] === 'googledrive') { |
| 93 | $options['pass'] = ''; |
| 94 | } |
| 95 | |
| 96 | $options = array_merge($this->session->get('GoogleDriveAuthParams', []), $options); |
| 97 | |
| 98 | if (!isset($options['access_token'])) { |
| 99 | $options['access_token'] = $this->session->get('GoogleDriveTokens', []); |
| 100 | $this->session->remove('GoogleDriveTokens'); |
| 101 | } |
| 102 | $aToken = $options['access_token']; |
| 103 | |
| 104 | $rootObj = $service = null; |
| 105 | if ($aToken) { |
| 106 | try { |
| 107 | $client->setAccessToken($aToken); |
| 108 | if ($client->isAccessTokenExpired()) { |
| 109 | $aToken = array_merge($aToken, $client->fetchAccessTokenWithRefreshToken()); |
| 110 | $client->setAccessToken($aToken); |
| 111 | } |
| 112 | $service = new \Google_Service_Drive($client); |
| 113 | $rootObj = $service->files->get('root'); |
| 114 | |
| 115 | $options['access_token'] = $aToken; |
| 116 | $this->session->set('GoogleDriveAuthParams', $options); |
| 117 | |
| 118 | } catch (Exception $e) { |
| 119 | $aToken = []; |
| 120 | $options['access_token'] = []; |
| 121 | if ($options['user'] !== 'init') { |
| 122 | $this->session->set('GoogleDriveAuthParams', $options); |
| 123 | return array('exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | } |
| 128 | |
| 129 | $itpCare = isset($options['code']); |
| 130 | $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : ''); |
| 131 | if ($code || $options['user'] === 'init') { |
| 132 | if (empty($options['url'])) { |
| 133 | $options['url'] = elFinder::getConnectorUrl(); |
| 134 | } |
| 135 | |
| 136 | if (isset($options['id'])) { |
| 137 | $callback = $options['url'] . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']); |
| 138 | $client->setRedirectUri($callback); |
| 139 | } |
| 140 | |
| 141 | if (!$aToken && empty($code)) { |
| 142 | $client->setScopes([Google_Service_Drive::DRIVE]); |
| 143 | if (!empty($options['offline'])) { |
| 144 | $client->setApprovalPrompt('force'); |
| 145 | $client->setAccessType('offline'); |
| 146 | } |
| 147 | $url = $client->createAuthUrl(); |
| 148 | |
| 149 | $html = '<input id="elf-volumedriver-googledrive-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button">'; |
| 150 | $html .= '<script> |
| 151 | $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "googledrive", mode: "makebtn", url: "' . $url . '"}); |
| 152 | </script>'; |
| 153 | if (empty($options['pass']) && $options['host'] !== '1') { |
| 154 | $options['pass'] = 'return'; |
| 155 | $this->session->set('GoogleDriveAuthParams', $options); |
| 156 | return array('exit' => true, 'body' => $html); |
| 157 | } else { |
| 158 | $out = array( |
| 159 | 'node' => $options['id'], |
| 160 | 'json' => '{"protocol": "googledrive", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}', |
| 161 | 'bind' => 'netmount' |
| 162 | ); |
| 163 | return array('exit' => 'callback', 'out' => $out); |
| 164 | } |
| 165 | } else { |
| 166 | if ($code) { |
| 167 | if (!empty($options['id'])) { |
| 168 | $aToken = $client->fetchAccessTokenWithAuthCode($code); |
| 169 | $options['access_token'] = $aToken; |
| 170 | unset($options['code']); |
| 171 | $this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options); |
| 172 | $out = array( |
| 173 | 'node' => $options['id'], |
| 174 | 'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}', |
| 175 | 'bind' => 'netmount' |
| 176 | ); |
| 177 | } else { |
| 178 | $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host']; |
| 179 | $out = array( |
| 180 | 'node' => $nodeid, |
| 181 | 'json' => json_encode(array( |
| 182 | 'protocol' => 'googledrive', |
| 183 | 'host' => $nodeid, |
| 184 | 'mode' => 'redirect', |
| 185 | 'options' => array( |
| 186 | 'id' => $nodeid, |
| 187 | 'code'=> $code |
| 188 | ) |
| 189 | )), |
| 190 | 'bind' => 'netmount' |
| 191 | ); |
| 192 | } |
| 193 | if (!$itpCare) { |
| 194 | return array('exit' => 'callback', 'out' => $out); |
| 195 | } else { |
| 196 | return array('exit' => true, 'body' => $out['json']); |
| 197 | } |
| 198 | } |
| 199 | $folders = []; |
| 200 | foreach ($service->files->listFiles([ |
| 201 | 'pageSize' => 1000, |
| 202 | 'q' => 'trashed = false and mimeType = "application/vnd.google-apps.folder"' |
| 203 | ]) as $f) { |
| 204 | $folders[$f->getId()] = $f->getName(); |
| 205 | } |
| 206 | natcasesort($folders); |
| 207 | $folders = ['root' => $rootObj->getName()] + $folders; |
| 208 | $folders = json_encode($folders); |
| 209 | $json = '{"protocol": "googledrive", "mode": "done", "folders": ' . $folders . '}'; |
| 210 | $options['pass'] = 'return'; |
| 211 | $html = 'Google.com'; |
| 212 | $html .= '<script> |
| 213 | $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . '); |
| 214 | </script>'; |
| 215 | $this->session->set('GoogleDriveAuthParams', $options); |
| 216 | return array('exit' => true, 'body' => $html); |
| 217 | } |
| 218 | } |
| 219 | } catch (Exception $e) { |
| 220 | $this->session->remove('GoogleDriveAuthParams')->remove('GoogleDriveTokens'); |
| 221 | if (empty($options['pass'])) { |
| 222 | return array('exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage()); |
| 223 | } else { |
| 224 | return array('exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | if (!$aToken) { |
| 229 | return array('exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE); |
| 230 | } |
| 231 | |
| 232 | if ($options['path'] === '/') { |
| 233 | $options['path'] = 'root'; |
| 234 | } |
| 235 | |
| 236 | try { |
| 237 | $file = $service->files->get($options['path']); |
| 238 | $options['alias'] = sprintf($this->options['gdAlias'], $file->getName()); |
| 239 | if (!empty($this->options['netkey'])) { |
| 240 | elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); |
| 241 | } |
| 242 | } catch (Google_Service_Exception $e) { |
| 243 | $err = json_decode($e->getMessage(), true); |
| 244 | if (isset($err['error']) && $err['error']['code'] == 404) { |
| 245 | return array('exit' => true, 'error' => [elFinder::ERROR_TRGDIR_NOT_FOUND, $options['path']]); |
| 246 | } else { |
| 247 | return array('exit' => true, 'error' => $e->getMessage()); |
| 248 | } |
| 249 | } catch (Exception $e) { |
| 250 | return array('exit' => true, 'error' => $e->getMessage()); |
| 251 | } |
| 252 | |
| 253 | foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) { |
| 254 | unset($options[$key]); |
| 255 | } |
| 256 | |
| 257 | return $options; |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * process of on netunmount |
| 262 | * Drop table `dropbox` & rm thumbs |
| 263 | * |
| 264 | * @param $netVolumes |
| 265 | * @param $key |
| 266 | * |
| 267 | * @return bool |
| 268 | * @internal param array $options |
| 269 | */ |
| 270 | public function netunmount($netVolumes, $key) |
| 271 | { |
| 272 | $cache = $this->options['gdCacheDir'] . DIRECTORY_SEPARATOR . $this->options['gdCachePrefix'] . $this->netMountKey; |
| 273 | if (file_exists($cache) && is_writeable($cache)) { |
| 274 | unlink($cache); |
| 275 | } |
| 276 | if ($tmbs = glob($this->tmbPath . DIRECTORY_SEPARATOR . $this->netMountKey . '*')) { |
| 277 | foreach ($tmbs as $file) { |
| 278 | unlink($file); |
| 279 | } |
| 280 | } |
| 281 | return true; |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * "Mount" volume. |
| 286 | * Return true if volume available for read or write, |
| 287 | * false - otherwise |
| 288 | * |
| 289 | * @param array $opts |
| 290 | * |
| 291 | * @return bool |
| 292 | * @author Naoki Sawada |
| 293 | */ |
| 294 | public function mount(array $opts) |
| 295 | { |
| 296 | $creds = null; |
| 297 | if (isset($opts['access_token'])) { |
| 298 | $this->netMountKey = md5(join('-', array('googledrive', $opts['path'], (isset($opts['access_token']['refresh_token']) ? $opts['access_token']['refresh_token'] : $opts['access_token']['access_token'])))); |
| 299 | } |
| 300 | |
| 301 | $client = new \Google_Client(); |
| 302 | $client->setClientId($opts['client_id']); |
| 303 | $client->setClientSecret($opts['client_secret']); |
| 304 | |
| 305 | if (!empty($opts['access_token'])) { |
| 306 | $client->setAccessToken($opts['access_token']); |
| 307 | } |
| 308 | if ($this->needOnline && $client->isAccessTokenExpired()) { |
| 309 | try { |
| 310 | $creds = $client->fetchAccessTokenWithRefreshToken(); |
| 311 | } catch (LogicException $e) { |
| 312 | $this->session->remove('GoogleDriveAuthParams'); |
| 313 | throw $e; |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | $service = new \Google_Service_Drive($client); |
| 318 | |
| 319 | // If path is not set, use the root |
| 320 | if (!isset($opts['path']) || $opts['path'] === '') { |
| 321 | $opts['path'] = 'root'; |
| 322 | } |
| 323 | |
| 324 | $googleDrive = new GoogleDriveAdapter($service, $opts['path'], ['useHasDir' => true]); |
| 325 | |
| 326 | $opts['fscache'] = null; |
| 327 | if ($this->options['gdCacheDir'] && is_writeable($this->options['gdCacheDir'])) { |
| 328 | if ($this->options['gdCacheExpire']) { |
| 329 | $opts['fscache'] = new elFinderVolumeFlysystemGoogleDriveCache(new Local($this->options['gdCacheDir']), $this->options['gdCachePrefix'] . $this->netMountKey, $this->options['gdCacheExpire']); |
| 330 | } |
| 331 | } |
| 332 | if ($opts['fscache']) { |
| 333 | $filesystem = new Filesystem(new CachedAdapter($googleDrive, $opts['fscache'])); |
| 334 | } else { |
| 335 | $filesystem = new Filesystem($googleDrive); |
| 336 | } |
| 337 | |
| 338 | $opts['driver'] = 'FlysystemExt'; |
| 339 | $opts['filesystem'] = $filesystem; |
| 340 | $opts['separator'] = '/'; |
| 341 | $opts['checkSubfolders'] = true; |
| 342 | if (!isset($opts['alias'])) { |
| 343 | $opts['alias'] = 'GoogleDrive'; |
| 344 | } |
| 345 | |
| 346 | if ($res = parent::mount($opts)) { |
| 347 | // update access_token of session data |
| 348 | if ($creds) { |
| 349 | $netVolumes = $this->session->get('netvolume'); |
| 350 | $netVolumes[$this->netMountKey]['access_token'] = array_merge($netVolumes[$this->netMountKey]['access_token'], $creds); |
| 351 | $this->session->set('netvolume', $netVolumes); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | return $res; |
| 356 | } |
| 357 | |
| 358 | /** |
| 359 | * @inheritdoc |
| 360 | */ |
| 361 | protected function tmbname($stat) |
| 362 | { |
| 363 | return $this->netMountKey . substr(substr($stat['hash'], strlen($this->id)), -38) . $stat['ts'] . '.png'; |
| 364 | } |
| 365 | |
| 366 | /** |
| 367 | * Return debug info for client. |
| 368 | * |
| 369 | * @return array |
| 370 | **/ |
| 371 | public function debug() |
| 372 | { |
| 373 | $res = parent::debug(); |
| 374 | if (!empty($this->options['netkey']) && empty($this->options['refresh_token']) && $this->options['access_token'] && isset($this->options['access_token']['refresh_token'])) { |
| 375 | $res['refresh_token'] = $this->options['access_token']['refresh_token']; |
| 376 | } |
| 377 | |
| 378 | return $res; |
| 379 | } |
| 380 | } |
| 381 |