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 / elFinderVolumeDropbox.class.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
elFinderVolumeDropbox.class.php
1465 lines
1 <?php
2
3 elFinder::$netDrivers['dropbox'] = 'Dropbox';
4
5 /**
6 * Simple elFinder driver for FTP
7 *
8 * @author Dmitry (dio) Levashov
9 * @author Cem (discofever)
10 **/
11 class elFinderVolumeDropbox extends elFinderVolumeDriver {
12
13 /**
14 * Driver id
15 * Must be started from letter and contains [a-z0-9]
16 * Used as part of volume id
17 *
18 * @var string
19 **/
20 protected $driverId = 'd';
21
22 /**
23 * OAuth object
24 *
25 * @var oauth
26 **/
27 protected $oauth = null;
28
29 /**
30 * Dropbox object
31 *
32 * @var dropbox
33 **/
34 protected $dropbox = null;
35
36 /**
37 * Directory for meta data caches
38 * If not set driver not cache meta data
39 *
40 * @var string
41 **/
42 protected $metaCache = '';
43
44 /**
45 * Last API error message
46 *
47 * @var string
48 **/
49 protected $apiError = '';
50
51 /**
52 * Directory for tmp files
53 * If not set driver will try to use tmbDir as tmpDir
54 *
55 * @var string
56 **/
57 protected $tmp = '';
58
59 /**
60 * Dropbox.com uid
61 *
62 * @var string
63 **/
64 protected $dropboxUid = '';
65
66 /**
67 * Dropbox download host, replaces 'www.dropbox.com' of shares URL
68 *
69 * @var string
70 */
71 private $dropbox_dlhost = 'dl.dropboxusercontent.com';
72
73 private $dropbox_phpFound = false;
74
75 private $DB_TableName = '';
76
77 private $tmbPrefix = '';
78
79 /**
80 * Constructor
81 * Extend options with required fields
82 *
83 * @author Dmitry (dio) Levashov
84 * @author Cem (DiscoFever)
85 */
86 public function __construct() {
87
88 // check with composer
89 $this->dropbox_phpFound = class_exists('Dropbox_API');
90
91 if (! $this->dropbox_phpFound) {
92 // check with pear
93 if (include_once 'Dropbox/autoload.php') {
94 $this->dropbox_phpFound = in_array('Dropbox_autoload', spl_autoload_functions());
95 }
96 }
97
98 $opts = array(
99 'consumerKey' => '',
100 'consumerSecret' => '',
101 'accessToken' => '',
102 'accessTokenSecret' => '',
103 'dropboxUid' => '',
104 'root' => 'dropbox',
105 'path' => '/',
106 'separator' => '/',
107 'PDO_DSN' => '', // if empty use 'sqlite:(metaCachePath|tmbPath)/elFinder_dropbox_db_(hash:dropboxUid+consumerSecret)'
108 'PDO_User' => '',
109 'PDO_Pass' => '',
110 'PDO_Options' => array(),
111 'PDO_DBName' => 'dropbox',
112 'treeDeep' => 0,
113 'tmbPath' => '',
114 'tmbURL' => '',
115 'tmpPath' => '',
116 'getTmbSize' => 'large', // small: 32x32, medium or s: 64x64, large or m: 128x128, l: 640x480, xl: 1024x768
117 'metaCachePath' => '',
118 'metaCacheTime' => '600', // 10m
119 'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
120 'rootCssClass' => 'elfinder-navbar-root-dropbox'
121 );
122 $this->options = array_merge($this->options, $opts);
123 $this->options['mimeDetect'] = 'internal';
124 }
125
126 /**
127 * Prepare
128 * Call from elFinder::netmout() before volume->mount()
129 *
130 * @param $options
131 * @return Array
132 * @author Naoki Sawada
133 */
134 public function netmountPrepare($options) {
135 if (empty($options['consumerKey']) && defined('ELFINDER_DROPBOX_CONSUMERKEY')) $options['consumerKey'] = ELFINDER_DROPBOX_CONSUMERKEY;
136 if (empty($options['consumerSecret']) && defined('ELFINDER_DROPBOX_CONSUMERSECRET')) $options['consumerSecret'] = ELFINDER_DROPBOX_CONSUMERSECRET;
137
138 if ($options['user'] === 'init') {
139
140 if (! $this->dropbox_phpFound || empty($options['consumerKey']) || empty($options['consumerSecret']) || !class_exists('PDO', false)) {
141 return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
142 }
143
144 if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) {
145 $this->oauth = new Dropbox_OAuth_Curl($options['consumerKey'], $options['consumerSecret']);
146 } else {
147 if (class_exists('OAuth', false)) {
148 $this->oauth = new Dropbox_OAuth_PHP($options['consumerKey'], $options['consumerSecret']);
149 } else {
150 if (! class_exists('HTTP_OAuth_Consumer')) {
151 // We're going to try to load in manually
152 include 'HTTP/OAuth/Consumer.php';
153 }
154 if (class_exists('HTTP_OAuth_Consumer', false)) {
155 $this->oauth = new Dropbox_OAuth_PEAR($options['consumerKey'], $options['consumerSecret']);
156 }
157 }
158 }
159
160 if (! $this->oauth) {
161 return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
162 }
163
164 if ($options['pass'] === 'init') {
165 $html = '';
166 if ($sessionToken = $this->session->get('DropboxTokens')) {
167 // token check
168 try {
169 list(, $accessToken, $accessTokenSecret) = $sessionToken;
170 $this->oauth->setToken($accessToken, $accessTokenSecret);
171 $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']);
172 $this->dropbox->getAccountInfo();
173 $script = '<script>
174 $("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "done"});
175 </script>';
176 $html = $script;
177 } catch (Dropbox_Exception $e) {
178 $this->session->remove('DropboxTokens');
179 }
180 }
181 if (! $html) {
182 // get customdata
183 $cdata = '';
184 $innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user');
185 $this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST'? $_POST : $_GET;
186 foreach($this->ARGS as $k => $v) {
187 if (! in_array($k, $innerKeys)) {
188 $cdata .= '&' . $k . '=' . rawurlencode($v);
189 }
190 }
191 if (strpos($options['url'], 'http') !== 0 ) {
192 $options['url'] = elFinder::getConnectorUrl();
193 }
194 $callback = $options['url']
195 . '?cmd=netmount&protocol=dropbox&host=dropbox.com&user=init&pass=return&node='.$options['id'].$cdata;
196
197 try {
198 $tokens = $this->oauth->getRequestToken();
199 $url= $this->oauth->getAuthorizeUrl(rawurlencode($callback));
200 } catch (Dropbox_Exception $e) {
201 return array('exit' => true, 'body' => '{msg:errAccess}');
202 }
203
204 $this->session->set('DropboxAuthTokens', $tokens);
205 $html = '<input id="elf-volumedriver-dropbox-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button" onclick="window.open(\''.$url.'\')">';
206 $html .= '<script>
207 $("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "makebtn"});
208 </script>';
209 }
210 return array('exit' => true, 'body' => $html);
211 } else {
212 $this->oauth->setToken($this->session->get('DropboxAuthTokens'));
213 $this->session->remove('DropboxAuthTokens');
214 $tokens = $this->oauth->getAccessToken();
215 $this->session->set('DropboxTokens', array($_GET['uid'], $tokens['token'], $tokens['token_secret']));
216
217 $out = array(
218 'node' => $_GET['node'],
219 'json' => '{"protocol": "dropbox", "mode": "done"}',
220 'bind' => 'netmount'
221 );
222
223 return array('exit' => 'callback', 'out' => $out);
224 }
225 }
226 if ($sessionToken = $this->session->get('DropboxTokens')) {
227 list($options['dropboxUid'], $options['accessToken'], $options['accessTokenSecret']) = $sessionToken;
228 }
229 unset($options['user'], $options['pass']);
230 return $options;
231 }
232
233 /**
234 * process of on netunmount
235 * Drop table `dropbox` & rm thumbs
236 *
237 * @param $netVolumes
238 * @param $key
239 * @return bool
240 * @internal param array $options
241 */
242 public function netunmount($netVolumes, $key) {
243 $count = 0;
244 $dropboxUid = '';
245 if (isset($netVolumes[$key])) {
246 $dropboxUid = $netVolumes[$key]['dropboxUid'];
247 }
248 foreach($netVolumes as $volume) {
249 if ($volume['host'] === 'dropbox' && $volume['dropboxUid'] === $dropboxUid) {
250 $count++;
251 }
252 }
253 if ($count === 1) {
254 $this->DB->exec('drop table '.$this->DB_TableName);
255 foreach(glob(rtrim($this->options['tmbPath'], '\\/').DIRECTORY_SEPARATOR.$this->tmbPrefix.'*.png') as $tmb) {
256 unlink($tmb);
257 }
258 }
259 return true;
260 }
261
262 /*********************************************************************/
263 /* INIT AND CONFIGURE */
264 /*********************************************************************/
265
266 /**
267 * Prepare FTP connection
268 * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn
269 *
270 * @return bool
271 * @author Dmitry (dio) Levashov
272 * @author Cem (DiscoFever)
273 **/
274 protected function init() {
275 if (!class_exists('PDO', false)) {
276 return $this->setError('PHP PDO class is require.');
277 }
278
279 if (!$this->options['consumerKey']
280 || !$this->options['consumerSecret']
281 || !$this->options['accessToken']
282 || !$this->options['accessTokenSecret']) {
283 return $this->setError('Required options undefined.');
284 }
285
286 if (empty($this->options['metaCachePath']) && defined('ELFINDER_DROPBOX_META_CACHE_PATH')) {
287 $this->options['metaCachePath'] = ELFINDER_DROPBOX_META_CACHE_PATH;
288 }
289
290 // make net mount key
291 $this->netMountKey = md5(join('-', array('dropbox', $this->options['path'])));
292
293 if (! $this->oauth) {
294 if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) {
295 $this->oauth = new Dropbox_OAuth_Curl($this->options['consumerKey'], $this->options['consumerSecret']);
296 } else {
297 if (class_exists('OAuth', false)) {
298 $this->oauth = new Dropbox_OAuth_PHP($this->options['consumerKey'], $this->options['consumerSecret']);
299 } else {
300 if (! class_exists('HTTP_OAuth_Consumer')) {
301 // We're going to try to load in manually
302 include 'HTTP/OAuth/Consumer.php';
303 }
304 if (class_exists('HTTP_OAuth_Consumer', false)) {
305 $this->oauth = new Dropbox_OAuth_PEAR($this->options['consumerKey'], $this->options['consumerSecret']);
306 }
307 }
308 }
309 }
310
311 if (! $this->oauth) {
312 return $this->setError('OAuth extension not loaded.');
313 }
314
315 // normalize root path
316 $this->root = $this->options['path'] = $this->_normpath($this->options['path']);
317
318 if (empty($this->options['alias'])) {
319 $this->options['alias'] = ($this->options['path'] === '/')? 'Dropbox.com' : 'Dropbox'.$this->options['path'];
320 }
321
322 $this->rootName = $this->options['alias'];
323
324 try {
325 $this->oauth->setToken($this->options['accessToken'], $this->options['accessTokenSecret']);
326 $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']);
327 } catch (Dropbox_Exception $e) {
328 $this->session->remove('DropboxTokens');
329 return $this->setError('Dropbox error: '.$e->getMessage());
330 }
331
332 // user
333 if (empty($this->options['dropboxUid'])) {
334 try {
335 $res = $this->dropbox->getAccountInfo();
336 $this->options['dropboxUid'] = $res['uid'];
337 } catch (Dropbox_Exception $e) {
338 $this->session->remove('DropboxTokens');
339 return $this->setError('Dropbox error: '.$e->getMessage());
340 }
341 }
342
343 $this->dropboxUid = $this->options['dropboxUid'];
344 $this->tmbPrefix = 'dropbox'.base_convert($this->dropboxUid, 10, 32);
345
346 if (!empty($this->options['tmpPath'])) {
347 if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
348 $this->tmp = $this->options['tmpPath'];
349 }
350 }
351 if (!$this->tmp && is_writable($this->options['tmbPath'])) {
352 $this->tmp = $this->options['tmbPath'];
353 }
354 if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
355 $this->tmp = $tmp;
356 }
357
358 if (!empty($this->options['metaCachePath'])) {
359 if ((is_dir($this->options['metaCachePath']) || mkdir($this->options['metaCachePath'])) && is_writable($this->options['metaCachePath'])) {
360 $this->metaCache = $this->options['metaCachePath'];
361 }
362 }
363 if (!$this->metaCache && $this->tmp) {
364 $this->metaCache = $this->tmp;
365 }
366
367 if (!$this->metaCache) {
368 return $this->setError('Cache dirctory (metaCachePath or tmp) is require.');
369 }
370
371 // setup PDO
372 if (! $this->options['PDO_DSN']) {
373 $this->options['PDO_DSN'] = 'sqlite:'.$this->metaCache.DIRECTORY_SEPARATOR.'.elFinder_dropbox_db_'.md5($this->dropboxUid.$this->options['consumerSecret']);
374 }
375 // DataBase table name
376 $this->DB_TableName = $this->options['PDO_DBName'];
377 // DataBase check or make table
378 try {
379 $this->DB = new PDO($this->options['PDO_DSN'], $this->options['PDO_User'], $this->options['PDO_Pass'], $this->options['PDO_Options']);
380 if (! $this->checkDB()) {
381 return $this->setError('Can not make DB table');
382 }
383 } catch (PDOException $e) {
384 return $this->setError('PDO connection failed: '.$e->getMessage());
385 }
386
387 $res = $this->deltaCheck($this->isMyReload());
388 if ($res !== true) {
389 if (is_string($res)) {
390 return $this->setError($res);
391 } else {
392 return $this->setError('Could not check API "delta"');
393 }
394 }
395
396 if (is_null($this->options['syncChkAsTs'])) {
397 $this->options['syncChkAsTs'] = true;
398 }
399 if ($this->options['syncChkAsTs']) {
400 // 'tsPlSleep' minmum 5 sec
401 $this->options['tsPlSleep'] = max(5, $this->options['tsPlSleep']);
402 } else {
403 // 'lsPlSleep' minmum 10 sec
404 $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
405 }
406
407 return true;
408 }
409
410
411 /**
412 * Configure after successful mount.
413 *
414 * @return string
415 * @author Dmitry (dio) Levashov
416 **/
417 protected function configure() {
418 parent::configure();
419
420 $this->disabled[] = 'archive';
421 $this->disabled[] = 'extract';
422 }
423
424 /**
425 * Check DB for delta cache
426 *
427 * @return bool
428 */
429 private function checkDB() {
430 $res = $this->query('SELECT * FROM sqlite_master WHERE type=\'table\' AND name=\''.$this->DB_TableName.'\'');
431 if ($res && isset($_REQUEST['init'])) {
432 // check is index(nameidx) UNIQUE?
433 $chk = $this->query('SELECT sql FROM sqlite_master WHERE type=\'index\' and name=\'nameidx\'');
434 if (!$chk || strpos(strtoupper($chk[0]), 'UNIQUE') === false) {
435 // remake
436 $this->DB->exec('DROP TABLE '.$this->DB_TableName);
437 $res = false;
438 }
439 }
440 if (! $res) {
441 try {
442 $this->DB->exec('CREATE TABLE '.$this->DB_TableName.'(path text, fname text, dat blob, isdir integer);');
443 $this->DB->exec('CREATE UNIQUE INDEX nameidx ON '.$this->DB_TableName.'(path, fname)');
444 $this->DB->exec('CREATE INDEX isdiridx ON '.$this->DB_TableName.'(isdir)');
445 } catch (PDOException $e) {
446 return $this->setError($e->getMessage());
447 }
448 }
449 return true;
450 }
451
452 /**
453 * DB query and fetchAll
454 *
455 * @param string $sql
456 * @return boolean|array
457 */
458 private function query($sql) {
459 if ($sth = $this->DB->query($sql)) {
460 $res = $sth->fetchAll(PDO::FETCH_COLUMN);
461 } else {
462 $res = false;
463 }
464 return $res;
465 }
466
467 /**
468 * Get dat(dropbox metadata) from DB
469 *
470 * @param string $path
471 * @return array dropbox metadata
472 */
473 private function getDBdat($path) {
474 if ($res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower($this->_basename($path))).' limit 1')) {
475 return unserialize($res[0]);
476 } else {
477 return array();
478 }
479 }
480
481 /**
482 * Update DB dat(dropbox metadata)
483 *
484 * @param string $path
485 * @param array $dat
486 * @return bool|array
487 */
488 private function updateDBdat($path, $dat) {
489 return $this->query('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($dat))
490 . ', isdir=' . ($dat['is_dir']? 1 : 0)
491 . ' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower($this->_basename($path))));
492 }
493 /*********************************************************************/
494 /* FS API */
495 /*********************************************************************/
496
497 /**
498 * Close opened connection
499 *
500 * @return void
501 * @author Dmitry (dio) Levashov
502 **/
503 public function umount() {
504
505 }
506
507 /**
508 * Get delta data and DB update
509 *
510 * @param boolean $refresh force refresh
511 * @return true|string error message
512 */
513 protected function deltaCheck($refresh = true) {
514 $chk = false;
515 if (! $refresh && $chk = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) {
516 $chk = unserialize($chk[0]);
517 }
518 if ($chk && ($chk['mtime'] + $this->options['metaCacheTime']) > $_SERVER['REQUEST_TIME']) {
519 return true;
520 }
521
522 try {
523 $more = true;
524 $this->DB->beginTransaction();
525
526 if ($res = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) {
527 $res = unserialize($res[0]);
528 $cursor = $res['cursor'];
529 } else {
530 $cursor = '';
531 }
532 $delete = false;
533 $reset = false;
534 $ptimes = array();
535 $now = time();
536 do {
537 ini_set('max_execution_time', 120);
538 $_info = $this->dropbox->delta($cursor);
539 if (! empty($_info['reset'])) {
540 $this->DB->exec('TRUNCATE table '.$this->DB_TableName);
541 $this->DB->exec('insert into '.$this->DB_TableName.' values(\'\', \'\', \''.serialize(array('cursor' => '', 'mtime' => 0)).'\', 0);');
542 $this->DB->exec('insert into '.$this->DB_TableName.' values(\'/\', \'\', \''.serialize(array(
543 'path' => '/',
544 'is_dir' => 1,
545 'mime_type' => '',
546 'bytes' => 0
547 )).'\', 0);');
548 $reset = true;
549 }
550 $cursor = $_info['cursor'];
551
552 foreach($_info['entries'] as $entry) {
553 $key = strtolower($entry[0]);
554 $pkey = strtolower($this->_dirname($key));
555
556 $path = $this->DB->quote($pkey);
557 $fname = $this->DB->quote(strtolower($this->_basename($key)));
558 $where = 'where path='.$path.' and fname='.$fname;
559
560 if (empty($entry[1])) {
561 $ptimes[$pkey] = isset($ptimes[$pkey])? max(array($now, $ptimes[$pkey])) : $now;
562 $this->DB->exec('delete from '.$this->DB_TableName.' '.$where);
563 ! $delete && $delete = true;
564 continue;
565 }
566
567 $_itemTime = strtotime(isset($entry[1]['client_mtime'])? $entry[1]['client_mtime'] : $entry[1]['modified']);
568 $ptimes[$pkey] = isset($ptimes[$pkey])? max(array($_itemTime, $ptimes[$pkey])) : $_itemTime;
569 $sql = 'select path from '.$this->DB_TableName.' '.$where.' limit 1';
570 if (! $reset && $this->query($sql)) {
571 $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($entry[1])).', isdir='.($entry[1]['is_dir']? 1 : 0).' ' .$where);
572 } else {
573 $this->DB->exec('insert into '.$this->DB_TableName.' values ('.$path.', '.$fname.', '.$this->DB->quote(serialize($entry[1])).', '.(int)$entry[1]['is_dir'].')');
574 }
575 }
576 } while (! empty($_info['has_more']));
577
578 // update time stamp of parent holder
579 foreach ($ptimes as $_p => $_t) {
580 if ($praw = $this->getDBdat($_p)) {
581 $_update = false;
582 if (isset($praw['client_mtime']) && $_t > strtotime($praw['client_mtime'])) {
583 $praw['client_mtime'] = date('r', $_t);
584 $_update = true;
585 }
586 if (isset($praw['modified']) && $_t > strtotime($praw['modified'])) {
587 $praw['modified'] = date('r', $_t);
588 $_update = true;
589 }
590 if ($_update) {
591 $pwhere = 'where path='.$this->DB->quote(strtolower($this->_dirname($_p))).' and fname='.$this->DB->quote(strtolower($this->_basename($_p)));
592 $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($praw)).' '.$pwhere);
593 }
594 }
595 }
596
597 $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize(array('cursor'=>$cursor, 'mtime'=>$_SERVER['REQUEST_TIME']))).' where path=\'\' and fname=\'\'');
598 if (! $this->DB->commit()) {
599 $e = $this->DB->errorInfo();
600 return $e[2];
601 }
602 if ($delete) {
603 $this->DB->exec('vacuum');
604 }
605 } catch(Dropbox_Exception $e) {
606 return $e->getMessage();
607 }
608 return true;
609 }
610
611 /**
612 * Parse line from dropbox metadata output and return file stat (array)
613 *
614 * @param string $raw line from ftp_rawlist() output
615 * @return array
616 * @author Dmitry Levashov
617 **/
618 protected function parseRaw($raw) {
619 $stat = array();
620
621 $stat['rev'] = isset($raw['rev'])? $raw['rev'] : 'root';
622 $stat['name'] = $this->_basename($raw['path']);
623 $stat['mime'] = $raw['is_dir']? 'directory' : $raw['mime_type'];
624 $stat['size'] = $stat['mime'] == 'directory' ? 0 : $raw['bytes'];
625 $stat['ts'] = isset($raw['client_mtime'])? strtotime($raw['client_mtime']) :
626 (isset($raw['modified'])? strtotime($raw['modified']) : $_SERVER['REQUEST_TIME']);
627 $stat['dirs'] = 0;
628 if ($raw['is_dir']) {
629 $stat['dirs'] = (int)(bool)$this->query('select path from '.$this->DB_TableName.' where isdir=1 and path='.$this->DB->quote(strtolower($raw['path'])));
630 }
631
632 if (!empty($raw['url'])) {
633 $stat['url'] = $raw['url'];
634 } else if (! $this->disabledGetUrl) {
635 $stat['url'] = '1';
636 }
637 if (isset($raw['width'])) $stat['width'] = $raw['width'];
638 if (isset($raw['height'])) $stat['height'] = $raw['height'];
639
640 return $stat;
641 }
642
643 /**
644 * Cache dir contents
645 *
646 * @param string $path dir path
647 * @return string
648 * @author Dmitry Levashov
649 **/
650 protected function cacheDir($path) {
651 $this->dirsCache[$path] = array();
652 $hasDir = false;
653
654 $res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($path)));
655
656 if ($res) {
657 foreach($res as $raw) {
658 $raw = unserialize($raw);
659 if ($stat = $this->parseRaw($raw)) {
660 $stat = $this->updateCache($raw['path'], $stat);
661 if (empty($stat['hidden']) && $path !== $raw['path']) {
662 if (! $hasDir && $stat['mime'] === 'directory') {
663 $hasDir = true;
664 }
665 $this->dirsCache[$path][] = $raw['path'];
666 }
667 }
668 }
669 }
670
671 if (isset($this->sessionCache['subdirs'])) {
672 $this->sessionCache['subdirs'][$path] = $hasDir;
673 }
674
675 return $this->dirsCache[$path];
676 }
677
678 /**
679 * Recursive files search
680 *
681 * @param string $path dir path
682 * @param string $q search string
683 * @param array $mimes
684 * @return array
685 * @author Naoki Sawada
686 **/
687 protected function doSearch($path, $q, $mimes) {
688 $result = array();
689 $sth = $this->DB->prepare('select dat from '.$this->DB_TableName.' WHERE path LIKE ? AND fname LIKE ?');
690 $sth->execute(array((($path === '/')? '' : strtolower($path)).'%', '%'.strtolower($q).'%'));
691 $res = $sth->fetchAll(PDO::FETCH_COLUMN);
692 $timeout = $this->options['searchTimeout']? $this->searchStart + $this->options['searchTimeout'] : 0;
693
694 if ($res) {
695 foreach($res as $raw) {
696 if ($timeout && $timeout < time()) {
697 $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
698 break;
699 }
700
701 $raw = unserialize($raw);
702 if ($stat = $this->parseRaw($raw)) {
703 if (!isset($this->cache[$raw['path']])) {
704 $stat = $this->updateCache($raw['path'], $stat);
705 }
706 if (!empty($stat['hidden']) || ($mimes && $stat['mime'] === 'directory') || !$this->mimeAccepted($stat['mime'], $mimes)) {
707 continue;
708 }
709 $stat = $this->stat($raw['path']);
710 $stat['path'] = $this->path($stat['hash']);
711 $result[] = $stat;
712 }
713 }
714 }
715 return $result;
716 }
717
718 /**
719 * Copy file/recursive copy dir only in current volume.
720 * Return new file path or false.
721 *
722 * @param string $src source path
723 * @param string $dst destination dir path
724 * @param string $name new file name (optionaly)
725 * @return string|false
726 * @author Dmitry (dio) Levashov
727 * @author Naoki Sawada
728 **/
729 protected function copy($src, $dst, $name) {
730
731 $this->clearcache();
732
733 return $this->_copy($src, $dst, $name)
734 ? $this->_joinPath($dst, $name)
735 : $this->setError(elFinder::ERROR_COPY, $this->_path($src));
736 }
737
738 /**
739 * Remove file/ recursive remove dir
740 *
741 * @param string $path file path
742 * @param bool $force try to remove even if file locked
743 * @param bool $recursive
744 * @return bool
745 * @author Dmitry (dio) Levashov
746 * @author Naoki Sawada
747 */
748 protected function remove($path, $force = false, $recursive = false) {
749 $stat = $this->stat($path);
750 $stat['realpath'] = $path;
751 $this->rmTmb($stat);
752 $this->clearcache();
753
754 if (empty($stat)) {
755 return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
756 }
757
758 if (!$force && !empty($stat['locked'])) {
759 return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
760 }
761
762 if ($stat['mime'] == 'directory') {
763 if (!$recursive && !$this->_rmdir($path)) {
764 return $this->setError(elFinder::ERROR_RM, $this->_path($path));
765 }
766 } else {
767 if (!$recursive && !$this->_unlink($path)) {
768 return $this->setError(elFinder::ERROR_RM, $this->_path($path));
769 }
770 }
771
772 $this->removed[] = $stat;
773 return true;
774 }
775
776 /**
777 * Create thumnbnail and return it's URL on success
778 *
779 * @param string $path file path
780 * @param $stat
781 * @return false|string
782 * @internal param string $mime file mime type
783 * @author Dmitry (dio) Levashov
784 * @author Naoki Sawada
785 */
786 protected function createTmb($path, $stat) {
787 if (!$stat || !$this->canCreateTmb($path, $stat)) {
788 return false;
789 }
790
791 $name = $this->tmbname($stat);
792 $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
793
794 // copy image into tmbPath so some drivers does not store files on local fs
795 if (! $data = $this->getThumbnail($path, $this->options['getTmbSize'])) {
796 return false;
797 }
798 if (! file_put_contents($tmb, $data)) {
799 return false;
800 }
801
802 $result = false;
803
804 $tmbSize = $this->tmbSize;
805
806 if (($s = getimagesize($tmb)) == false) {
807 return false;
808 }
809
810 /* If image smaller or equal thumbnail size - just fitting to thumbnail square */
811 if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
812 $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
813
814 } else {
815
816 if ($this->options['tmbCrop']) {
817
818 /* Resize and crop if image bigger than thumbnail */
819 if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize) ) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
820 $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
821 }
822
823 if (($s = getimagesize($tmb)) != false) {
824 $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize)/2) : 0;
825 $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize)/2) : 0;
826 $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
827 }
828
829 } else {
830 $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
831 }
832
833 $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' );
834 }
835
836 if (!$result) {
837 unlink($tmb);
838 return false;
839 }
840
841 return $name;
842 }
843
844 /**
845 * Return thumbnail file name for required file
846 *
847 * @param array $stat file stat
848 * @return string
849 * @author Dmitry (dio) Levashov
850 **/
851 protected function tmbname($stat) {
852 return $this->tmbPrefix.$stat['rev'].'.png';
853 }
854
855 /**
856 * Get thumbnail from dropbox.com
857 * @param string $path
858 * @param string $size
859 * @return string | boolean
860 */
861 protected function getThumbnail($path, $size = 'small') {
862 try {
863 return $this->dropbox->getThumbnail($path, $size);
864 } catch (Dropbox_Exception $e) {
865 return false;
866 }
867 }
868
869 /**
870 * Return content URL
871 *
872 * @param string $hash file hash
873 * @param array $options options
874 * @return array
875 * @author Naoki Sawada
876 **/
877 public function getContentUrl($hash, $options = array()) {
878 if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) {
879 $path = $this->decode($hash);
880 $cache = $this->getDBdat($path);
881 $url = '';
882 if (isset($cache['share']) && strpos($cache['share'], $this->dropbox_dlhost) !== false) {
883 $res = $this->getHttpResponseHeader($cache['share']);
884 if (preg_match("/^HTTP\/[01\.]+ ([0-9]{3})/", $res, $match)) {
885 if ($match[1] < 400) {
886 $url = $cache['share'];
887 }
888 }
889 }
890 if (! $url) {
891 try {
892 $res = $this->dropbox->share($path, null, false);
893 $url = $res['url'];
894 if (strpos($url, 'www.dropbox.com') === false) {
895 $res = $this->getHttpResponseHeader($url);
896 if (preg_match('/^location:\s*(http[^\s]+)/im', $res, $match)) {
897 $url = $match[1];
898 }
899 }
900 list($url) = explode('?', $url);
901 $url = str_replace('www.dropbox.com', $this->dropbox_dlhost, $url);
902 if (! isset($cache['share']) || $cache['share'] !== $url) {
903 $cache['share'] = $url;
904 $this->updateDBdat($path, $cache);
905 }
906 } catch (Dropbox_Exception $e) {
907 return false;
908 }
909 }
910 return $url;
911 }
912 return $file['url'];
913 }
914
915 /**
916 * Get HTTP request response header string
917 *
918 * @param string $url target URL
919 * @return string
920 * @author Naoki Sawada
921 */
922 private function getHttpResponseHeader($url) {
923 if (function_exists('curl_exec')) {
924
925 $c = curl_init();
926 curl_setopt( $c, CURLOPT_RETURNTRANSFER, true );
927 curl_setopt( $c, CURLOPT_CUSTOMREQUEST, 'HEAD' );
928 curl_setopt( $c, CURLOPT_HEADER, 1 );
929 curl_setopt( $c, CURLOPT_NOBODY, true );
930 curl_setopt( $c, CURLOPT_URL, $url );
931 $res = curl_exec( $c );
932
933 } else {
934
935 require_once 'HTTP/Request2.php';
936 try {
937 $request2 = new HTTP_Request2();
938 $request2->setConfig(array(
939 'ssl_verify_peer' => false,
940 'ssl_verify_host' => false
941 ));
942 $request2->setUrl($url);
943 $request2->setMethod(HTTP_Request2::METHOD_HEAD);
944 $result = $request2->send();
945 $res = array();
946 $res[] = 'HTTP/'.$result->getVersion().' '.$result->getStatus().' '.$result->getReasonPhrase();
947 foreach($result->getHeader() as $key => $val) {
948 $res[] = $key . ': ' . $val;
949 }
950 $res = join("\r\n", $res);
951 } catch( HTTP_Request2_Exception $e ){
952 $res = '';
953 } catch (Exception $e){
954 $res = '';
955 }
956
957 }
958 return $res;
959 }
960
961 /*********************** paths/urls *************************/
962
963 /**
964 * Return parent directory path
965 *
966 * @param string $path file path
967 * @return string
968 * @author Dmitry (dio) Levashov
969 **/
970 protected function _dirname($path) {
971 return $this->_normpath(substr($path, 0, strrpos($path, '/')));
972 }
973
974 /**
975 * Return file name
976 *
977 * @param string $path file path
978 * @return string
979 * @author Dmitry (dio) Levashov
980 **/
981 protected function _basename($path) {
982 return substr($path, strrpos($path, '/') + 1);
983 }
984
985 /**
986 * Join dir name and file name and retur full path
987 *
988 * @param string $dir
989 * @param string $name
990 * @return string
991 * @author Dmitry (dio) Levashov
992 **/
993 protected function _joinPath($dir, $name) {
994 return $this->_normpath($dir.'/'.$name);
995 }
996
997 /**
998 * Return normalized path, this works the same as os.path.normpath() in Python
999 *
1000 * @param string $path path
1001 * @return string
1002 * @author Troex Nevelin
1003 **/
1004 protected function _normpath($path) {
1005 $path = '/' . ltrim($path, '/');
1006 return $path;
1007 }
1008
1009 /**
1010 * Return file path related to root dir
1011 *
1012 * @param string $path file path
1013 * @return string
1014 * @author Dmitry (dio) Levashov
1015 **/
1016 protected function _relpath($path) {
1017 return $path;
1018 }
1019
1020 /**
1021 * Convert path related to root dir into real path
1022 *
1023 * @param string $path file path
1024 * @return string
1025 * @author Dmitry (dio) Levashov
1026 **/
1027 protected function _abspath($path) {
1028 return $path;
1029 }
1030
1031 /**
1032 * Return fake path started from root dir
1033 *
1034 * @param string $path file path
1035 * @return string
1036 * @author Dmitry (dio) Levashov
1037 **/
1038 protected function _path($path) {
1039 return $this->rootName . $this->_normpath(substr($path, strlen($this->root)));
1040 }
1041
1042 /**
1043 * Return true if $path is children of $parent
1044 *
1045 * @param string $path path to check
1046 * @param string $parent parent path
1047 * @return bool
1048 * @author Dmitry (dio) Levashov
1049 **/
1050 protected function _inpath($path, $parent) {
1051 return $path == $parent || strpos($path, $parent.'/') === 0;
1052 }
1053
1054 /***************** file stat ********************/
1055 /**
1056 * Return stat for given path.
1057 * Stat contains following fields:
1058 * - (int) size file size in b. required
1059 * - (int) ts file modification time in unix time. required
1060 * - (string) mime mimetype. required for folders, others - optionally
1061 * - (bool) read read permissions. required
1062 * - (bool) write write permissions. required
1063 * - (bool) locked is object locked. optionally
1064 * - (bool) hidden is object hidden. optionally
1065 * - (string) alias for symlinks - link target path relative to root path. optionally
1066 * - (string) target for symlinks - link target path. optionally
1067 *
1068 * If file does not exists - returns empty array or false.
1069 *
1070 * @param string $path file path
1071 * @return array|false
1072 * @author Dmitry (dio) Levashov
1073 **/
1074 protected function _stat($path) {
1075 //if (!empty($this->ARGS['reload']) && isset($this->ARGS['target']) && strpos($this->ARGS['target'], $this->id) === 0) {
1076 if ($this->isMyReload()) {
1077 $this->deltaCheck();
1078 }
1079 if ($raw = $this->getDBdat($path)) {
1080 return $this->parseRaw($raw);
1081 }
1082 return false;
1083 }
1084
1085 /**
1086 * Return true if path is dir and has at least one childs directory
1087 *
1088 * @param string $path dir path
1089 * @return bool
1090 * @author Dmitry (dio) Levashov
1091 **/
1092 protected function _subdirs($path) {
1093 return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
1094 }
1095
1096 /**
1097 * Return object width and height
1098 * Ususaly used for images, but can be realize for video etc...
1099 *
1100 * @param string $path file path
1101 * @param string $mime file mime type
1102 * @return string
1103 * @author Dmitry (dio) Levashov
1104 **/
1105 protected function _dimensions($path, $mime) {
1106 if (strpos($mime, 'image') !== 0) return '';
1107 $cache = $this->getDBdat($path);
1108 if (isset($cache['width']) && isset($cache['height'])) {
1109 return $cache['width'].'x'.$cache['height'];
1110 }
1111 $ret = '';
1112 if ($work = $this->getWorkFile($path)) {
1113 if ($size = getimagesize($work)) {
1114 $cache['width'] = $size[0];
1115 $cache['height'] = $size[1];
1116 $this->updateDBdat($path, $cache);
1117 $ret = $size[0].'x'.$size[1];
1118 }
1119 }
1120 is_file($work) && unlink($work);
1121 return $ret;
1122 }
1123
1124 /******************** file/dir content *********************/
1125
1126 /**
1127 * Return files list in directory.
1128 *
1129 * @param string $path dir path
1130 * @return array
1131 * @author Dmitry (dio) Levashov
1132 * @author Cem (DiscoFever)
1133 **/
1134 protected function _scandir($path) {
1135 return isset($this->dirsCache[$path])
1136 ? $this->dirsCache[$path]
1137 : $this->cacheDir($path);
1138 }
1139
1140 /**
1141 * Open file and return file pointer
1142 *
1143 * @param string $path file path
1144 * @param string $mode
1145 * @return false|resource
1146 * @internal param bool $write open file for writing
1147 * @author Dmitry (dio) Levashov
1148 */
1149 protected function _fopen($path, $mode='rb') {
1150
1151 if (($mode == 'rb' || $mode == 'r')) {
1152 try {
1153 $res = $this->dropbox->media($path);
1154 $url = parse_url($res['url']);
1155 $fp = stream_socket_client('ssl://'.$url['host'].':443');
1156 fputs($fp, "GET {$url['path']} HTTP/1.0\r\n");
1157 fputs($fp, "Host: {$url['host']}\r\n");
1158 fputs($fp, "\r\n");
1159 while(trim(fgets($fp)) !== ''){};
1160 return $fp;
1161 } catch (Dropbox_Exception $e) {
1162 return false;
1163 }
1164 }
1165
1166 if ($this->tmp) {
1167 $contents = $this->_getContents($path);
1168
1169 if ($contents === false) {
1170 return false;
1171 }
1172
1173 if ($local = $this->getTempFile($path)) {
1174 if (file_put_contents($local, $contents, LOCK_EX) !== false) {
1175 return fopen($local, $mode);
1176 }
1177 }
1178 }
1179
1180 return false;
1181 }
1182
1183 /**
1184 * Close opened file
1185 *
1186 * @param resource $fp file pointer
1187 * @param string $path
1188 * @return bool
1189 * @author Dmitry (dio) Levashov
1190 */
1191 protected function _fclose($fp, $path='') {
1192 fclose($fp);
1193 if ($path) {
1194 unlink($this->getTempFile($path));
1195 }
1196 }
1197
1198 /******************** file/dir manipulations *************************/
1199
1200 /**
1201 * Create dir and return created dir path or false on failed
1202 *
1203 * @param string $path parent dir path
1204 * @param string $name new directory name
1205 * @return string|bool
1206 * @author Dmitry (dio) Levashov
1207 **/
1208 protected function _mkdir($path, $name) {
1209 $path = $this->_normpath($path.'/'.$name);
1210 try {
1211 $this->dropbox->createFolder($path);
1212 } catch (Dropbox_Exception $e) {
1213 $this->deltaCheck();
1214 if ($this->dir($this->encode($path))) {
1215 return $path;
1216 }
1217 return $this->setError('Dropbox error: '.$e->getMessage());
1218 }
1219 $this->deltaCheck();
1220 return $path;
1221 }
1222
1223 /**
1224 * Create file and return it's path or false on failed
1225 *
1226 * @param string $path parent dir path
1227 * @param string $name new file name
1228 * @return string|bool
1229 * @author Dmitry (dio) Levashov
1230 **/
1231 protected function _mkfile($path, $name) {
1232 return $this->_filePutContents($path.'/'.$name, '');
1233 }
1234
1235 /**
1236 * Create symlink. FTP driver does not support symlinks.
1237 *
1238 * @param string $target link target
1239 * @param string $path symlink path
1240 * @param string $name
1241 * @return bool
1242 * @author Dmitry (dio) Levashov
1243 */
1244 protected function _symlink($target, $path, $name) {
1245 return false;
1246 }
1247
1248 /**
1249 * Copy file into another file
1250 *
1251 * @param string $source source file path
1252 * @param string $targetDir target directory path
1253 * @param string $name new file name
1254 * @return bool
1255 * @author Dmitry (dio) Levashov
1256 **/
1257 protected function _copy($source, $targetDir, $name) {
1258 $path = $this->_normpath($targetDir.'/'.$name);
1259 try {
1260 $this->dropbox->copy($source, $path);
1261 } catch (Dropbox_Exception $e) {
1262 return $this->setError('Dropbox error: '.$e->getMessage());
1263 }
1264 $this->deltaCheck();
1265 return true;
1266 }
1267
1268 /**
1269 * Move file into another parent dir.
1270 * Return new file path or false.
1271 *
1272 * @param string $source source file path
1273 * @param $targetDir
1274 * @param string $name file name
1275 * @return bool|string
1276 * @internal param string $target target dir path
1277 * @author Dmitry (dio) Levashov
1278 */
1279 protected function _move($source, $targetDir, $name) {
1280 $target = $this->_normpath($targetDir.'/'.$name);
1281 try {
1282 $this->dropbox->move($source, $target);
1283 } catch (Dropbox_Exception $e) {
1284 return $this->setError('Dropbox error: '.$e->getMessage());
1285 }
1286 $this->deltaCheck();
1287 return $target;
1288 }
1289
1290 /**
1291 * Remove file
1292 *
1293 * @param string $path file path
1294 * @return bool
1295 * @author Dmitry (dio) Levashov
1296 **/
1297 protected function _unlink($path) {
1298 try {
1299 $this->dropbox->delete($path);
1300 } catch (Dropbox_Exception $e) {
1301 return $this->setError('Dropbox error: '.$e->getMessage());
1302 }
1303 $this->deltaCheck();
1304 return true;
1305 }
1306
1307 /**
1308 * Remove dir
1309 *
1310 * @param string $path dir path
1311 * @return bool
1312 * @author Dmitry (dio) Levashov
1313 **/
1314 protected function _rmdir($path) {
1315 return $this->_unlink($path);
1316 }
1317
1318 /**
1319 * Create new file and write into it from file pointer.
1320 * Return new file path or false on error.
1321 *
1322 * @param resource $fp file pointer
1323 * @param string $path
1324 * @param string $name file name
1325 * @param array $stat file stat (required by some virtual fs)
1326 * @return bool|string
1327 * @internal param string $dir target dir path
1328 * @author Dmitry (dio) Levashov
1329 */
1330 protected function _save($fp, $path, $name, $stat) {
1331 if ($name) $path .= '/'.$name;
1332 $path = $this->_normpath($path);
1333 try {
1334 $this->dropbox->putFile($path, $fp);
1335 } catch (Dropbox_Exception $e) {
1336 return $this->setError('Dropbox error: '.$e->getMessage());
1337 }
1338 $this->deltaCheck();
1339 if (is_array($stat)) {
1340 $raw = $this->getDBdat($path);
1341 if (isset($stat['width'])) $raw['width'] = $stat['width'];
1342 if (isset($stat['height'])) $raw['height'] = $stat['height'];
1343 $this->updateDBdat($path, $raw);
1344 }
1345 return $path;
1346 }
1347
1348 /**
1349 * Get file contents
1350 *
1351 * @param string $path file path
1352 * @return string|false
1353 * @author Dmitry (dio) Levashov
1354 **/
1355 protected function _getContents($path) {
1356 $contents = '';
1357 try {
1358 $contents = $this->dropbox->getFile($path);
1359 } catch (Dropbox_Exception $e) {
1360 return $this->setError('Dropbox error: '.$e->getMessage());
1361 }
1362 return $contents;
1363 }
1364
1365 /**
1366 * Write a string to a file
1367 *
1368 * @param string $path file path
1369 * @param string $content new file content
1370 * @return bool
1371 * @author Dmitry (dio) Levashov
1372 **/
1373 protected function _filePutContents($path, $content) {
1374 $res = false;
1375
1376 if ($local = $this->getTempFile($path)) {
1377 if (file_put_contents($local, $content, LOCK_EX) !== false
1378 && ($fp = fopen($local, 'rb'))) {
1379 clearstatcache();
1380 $res = $this->_save($fp, $path, '', array());
1381 fclose($fp);
1382 }
1383 file_exists($local) && unlink($local);
1384 }
1385
1386 return $res;
1387 }
1388
1389 /**
1390 * Detect available archivers
1391 *
1392 * @return array
1393 **/
1394 protected function _checkArchivers() {
1395 // die('Not yet implemented. (_checkArchivers)');
1396 return array();
1397 }
1398
1399 /**
1400 * chmod implementation
1401 *
1402 * @param string $path
1403 * @param string $mode
1404 * @return bool
1405 */
1406 protected function _chmod($path, $mode) {
1407 return false;
1408 }
1409
1410 /**
1411 * Unpack archive
1412 *
1413 * @param string $path archive path
1414 * @param array $arc archiver command and arguments (same as in $this->archivers)
1415 * @return true
1416 * @return void
1417 * @author Dmitry (dio) Levashov
1418 * @author Alexey Sukhotin
1419 **/
1420 protected function _unpack($path, $arc) {
1421 die('Not yet implemented. (_unpack)');
1422 }
1423
1424 /**
1425 * Recursive symlinks search
1426 *
1427 * @param string $path file/dir path
1428 * @return bool
1429 * @author Dmitry (dio) Levashov
1430 **/
1431 protected function _findSymlinks($path) {
1432 die('Not yet implemented. (_findSymlinks)');
1433 }
1434
1435 /**
1436 * Extract files from archive
1437 *
1438 * @param string $path archive path
1439 * @param array $arc archiver command and arguments (same as in $this->archivers)
1440 * @return true
1441 * @author Dmitry (dio) Levashov,
1442 * @author Alexey Sukhotin
1443 **/
1444 protected function _extract($path, $arc) {
1445 die('Not yet implemented. (_extract)');
1446
1447 }
1448
1449 /**
1450 * Create archive and return its path
1451 *
1452 * @param string $dir target dir
1453 * @param array $files files names list
1454 * @param string $name archive name
1455 * @param array $arc archiver options
1456 * @return string|bool
1457 * @author Dmitry (dio) Levashov,
1458 * @author Alexey Sukhotin
1459 **/
1460 protected function _archive($dir, $files, $name, $arc) {
1461 die('Not yet implemented. (_archive)');
1462 }
1463
1464 } // END class
1465