elFinderVolumeDropbox2.class.php 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. <?php
  2. use Kunnu\Dropbox\Dropbox;
  3. use Kunnu\Dropbox\DropboxApp;
  4. use Kunnu\Dropbox\DropboxFile;
  5. use Kunnu\Dropbox\Exceptions\DropboxClientException;
  6. use Kunnu\Dropbox\Models\FileMetadata;
  7. use Kunnu\Dropbox\Models\FolderMetadata;
  8. /**
  9. * Simple elFinder driver for Dropbox
  10. * kunalvarma05/dropbox-php-sdk:0.1.5 or above.
  11. *
  12. * @author Naoki Sawada
  13. **/
  14. class elFinderVolumeDropbox2 extends elFinderVolumeDriver
  15. {
  16. /**
  17. * Driver id
  18. * Must be started from letter and contains [a-z0-9]
  19. * Used as part of volume id.
  20. *
  21. * @var string
  22. **/
  23. protected $driverId = 'db';
  24. /**
  25. * Dropbox service object.
  26. *
  27. * @var object
  28. **/
  29. protected $service = null;
  30. /**
  31. * Fetch options.
  32. *
  33. * @var string
  34. */
  35. private $FETCH_OPTIONS = [];
  36. /**
  37. * Directory for tmp files
  38. * If not set driver will try to use tmbDir as tmpDir.
  39. *
  40. * @var string
  41. **/
  42. protected $tmp = '';
  43. /**
  44. * Net mount key.
  45. *
  46. * @var string
  47. **/
  48. public $netMountKey = '';
  49. /**
  50. * Constructor
  51. * Extend options with required fields.
  52. *
  53. * @author Naoki Sawada
  54. **/
  55. public function __construct()
  56. {
  57. $opts = [
  58. 'app_key' => '',
  59. 'app_secret' => '',
  60. 'access_token' => '',
  61. 'aliasFormat' => '%s@Dropbox',
  62. 'path' => '/',
  63. 'separator' => '/',
  64. 'acceptedName' => '#^[^\\\/]+$#',
  65. 'rootCssClass' => 'elfinder-navbar-root-dropbox',
  66. 'publishPermission' => [
  67. 'requested_visibility' => 'public',
  68. //'link_password' => '',
  69. //'expires' => '',
  70. ],
  71. 'getThumbSize' => 'medium', // Available sizes: 'thumb', 'small', 'medium', 'large', 'huge'
  72. ];
  73. $this->options = array_merge($this->options, $opts);
  74. $this->options['mimeDetect'] = 'internal';
  75. }
  76. /*********************************************************************/
  77. /* ORIGINAL FUNCTIONS */
  78. /*********************************************************************/
  79. /**
  80. * Get Parent ID, Item ID, Parent Path as an array from path.
  81. *
  82. * @param string $path
  83. *
  84. * @return array
  85. */
  86. protected function _db_splitPath($path)
  87. {
  88. $path = trim($path, '/');
  89. if ($path === '') {
  90. $dirname = '/';
  91. $basename = '';
  92. } else {
  93. $pos = strrpos($path, '/');
  94. if ($pos === false) {
  95. $dirname = '/';
  96. $basename = $path;
  97. } else {
  98. $dirname = '/' . substr($path, 0, $pos);
  99. $basename = substr($path, $pos + 1);
  100. }
  101. }
  102. return [$dirname, $basename];
  103. }
  104. /**
  105. * Get dat(Dropbox metadata) from Dropbox.
  106. *
  107. * @param string $path
  108. *
  109. * @return boolean|object Dropbox metadata
  110. */
  111. private function _db_getFile($path)
  112. {
  113. if ($path === '/') {
  114. return true;
  115. }
  116. $res = false;
  117. try {
  118. $file = $this->service->getMetadata($path, $this->FETCH_OPTIONS);
  119. if ($file instanceof FolderMetadata || $file instanceof FileMetadata) {
  120. $res = $file;
  121. }
  122. return $res;
  123. } catch (DropboxClientException $e) {
  124. return false;
  125. }
  126. }
  127. /**
  128. * Parse line from Dropbox metadata output and return file stat (array).
  129. *
  130. * @param object $raw line from ftp_rawlist() output
  131. *
  132. * @return array
  133. * @author Naoki Sawada
  134. **/
  135. protected function _db_parseRaw($raw)
  136. {
  137. $stat = [];
  138. $isFolder = false;
  139. if ($raw === true) {
  140. // root folder
  141. $isFolder = true;
  142. $stat['name'] = '';
  143. $stat['iid'] = '0';
  144. }
  145. $data = [];
  146. if (is_object($raw)) {
  147. $isFolder = $raw instanceof FolderMetadata;
  148. $data = $raw->getData();
  149. } elseif (is_array($raw)) {
  150. $isFolder = $raw['.tag'] === 'folder';
  151. $data = $raw;
  152. }
  153. if (isset($data['path_lower'])) {
  154. $stat['path'] = $data['path_lower'];
  155. }
  156. if (isset($data['name'])) {
  157. $stat['name'] = $data['name'];
  158. }
  159. if (isset($data['id'])) {
  160. $stat['iid'] = substr($data['id'], 3);
  161. }
  162. if ($isFolder) {
  163. $stat['mime'] = 'directory';
  164. $stat['size'] = 0;
  165. $stat['ts'] = 0;
  166. $stat['dirs'] = -1;
  167. } else {
  168. $stat['size'] = isset($data['size']) ? (int)$data['size'] : 0;
  169. if (isset($data['server_modified'])) {
  170. $stat['ts'] = strtotime($data['server_modified']);
  171. } elseif (isset($data['client_modified'])) {
  172. $stat['ts'] = strtotime($data['client_modified']);
  173. } else {
  174. $stat['ts'] = 0;
  175. }
  176. $stat['url'] = '1';
  177. }
  178. return $stat;
  179. }
  180. /**
  181. * Get thumbnail from Dropbox.
  182. *
  183. * @param string $path
  184. * @param string $size
  185. *
  186. * @return string | boolean
  187. */
  188. protected function _db_getThumbnail($path)
  189. {
  190. try {
  191. return $this->service->getThumbnail($path, $this->options['getThumbSize'])->getContents();
  192. } catch (DropboxClientException $e) {
  193. return false;
  194. }
  195. }
  196. /**
  197. * Join dir name and file name(display name) and retur full path.
  198. *
  199. * @param string $dir
  200. * @param string $displayName
  201. *
  202. * @return string
  203. */
  204. protected function _db_joinName($dir, $displayName)
  205. {
  206. return rtrim($dir, '/') . '/' . $displayName;
  207. }
  208. /**
  209. * Get OAuth2 access token form OAuth1 tokens.
  210. *
  211. * @param string $app_key
  212. * @param string $app_secret
  213. * @param string $oauth1_token
  214. * @param string $oauth1_secret
  215. *
  216. * @return string|false
  217. */
  218. public static function getTokenFromOauth1($app_key, $app_secret, $oauth1_token, $oauth1_secret)
  219. {
  220. $data = [
  221. 'oauth1_token' => $oauth1_token,
  222. 'oauth1_token_secret' => $oauth1_secret,
  223. ];
  224. $auth = base64_encode($app_key . ':' . $app_secret);
  225. $ch = curl_init('https://api.dropboxapi.com/2/auth/token/from_oauth1');
  226. curl_setopt($ch, CURLOPT_POST, true);
  227. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  228. curl_setopt($ch, CURLOPT_HTTPHEADER, [
  229. 'Content-Type: application/json',
  230. 'Authorization: Basic ' . $auth,
  231. ]);
  232. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  233. $result = curl_exec($ch);
  234. curl_close($ch);
  235. $res = $result ? json_decode($result, true) : [];
  236. return isset($res['oauth2_token']) ? $res['oauth2_token'] : false;
  237. }
  238. /*********************************************************************/
  239. /* EXTENDED FUNCTIONS */
  240. /*********************************************************************/
  241. /**
  242. * Prepare
  243. * Call from elFinder::netmout() before volume->mount().
  244. *
  245. * @return array
  246. * @author Naoki Sawada
  247. **/
  248. public function netmountPrepare($options)
  249. {
  250. if (empty($options['app_key']) && defined('ELFINDER_DROPBOX_APPKEY')) {
  251. $options['app_key'] = ELFINDER_DROPBOX_APPKEY;
  252. }
  253. if (empty($options['app_secret']) && defined('ELFINDER_DROPBOX_APPSECRET')) {
  254. $options['app_secret'] = ELFINDER_DROPBOX_APPSECRET;
  255. }
  256. if (!isset($options['pass'])) {
  257. $options['pass'] = '';
  258. }
  259. try {
  260. $app = new DropboxApp($options['app_key'], $options['app_secret']);
  261. $dropbox = new Dropbox($app);
  262. $authHelper = $dropbox->getAuthHelper();
  263. if ($options['pass'] === 'reauth') {
  264. $options['pass'] = '';
  265. $this->session->set('Dropbox2AuthParams', [])->set('Dropbox2Tokens', []);
  266. } elseif ($options['pass'] === 'dropbox2') {
  267. $options['pass'] = '';
  268. }
  269. $options = array_merge($this->session->get('Dropbox2AuthParams', []), $options);
  270. if (!isset($options['tokens'])) {
  271. $options['tokens'] = $this->session->get('Dropbox2Tokens', []);
  272. $this->session->remove('Dropbox2Tokens');
  273. }
  274. $aToken = $options['tokens'];
  275. if (!is_array($aToken) || !isset($aToken['access_token'])) {
  276. $aToken = [];
  277. }
  278. $service = null;
  279. if ($aToken) {
  280. try {
  281. $dropbox->setAccessToken($aToken['access_token']);
  282. $this->session->set('Dropbox2AuthParams', $options);
  283. } catch (DropboxClientException $e) {
  284. $aToken = [];
  285. $options['tokens'] = [];
  286. if ($options['user'] !== 'init') {
  287. $this->session->set('Dropbox2AuthParams', $options);
  288. return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE];
  289. }
  290. }
  291. }
  292. if ((isset($options['user']) && $options['user'] === 'init') || (isset($_GET['host']) && $_GET['host'] == '1')) {
  293. if (empty($options['url'])) {
  294. $options['url'] = elFinder::getConnectorUrl();
  295. }
  296. if (!empty($options['id'])) {
  297. $callback = $options['url']
  298. . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=dropbox2&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
  299. }
  300. $itpCare = isset($options['code']);
  301. $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
  302. $state = $itpCare? $options['state'] : (isset($_GET['state'])? $_GET['state'] : '');
  303. if (!$aToken && empty($code)) {
  304. $url = $authHelper->getAuthUrl($callback);
  305. $html = '<input id="elf-volumedriver-dropbox2-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button">';
  306. $html .= '<script>
  307. $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "dropbox2", mode: "makebtn", url: "' . $url . '"});
  308. </script>';
  309. if (empty($options['pass']) && $options['host'] !== '1') {
  310. $options['pass'] = 'return';
  311. $this->session->set('Dropbox2AuthParams', $options);
  312. return ['exit' => true, 'body' => $html];
  313. } else {
  314. $out = [
  315. 'node' => $options['id'],
  316. 'json' => '{"protocol": "dropbox2", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}',
  317. 'bind' => 'netmount',
  318. ];
  319. return ['exit' => 'callback', 'out' => $out];
  320. }
  321. } else {
  322. if ($code && $state) {
  323. if (!empty($options['id'])) {
  324. // see https://github.com/kunalvarma05/dropbox-php-sdk/issues/115
  325. $authHelper->getPersistentDataStore()->set('state', filter_var($state, FILTER_SANITIZE_STRING));
  326. $tokenObj = $authHelper->getAccessToken($code, $state, $callback);
  327. $options['tokens'] = [
  328. 'access_token' => $tokenObj->getToken(),
  329. 'uid' => $tokenObj->getUid(),
  330. ];
  331. unset($options['code'], $options['state']);
  332. $this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options);
  333. $out = [
  334. 'node' => $options['id'],
  335. 'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}',
  336. 'bind' => 'netmount',
  337. ];
  338. } else {
  339. $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
  340. $out = [
  341. 'node' => $nodeid,
  342. 'json' => json_encode(array(
  343. 'protocol' => 'dropbox2',
  344. 'host' => $nodeid,
  345. 'mode' => 'redirect',
  346. 'options' => array(
  347. 'id' => $nodeid,
  348. 'code' => $code,
  349. 'state' => $state
  350. )
  351. )),
  352. 'bind' => 'netmount'
  353. ];
  354. }
  355. if (!$itpCare) {
  356. return array('exit' => 'callback', 'out' => $out);
  357. } else {
  358. return array('exit' => true, 'body' => $out['json']);
  359. }
  360. }
  361. $path = $options['path'];
  362. $folders = [];
  363. $listFolderContents = $dropbox->listFolder($path);
  364. $items = $listFolderContents->getItems();
  365. foreach ($items as $item) {
  366. $data = $item->getData();
  367. if ($data['.tag'] === 'folder') {
  368. $folders[$data['path_lower']] = $data['name'];
  369. }
  370. }
  371. natcasesort($folders);
  372. if ($options['pass'] === 'folders') {
  373. return ['exit' => true, 'folders' => $folders];
  374. }
  375. $folders = ['/' => '/'] + $folders;
  376. $folders = json_encode($folders);
  377. $json = '{"protocol": "dropbox2", "mode": "done", "folders": ' . $folders . '}';
  378. $options['pass'] = 'return';
  379. $html = 'Dropbox.com';
  380. $html .= '<script>
  381. $("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
  382. </script>';
  383. $this->session->set('Dropbox2AuthParams', $options);
  384. return ['exit' => true, 'body' => $html];
  385. }
  386. }
  387. } catch (DropboxClientException $e) {
  388. $this->session->remove('Dropbox2AuthParams')->remove('Dropbox2Tokens');
  389. if (empty($options['pass'])) {
  390. return ['exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage()];
  391. } else {
  392. return ['exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]];
  393. }
  394. }
  395. if (!$aToken) {
  396. return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE];
  397. }
  398. if ($options['path'] === 'root') {
  399. $options['path'] = '/';
  400. }
  401. try {
  402. if ($options['path'] !== '/') {
  403. $file = $dropbox->getMetadata($options['path']);
  404. $name = $file->getName();
  405. } else {
  406. $name = 'root';
  407. }
  408. $options['alias'] = sprintf($this->options['aliasFormat'], $name);
  409. } catch (DropboxClientException $e) {
  410. return ['exit' => true, 'error' => $e->getMessage()];
  411. }
  412. foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) {
  413. unset($options[$key]);
  414. }
  415. return $options;
  416. }
  417. /**
  418. * process of on netunmount
  419. * Drop `Dropbox` & rm thumbs.
  420. *
  421. * @param array $options
  422. *
  423. * @return bool
  424. */
  425. public function netunmount($netVolumes, $key)
  426. {
  427. if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->driverId . '_' . $this->options['tokens']['uid'] . '*.png')) {
  428. foreach ($tmbs as $file) {
  429. unlink($file);
  430. }
  431. }
  432. return true;
  433. }
  434. /*********************************************************************/
  435. /* INIT AND CONFIGURE */
  436. /*********************************************************************/
  437. /**
  438. * Prepare Dropbox connection
  439. * Connect to remote server and check if credentials are correct, if so, store the connection id in $this->service.
  440. *
  441. * @return bool
  442. * @author Naoki Sawada
  443. **/
  444. protected function init()
  445. {
  446. if (empty($this->options['app_key'])) {
  447. if (defined('ELFINDER_DROPBOX_APPKEY') && ELFINDER_DROPBOX_APPKEY) {
  448. $this->options['app_key'] = ELFINDER_DROPBOX_APPKEY;
  449. } else {
  450. return $this->setError('Required option "app_key" is undefined.');
  451. }
  452. }
  453. if (empty($this->options['app_secret'])) {
  454. if (defined('ELFINDER_DROPBOX_APPSECRET') && ELFINDER_DROPBOX_APPSECRET) {
  455. $this->options['app_secret'] = ELFINDER_DROPBOX_APPSECRET;
  456. } else {
  457. return $this->setError('Required option "app_secret" is undefined.');
  458. }
  459. }
  460. if (isset($this->options['tokens']) && is_array($this->options['tokens']) && !empty($this->options['tokens']['access_token'])) {
  461. $this->options['access_token'] = $this->options['tokens']['access_token'];
  462. }
  463. if (!$this->options['access_token']) {
  464. return $this->setError('Required option "access_token" or "refresh_token" is undefined.');
  465. }
  466. try {
  467. // make net mount key for network mount
  468. $aToken = $this->options['access_token'];
  469. $this->netMountKey = md5($aToken . '-' . $this->options['path']);
  470. $errors = [];
  471. if ($this->needOnline && !$this->service) {
  472. $app = new DropboxApp($this->options['app_key'], $this->options['app_secret'], $aToken);
  473. $this->service = new Dropbox($app);
  474. // to check access_token
  475. $this->service->getCurrentAccount();
  476. }
  477. } catch (DropboxClientException $e) {
  478. $errors[] = 'Dropbox error: ' . $e->getMessage();
  479. } catch (Exception $e) {
  480. $errors[] = $e->getMessage();
  481. }
  482. if ($this->needOnline && !$this->service) {
  483. $errors[] = 'Dropbox Service could not be loaded.';
  484. }
  485. if ($errors) {
  486. return $this->setError($errors);
  487. }
  488. // normalize root path
  489. $this->options['path'] = strtolower($this->options['path']);
  490. if ($this->options['path'] == 'root') {
  491. $this->options['path'] = '/';
  492. }
  493. $this->root = $this->options['path'] = $this->_normpath($this->options['path']);
  494. if (empty($this->options['alias'])) {
  495. $this->options['alias'] = sprintf($this->options['aliasFormat'], ($this->options['path'] === '/') ? 'Root' : $this->_basename($this->options['path']));
  496. if (!empty($this->options['netkey'])) {
  497. elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
  498. }
  499. }
  500. $this->rootName = $this->options['alias'];
  501. if (!empty($this->options['tmpPath'])) {
  502. if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
  503. $this->tmp = $this->options['tmpPath'];
  504. }
  505. }
  506. if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
  507. $this->tmp = $tmp;
  508. }
  509. // This driver dose not support `syncChkAsTs`
  510. $this->options['syncChkAsTs'] = false;
  511. // 'lsPlSleep' minmum 10 sec
  512. $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
  513. // enable command archive
  514. $this->options['useRemoteArchive'] = true;
  515. return true;
  516. }
  517. /**
  518. * Configure after successfull mount.
  519. *
  520. * @author Naoki Sawada
  521. * @throws elFinderAbortException
  522. */
  523. protected function configure()
  524. {
  525. parent::configure();
  526. // fallback of $this->tmp
  527. if (!$this->tmp && $this->tmbPathWritable) {
  528. $this->tmp = $this->tmbPath;
  529. }
  530. if ($this->isMyReload()) {
  531. //$this->_db_getDirectoryData(false);
  532. }
  533. }
  534. /*********************************************************************/
  535. /* FS API */
  536. /*********************************************************************/
  537. /**
  538. * Close opened connection.
  539. **/
  540. public function umount()
  541. {
  542. }
  543. /**
  544. * Cache dir contents.
  545. *
  546. * @param string $path dir path
  547. *
  548. * @return
  549. * @author Naoki Sawada
  550. */
  551. protected function cacheDir($path)
  552. {
  553. $this->dirsCache[$path] = [];
  554. $hasDir = false;
  555. $res = $this->service->listFolder($path, $this->FETCH_OPTIONS);
  556. if ($res) {
  557. $items = $res->getItems()->all();
  558. foreach ($items as $raw) {
  559. if ($stat = $this->_db_parseRaw($raw)) {
  560. $mountPath = $this->_joinPath($path, $stat['name']);
  561. $stat = $this->updateCache($mountPath, $stat);
  562. if (empty($stat['hidden']) && $path !== $mountPath) {
  563. if (!$hasDir && $stat['mime'] === 'directory') {
  564. $hasDir = true;
  565. }
  566. $this->dirsCache[$path][] = $mountPath;
  567. }
  568. }
  569. }
  570. }
  571. if (isset($this->sessionCache['subdirs'])) {
  572. $this->sessionCache['subdirs'][$path] = $hasDir;
  573. }
  574. return $this->dirsCache[$path];
  575. }
  576. /**
  577. * Recursive files search.
  578. *
  579. * @param string $path dir path
  580. * @param string $q search string
  581. * @param array $mimes
  582. *
  583. * @return array
  584. * @throws elFinderAbortException
  585. * @author Naoki Sawada
  586. */
  587. protected function doSearch($path, $q, $mimes)
  588. {
  589. if (!empty($this->doSearchCurrentQuery['matchMethod']) || $mimes) {
  590. // has custom match method or mimes, use elFinderVolumeDriver::doSearch()
  591. return parent::doSearch($path, $q, $mimes);
  592. }
  593. $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
  594. $searchRes = $this->service->search($path, $q, ['start' => 0, 'max_results' => 1000]);
  595. $items = $searchRes->getItems();
  596. $more = $searchRes->hasMoreItems();
  597. while ($more) {
  598. if ($timeout && $timeout < time()) {
  599. $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->_path($path));
  600. break;
  601. }
  602. $searchRes = $this->service->search($path, $q, ['start' => $searchRes->getCursor(), 'max_results' => 1000]);
  603. $more = $searchRes->hasMoreItems();
  604. $items = $items->merge($searchRes->getItems());
  605. }
  606. $result = [];
  607. foreach ($items as $raw) {
  608. if ($stat = $this->_db_parseRaw($raw->getMetadata())) {
  609. $stat = $this->updateCache($stat['path'], $stat);
  610. if (empty($stat['hidden'])) {
  611. $result[] = $stat;
  612. }
  613. }
  614. }
  615. return $result;
  616. }
  617. /**
  618. * Copy file/recursive copy dir only in current volume.
  619. * Return new file path or false.
  620. *
  621. * @param string $src source path
  622. * @param string $dst destination dir path
  623. * @param string $name new file name (optionaly)
  624. *
  625. * @return string|false
  626. * @throws elFinderAbortException
  627. * @author Naoki Sawada
  628. */
  629. protected function copy($src, $dst, $name)
  630. {
  631. $srcStat = $this->stat($src);
  632. $target = $this->_joinPath($dst, $name);
  633. $tgtStat = $this->stat($target);
  634. if ($tgtStat) {
  635. if ($srcStat['mime'] === 'directory') {
  636. return parent::copy($src, $dst, $name);
  637. } else {
  638. $this->_unlink($target);
  639. }
  640. }
  641. $this->clearcache();
  642. if ($res = $this->_copy($src, $dst, $name)) {
  643. $this->added[] = $this->stat($target);
  644. $res = $target;
  645. }
  646. return $res;
  647. }
  648. /**
  649. * Remove file/ recursive remove dir.
  650. *
  651. * @param string $path file path
  652. * @param bool $force try to remove even if file locked
  653. * @param bool $recursive
  654. *
  655. * @return bool
  656. * @throws elFinderAbortException
  657. * @author Naoki Sawada
  658. */
  659. protected function remove($path, $force = false, $recursive = false)
  660. {
  661. $stat = $this->stat($path);
  662. $stat['realpath'] = $path;
  663. $this->rmTmb($stat);
  664. $this->clearcache();
  665. if (empty($stat)) {
  666. return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
  667. }
  668. if (!$force && !empty($stat['locked'])) {
  669. return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
  670. }
  671. if ($stat['mime'] == 'directory') {
  672. if (!$recursive && !$this->_rmdir($path)) {
  673. return $this->setError(elFinder::ERROR_RM, $this->_path($path));
  674. }
  675. } else {
  676. if (!$recursive && !$this->_unlink($path)) {
  677. return $this->setError(elFinder::ERROR_RM, $this->_path($path));
  678. }
  679. }
  680. $this->removed[] = $stat;
  681. return true;
  682. }
  683. /**
  684. * Create thumnbnail and return it's URL on success.
  685. *
  686. * @param string $path file path
  687. * @param $stat
  688. *
  689. * @return string|false
  690. * @throws ImagickException
  691. * @throws elFinderAbortException
  692. * @author Naoki Sawada
  693. */
  694. protected function createTmb($path, $stat)
  695. {
  696. if (!$stat || !$this->canCreateTmb($path, $stat)) {
  697. return false;
  698. }
  699. $name = $this->tmbname($stat);
  700. $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name;
  701. // copy image into tmbPath so some drivers does not store files on local fs
  702. if (!$data = $this->_db_getThumbnail($path)) {
  703. return false;
  704. }
  705. if (!file_put_contents($tmb, $data)) {
  706. return false;
  707. }
  708. $tmbSize = $this->tmbSize;
  709. if (($s = getimagesize($tmb)) == false) {
  710. return false;
  711. }
  712. $result = true;
  713. /* If image smaller or equal thumbnail size - just fitting to thumbnail square */
  714. if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
  715. $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
  716. } else {
  717. if ($this->options['tmbCrop']) {
  718. /* Resize and crop if image bigger than thumbnail */
  719. if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
  720. $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
  721. }
  722. if ($result && ($s = getimagesize($tmb)) != false) {
  723. $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
  724. $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
  725. $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
  726. }
  727. } else {
  728. $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
  729. }
  730. if ($result) {
  731. $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
  732. }
  733. }
  734. if (!$result) {
  735. unlink($tmb);
  736. return false;
  737. }
  738. return $name;
  739. }
  740. /**
  741. * Return thumbnail file name for required file.
  742. *
  743. * @param array $stat file stat
  744. *
  745. * @return string
  746. * @author Naoki Sawada
  747. **/
  748. protected function tmbname($stat)
  749. {
  750. $name = $this->driverId . '_';
  751. if (isset($this->options['tokens']) && is_array($this->options['tokens'])) {
  752. $name .= $this->options['tokens']['uid'];
  753. }
  754. return $name . md5($stat['iid']) . $stat['ts'] . '.png';
  755. }
  756. /**
  757. * Return content URL (for netmout volume driver)
  758. * If file.url == 1 requests from JavaScript client with XHR.
  759. *
  760. * @param string $hash file hash
  761. * @param array $options options array
  762. *
  763. * @return bool|string
  764. * @author Naoki Sawada
  765. */
  766. public function getContentUrl($hash, $options = [])
  767. {
  768. if (!empty($options['onetime']) && $this->options['onetimeUrl']) {
  769. return parent::getContentUrl($hash, $options);
  770. }
  771. if (!empty($options['temporary'])) {
  772. // try make temporary file
  773. $url = parent::getContentUrl($hash, $options);
  774. if ($url) {
  775. return $url;
  776. }
  777. }
  778. $file = $this->file($hash);
  779. if (($file = $this->file($hash)) !== false && (!$file['url'] || $file['url'] == 1)) {
  780. $path = $this->decode($hash);
  781. $url = '';
  782. try {
  783. $res = $this->service->postToAPI('/sharing/list_shared_links', ['path' => $path, 'direct_only' => true])->getDecodedBody();
  784. if ($res && !empty($res['links'])) {
  785. foreach ($res['links'] as $link) {
  786. if (isset($link['link_permissions'])
  787. && isset($link['link_permissions']['requested_visibility'])
  788. && $link['link_permissions']['requested_visibility']['.tag'] === $this->options['publishPermission']['requested_visibility']) {
  789. $url = $link['url'];
  790. break;
  791. }
  792. }
  793. }
  794. if (!$url) {
  795. $res = $this->service->postToAPI('/sharing/create_shared_link_with_settings', ['path' => $path, 'settings' => $this->options['publishPermission']])->getDecodedBody();
  796. if (isset($res['url'])) {
  797. $url = $res['url'];
  798. }
  799. }
  800. if ($url) {
  801. $url = str_replace('www.dropbox.com', 'dl.dropboxusercontent.com', $url);
  802. $url = str_replace('?dl=0', '', $url);
  803. return $url;
  804. }
  805. } catch (DropboxClientException $e) {
  806. return $this->setError('Dropbox error: ' . $e->getMessage());
  807. }
  808. }
  809. return false;
  810. }
  811. /**
  812. * Return debug info for client.
  813. *
  814. * @return array
  815. **/
  816. public function debug()
  817. {
  818. $res = parent::debug();
  819. if (!empty($this->options['netkey']) && isset($this->options['tokens']) && !empty($this->options['tokens']['uid'])) {
  820. $res['Dropbox uid'] = $this->options['tokens']['uid'];
  821. $res['access_token'] = $this->options['tokens']['access_token'];
  822. }
  823. return $res;
  824. }
  825. /*********************** paths/urls *************************/
  826. /**
  827. * Return parent directory path.
  828. *
  829. * @param string $path file path
  830. *
  831. * @return string
  832. * @author Naoki Sawada
  833. **/
  834. protected function _dirname($path)
  835. {
  836. list($dirname) = $this->_db_splitPath($path);
  837. return $dirname;
  838. }
  839. /**
  840. * Return file name.
  841. *
  842. * @param string $path file path
  843. *
  844. * @return string
  845. * @author Naoki Sawada
  846. **/
  847. protected function _basename($path)
  848. {
  849. list(, $basename) = $this->_db_splitPath($path);
  850. return $basename;
  851. }
  852. /**
  853. * Join dir name and file name and retur full path.
  854. *
  855. * @param string $dir
  856. * @param string $name
  857. *
  858. * @return string
  859. * @author Dmitry (dio) Levashov
  860. **/
  861. protected function _joinPath($dir, $name)
  862. {
  863. return rtrim($dir, '/') . '/' . strtolower($name);
  864. }
  865. /**
  866. * Return normalized path, this works the same as os.path.normpath() in Python.
  867. *
  868. * @param string $path path
  869. *
  870. * @return string
  871. * @author Naoki Sawada
  872. **/
  873. protected function _normpath($path)
  874. {
  875. return '/' . ltrim($path, '/');
  876. }
  877. /**
  878. * Return file path related to root dir.
  879. *
  880. * @param string $path file path
  881. *
  882. * @return string
  883. * @author Dmitry (dio) Levashov
  884. **/
  885. protected function _relpath($path)
  886. {
  887. if ($path === $this->root) {
  888. return '';
  889. } else {
  890. return ltrim(substr($path, strlen($this->root)), '/');
  891. }
  892. }
  893. /**
  894. * Convert path related to root dir into real path.
  895. *
  896. * @param string $path file path
  897. *
  898. * @return string
  899. * @author Naoki Sawada
  900. **/
  901. protected function _abspath($path)
  902. {
  903. if ($path === '/') {
  904. return $this->root;
  905. } else {
  906. return $this->_joinPath($this->root, $path);
  907. }
  908. }
  909. /**
  910. * Return fake path started from root dir.
  911. *
  912. * @param string $path file path
  913. *
  914. * @return string
  915. * @author Naoki Sawada
  916. **/
  917. protected function _path($path)
  918. {
  919. $path = $this->_normpath(substr($path, strlen($this->root)));
  920. return $path;
  921. }
  922. /**
  923. * Return true if $path is children of $parent.
  924. *
  925. * @param string $path path to check
  926. * @param string $parent parent path
  927. *
  928. * @return bool
  929. * @author Naoki Sawada
  930. **/
  931. protected function _inpath($path, $parent)
  932. {
  933. return $path == $parent || strpos($path, $parent . '/') === 0;
  934. }
  935. /***************** file stat ********************/
  936. /**
  937. * Return stat for given path.
  938. * Stat contains following fields:
  939. * - (int) size file size in b. required
  940. * - (int) ts file modification time in unix time. required
  941. * - (string) mime mimetype. required for folders, others - optionally
  942. * - (bool) read read permissions. required
  943. * - (bool) write write permissions. required
  944. * - (bool) locked is object locked. optionally
  945. * - (bool) hidden is object hidden. optionally
  946. * - (string) alias for symlinks - link target path relative to root path. optionally
  947. * - (string) target for symlinks - link target path. optionally.
  948. * If file does not exists - returns empty array or false.
  949. *
  950. * @param string $path file path
  951. *
  952. * @return array|false
  953. * @author Dmitry (dio) Levashov
  954. **/
  955. protected function _stat($path)
  956. {
  957. if ($raw = $this->_db_getFile($path)) {
  958. return $this->_db_parseRaw($raw);
  959. }
  960. return false;
  961. }
  962. /**
  963. * Return true if path is dir and has at least one childs directory.
  964. *
  965. * @param string $path dir path
  966. *
  967. * @return bool
  968. * @author Naoki Sawada
  969. **/
  970. protected function _subdirs($path)
  971. {
  972. $hasdir = false;
  973. try {
  974. $res = $this->service->listFolder($path);
  975. if ($res) {
  976. $items = $res->getItems();
  977. foreach ($items as $raw) {
  978. if ($raw instanceof FolderMetadata) {
  979. $hasdir = true;
  980. break;
  981. }
  982. }
  983. }
  984. } catch (DropboxClientException $e) {
  985. $this->setError('Dropbox error: ' . $e->getMessage());
  986. }
  987. return $hasdir;
  988. }
  989. /**
  990. * Return object width and height
  991. * Ususaly used for images, but can be realize for video etc...
  992. *
  993. * @param string $path file path
  994. * @param string $mime file mime type
  995. *
  996. * @return string
  997. * @throws ImagickException
  998. * @throws elFinderAbortException
  999. * @author Naoki Sawada
  1000. */
  1001. protected function _dimensions($path, $mime)
  1002. {
  1003. if (strpos($mime, 'image') !== 0) {
  1004. return '';
  1005. }
  1006. $ret = '';
  1007. if ($data = $this->_getContents($path)) {
  1008. $tmp = $this->getTempFile();
  1009. file_put_contents($tmp, $data);
  1010. $size = getimagesize($tmp);
  1011. if ($size) {
  1012. $ret = array('dim' => $size[0] . 'x' . $size[1]);
  1013. $srcfp = fopen($tmp, 'rb');
  1014. $target = isset(elFinder::$currentArgs['target'])? elFinder::$currentArgs['target'] : '';
  1015. if ($subImgLink = $this->getSubstituteImgLink($target, $size, $srcfp)) {
  1016. $ret['url'] = $subImgLink;
  1017. }
  1018. }
  1019. }
  1020. return $ret;
  1021. }
  1022. /******************** file/dir content *********************/
  1023. /**
  1024. * Return files list in directory.
  1025. *
  1026. * @param string $path dir path
  1027. *
  1028. * @return array
  1029. * @author Naoki Sawada
  1030. **/
  1031. protected function _scandir($path)
  1032. {
  1033. return isset($this->dirsCache[$path])
  1034. ? $this->dirsCache[$path]
  1035. : $this->cacheDir($path);
  1036. }
  1037. /**
  1038. * Open file and return file pointer.
  1039. *
  1040. * @param string $path file path
  1041. * @param bool $write open file for writing
  1042. *
  1043. * @return resource|false
  1044. * @author Naoki Sawada
  1045. **/
  1046. protected function _fopen($path, $mode = 'rb')
  1047. {
  1048. if ($mode === 'rb' || $mode === 'r') {
  1049. if ($link = $this->service->getTemporaryLink($path)) {
  1050. $access_token = $this->service->getAccessToken();
  1051. if ($access_token) {
  1052. $data = array(
  1053. 'target' => $link->getLink(),
  1054. 'headers' => array('Authorization: Bearer ' . $access_token),
  1055. );
  1056. // to support range request
  1057. if (func_num_args() > 2) {
  1058. $opts = func_get_arg(2);
  1059. } else {
  1060. $opts = array();
  1061. }
  1062. if (!empty($opts['httpheaders'])) {
  1063. $data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
  1064. }
  1065. return elFinder::getStreamByUrl($data);
  1066. }
  1067. }
  1068. }
  1069. return false;
  1070. }
  1071. /**
  1072. * Close opened file.
  1073. *
  1074. * @param resource $fp file pointer
  1075. *
  1076. * @return bool
  1077. * @author Naoki Sawada
  1078. **/
  1079. protected function _fclose($fp, $path = '')
  1080. {
  1081. is_resource($fp) && fclose($fp);
  1082. }
  1083. /******************** file/dir manipulations *************************/
  1084. /**
  1085. * Create dir and return created dir path or false on failed.
  1086. *
  1087. * @param string $path parent dir path
  1088. * @param string $name new directory name
  1089. *
  1090. * @return string|bool
  1091. * @author Naoki Sawada
  1092. **/
  1093. protected function _mkdir($path, $name)
  1094. {
  1095. try {
  1096. return $this->service->createFolder($this->_db_joinName($path, $name))->getPathLower();
  1097. } catch (DropboxClientException $e) {
  1098. return $this->setError('Dropbox error: ' . $e->getMessage());
  1099. }
  1100. }
  1101. /**
  1102. * Create file and return it's path or false on failed.
  1103. *
  1104. * @param string $path parent dir path
  1105. * @param string $name new file name
  1106. *
  1107. * @return string|bool
  1108. * @author Naoki Sawada
  1109. **/
  1110. protected function _mkfile($path, $name)
  1111. {
  1112. return $this->_save($this->tmpfile(), $path, $name, []);
  1113. }
  1114. /**
  1115. * Create symlink. FTP driver does not support symlinks.
  1116. *
  1117. * @param string $target link target
  1118. * @param string $path symlink path
  1119. *
  1120. * @return bool
  1121. * @author Naoki Sawada
  1122. **/
  1123. protected function _symlink($target, $path, $name)
  1124. {
  1125. return false;
  1126. }
  1127. /**
  1128. * Copy file into another file.
  1129. *
  1130. * @param string $source source file path
  1131. * @param string $targetDir target directory path
  1132. * @param string $name new file name
  1133. *
  1134. * @return bool
  1135. * @author Naoki Sawada
  1136. **/
  1137. protected function _copy($source, $targetDir, $name)
  1138. {
  1139. try {
  1140. $this->service->copy($source, $this->_db_joinName($targetDir, $name))->getPathLower();
  1141. } catch (DropboxClientException $e) {
  1142. return $this->setError('Dropbox error: ' . $e->getMessage());
  1143. }
  1144. return true;
  1145. }
  1146. /**
  1147. * Move file into another parent dir.
  1148. * Return new file path or false.
  1149. *
  1150. * @param string $source source file path
  1151. * @param string $target target dir path
  1152. * @param string $name file name
  1153. *
  1154. * @return string|bool
  1155. * @author Naoki Sawada
  1156. **/
  1157. protected function _move($source, $targetDir, $name)
  1158. {
  1159. try {
  1160. return $this->service->move($source, $this->_db_joinName($targetDir, $name))->getPathLower();
  1161. } catch (DropboxClientException $e) {
  1162. return $this->setError('Dropbox error: ' . $e->getMessage());
  1163. }
  1164. }
  1165. /**
  1166. * Remove file.
  1167. *
  1168. * @param string $path file path
  1169. *
  1170. * @return bool
  1171. * @author Naoki Sawada
  1172. **/
  1173. protected function _unlink($path)
  1174. {
  1175. try {
  1176. $this->service->delete($path);
  1177. return true;
  1178. } catch (DropboxClientException $e) {
  1179. return $this->setError('Dropbox error: ' . $e->getMessage());
  1180. }
  1181. return true;
  1182. }
  1183. /**
  1184. * Remove dir.
  1185. *
  1186. * @param string $path dir path
  1187. *
  1188. * @return bool
  1189. * @author Naoki Sawada
  1190. **/
  1191. protected function _rmdir($path)
  1192. {
  1193. return $this->_unlink($path);
  1194. }
  1195. /**
  1196. * Create new file and write into it from file pointer.
  1197. * Return new file path or false on error.
  1198. *
  1199. * @param resource $fp file pointer
  1200. * @param string $dir target dir path
  1201. * @param string $name file name
  1202. * @param array $stat file stat (required by some virtual fs)
  1203. *
  1204. * @return bool|string
  1205. * @author Naoki Sawada
  1206. **/
  1207. protected function _save($fp, $path, $name, $stat)
  1208. {
  1209. try {
  1210. $info = stream_get_meta_data($fp);
  1211. if (empty($info['uri']) || preg_match('#^[a-z0-9.-]+://#', $info['uri'])) {
  1212. if ($filepath = $this->getTempFile()) {
  1213. $_fp = fopen($filepath, 'wb');
  1214. stream_copy_to_stream($fp, $_fp);
  1215. fclose($_fp);
  1216. }
  1217. } else {
  1218. $filepath = $info['uri'];
  1219. }
  1220. $dropboxFile = new DropboxFile($filepath);
  1221. if ($name === '') {
  1222. $fullpath = $path;
  1223. } else {
  1224. $fullpath = $this->_db_joinName($path, $name);
  1225. }
  1226. return $this->service->upload($dropboxFile, $fullpath, ['mode' => 'overwrite'])->getPathLower();
  1227. } catch (DropboxClientException $e) {
  1228. return $this->setError('Dropbox error: ' . $e->getMessage());
  1229. }
  1230. }
  1231. /**
  1232. * Get file contents.
  1233. *
  1234. * @param string $path file path
  1235. *
  1236. * @return string|false
  1237. * @author Naoki Sawada
  1238. **/
  1239. protected function _getContents($path)
  1240. {
  1241. $contents = '';
  1242. try {
  1243. $file = $this->service->download($path);
  1244. $contents = $file->getContents();
  1245. } catch (Exception $e) {
  1246. return $this->setError('Dropbox error: ' . $e->getMessage());
  1247. }
  1248. return $contents;
  1249. }
  1250. /**
  1251. * Write a string to a file.
  1252. *
  1253. * @param string $path file path
  1254. * @param string $content new file content
  1255. *
  1256. * @return bool
  1257. * @author Naoki Sawada
  1258. **/
  1259. protected function _filePutContents($path, $content)
  1260. {
  1261. $res = false;
  1262. if ($local = $this->getTempFile($path)) {
  1263. if (file_put_contents($local, $content, LOCK_EX) !== false
  1264. && ($fp = fopen($local, 'rb'))) {
  1265. clearstatcache();
  1266. $name = '';
  1267. $stat = $this->stat($path);
  1268. if ($stat) {
  1269. // keep real name
  1270. $path = $this->_dirname($path);
  1271. $name = $stat['name'];
  1272. }
  1273. $res = $this->_save($fp, $path, $name, []);
  1274. fclose($fp);
  1275. }
  1276. file_exists($local) && unlink($local);
  1277. }
  1278. return $res;
  1279. }
  1280. /**
  1281. * Detect available archivers.
  1282. **/
  1283. protected function _checkArchivers()
  1284. {
  1285. // die('Not yet implemented. (_checkArchivers)');
  1286. return [];
  1287. }
  1288. /**
  1289. * chmod implementation.
  1290. *
  1291. * @return bool
  1292. **/
  1293. protected function _chmod($path, $mode)
  1294. {
  1295. return false;
  1296. }
  1297. /**
  1298. * Unpack archive.
  1299. *
  1300. * @param string $path archive path
  1301. * @param array $arc archiver command and arguments (same as in $this->archivers)
  1302. *
  1303. * @return true
  1304. * @author Dmitry (dio) Levashov
  1305. * @author Alexey Sukhotin
  1306. **/
  1307. protected function _unpack($path, $arc)
  1308. {
  1309. die('Not yet implemented. (_unpack)');
  1310. //return false;
  1311. }
  1312. /**
  1313. * Recursive symlinks search.
  1314. *
  1315. * @param string $path file/dir path
  1316. *
  1317. * @return bool
  1318. * @author Dmitry (dio) Levashov
  1319. **/
  1320. protected function _findSymlinks($path)
  1321. {
  1322. die('Not yet implemented. (_findSymlinks)');
  1323. }
  1324. /**
  1325. * Extract files from archive.
  1326. *
  1327. * @param string $path archive path
  1328. * @param array $arc archiver command and arguments (same as in $this->archivers)
  1329. *
  1330. * @return true
  1331. * @author Dmitry (dio) Levashov,
  1332. * @author Alexey Sukhotin
  1333. **/
  1334. protected function _extract($path, $arc)
  1335. {
  1336. die('Not yet implemented. (_extract)');
  1337. }
  1338. /**
  1339. * Create archive and return its path.
  1340. *
  1341. * @param string $dir target dir
  1342. * @param array $files files names list
  1343. * @param string $name archive name
  1344. * @param array $arc archiver options
  1345. *
  1346. * @return string|bool
  1347. * @author Dmitry (dio) Levashov,
  1348. * @author Alexey Sukhotin
  1349. **/
  1350. protected function _archive($dir, $files, $name, $arc)
  1351. {
  1352. die('Not yet implemented. (_archive)');
  1353. }
  1354. } // END class