PluginProbe ʕ •ᴥ•ʔ
Advanced File Manager – Ultimate File Manager for WordPress And Document Library Solution / trunk
Advanced File Manager – Ultimate File Manager for WordPress And Document Library Solution vtrunk
trunk 4.1.5 4.1.6 5.0 5.2.13 5.2.14 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.4.0 5.4.1 5.4.10 5.4.11 5.4.12 5.4.2 5.4.3 5.4.4 5.4.5 5.4.6 5.4.7 5.4.8
file-manager-advanced / application / library / php / elFinderFlysystemGoogleDriveNetmount.php
file-manager-advanced / application / library / php Last commit date
.tmp 10 months ago editors 4 weeks ago libs 7 years ago plugins 3 years ago resources 7 years ago MySQLStorage.sql 1 year ago autoload.php 10 months ago connector.maximal.php-dist 1 year ago connector.minimal.php-dist 1 year ago elFinder.class.php 4 weeks ago elFinderConnector.class.php 4 weeks ago elFinderFlysystemGoogleDriveNetmount.php 5 years ago elFinderPlugin.php 7 years ago elFinderSession.php 4 years ago elFinderSessionInterface.php 7 years ago elFinderVolumeBox.class.php 5 years ago elFinderVolumeDriver.class.php 4 weeks ago elFinderVolumeDropbox.class.php 1 year ago elFinderVolumeDropbox2.class.php 4 weeks ago elFinderVolumeFTP.class.php 5 years ago elFinderVolumeGoogleDrive.class.php 5 years ago elFinderVolumeGroup.class.php 7 years ago elFinderVolumeLocalFileSystem.class.php 2 years ago elFinderVolumeMySQL.class.php 10 months ago elFinderVolumeOneDrive.class.php 4 weeks ago elFinderVolumeSFTPphpseclib.class.php 4 weeks ago elFinderVolumeTrash.class.php 7 years ago elFinderVolumeTrashMySQL.class.php 7 years ago mime.types 3 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