PageRenderTime 91ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/man/themes/pertho_admin_v1.3/lib/elfinder/php/elFinderVolumeDriver.class.php

https://bitbucket.org/speedealing/speedealing
PHP | 2813 lines | 1349 code | 366 blank | 1098 comment | 404 complexity | 63e764a636fdbff2bbe32b1486573fbf MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /**
  3. * Base class for elFinder volume.
  4. * Provide 2 layers:
  5. * 1. Public API (commands)
  6. * 2. abstract fs API
  7. *
  8. * All abstract methods begin with "_"
  9. *
  10. * @author Dmitry (dio) Levashov
  11. * @author Troex Nevelin
  12. * @author Alexey Sukhotin
  13. **/
  14. abstract class elFinderVolumeDriver {
  15. /**
  16. * Driver id
  17. * Must be started from letter and contains [a-z0-9]
  18. * Used as part of volume id
  19. *
  20. * @var string
  21. **/
  22. protected $driverId = 'a';
  23. /**
  24. * Volume id - used as prefix for files hashes
  25. *
  26. * @var string
  27. **/
  28. protected $id = '';
  29. /**
  30. * Flag - volume "mounted" and available
  31. *
  32. * @var bool
  33. **/
  34. protected $mounted = false;
  35. /**
  36. * Root directory path
  37. *
  38. * @var string
  39. **/
  40. protected $root = '';
  41. /**
  42. * Root basename | alias
  43. *
  44. * @var string
  45. **/
  46. protected $rootName = '';
  47. /**
  48. * Default directory to open
  49. *
  50. * @var string
  51. **/
  52. protected $startPath = '';
  53. /**
  54. * Base URL
  55. *
  56. * @var string
  57. **/
  58. protected $URL = '';
  59. /**
  60. * Thumbnails dir path
  61. *
  62. * @var string
  63. **/
  64. protected $tmbPath = '';
  65. /**
  66. * Is thumbnails dir writable
  67. *
  68. * @var bool
  69. **/
  70. protected $tmbPathWritable = false;
  71. /**
  72. * Thumbnails base URL
  73. *
  74. * @var string
  75. **/
  76. protected $tmbURL = '';
  77. /**
  78. * undocumented class variable
  79. *
  80. * @var string
  81. **/
  82. protected $tmbSize = 48;
  83. /**
  84. * Image manipulation lib name
  85. * auto|imagick|mogtify|gd
  86. *
  87. * @var string
  88. **/
  89. protected $imgLib = 'auto';
  90. /**
  91. * Library to crypt files name
  92. *
  93. * @var string
  94. **/
  95. protected $cryptLib = '';
  96. /**
  97. * undocumented class variable
  98. *
  99. * @var string
  100. **/
  101. protected $archivers = array(
  102. 'create' => array(),
  103. 'extract' => array()
  104. );
  105. /**
  106. * How many subdirs levels return for tree
  107. *
  108. * @var int
  109. **/
  110. protected $treeDeep = 1;
  111. /**
  112. * Errors from last failed action
  113. *
  114. * @var array
  115. **/
  116. protected $error = array();
  117. /**
  118. * Today 24:00 timestamp
  119. *
  120. * @var int
  121. **/
  122. protected $today = 0;
  123. /**
  124. * Yesterday 24:00 timestamp
  125. *
  126. * @var int
  127. **/
  128. protected $yesterday = 0;
  129. /**
  130. * Object configuration
  131. *
  132. * @var array
  133. **/
  134. protected $options = array(
  135. 'id' => '',
  136. // root directory path
  137. 'path' => '',
  138. // open this path on initial request instead of root path
  139. 'startPath' => '',
  140. // how many subdirs levels return per request
  141. 'treeDeep' => 1,
  142. // root url, not set to disable sending URL to client (replacement for old "fileURL" option)
  143. 'URL' => '',
  144. // directory separator. required by client to show paths correctly
  145. 'separator' => DIRECTORY_SEPARATOR,
  146. // library to crypt/uncrypt files names (not implemented)
  147. 'cryptLib' => '',
  148. // how to detect files mimetypes. (auto/internal/finfo/mime_content_type)
  149. 'mimeDetect' => 'auto',
  150. // mime.types file path (for mimeDetect==internal)
  151. 'mimefile' => '',
  152. // directory for thumbnails
  153. 'tmbPath' => '.tmb',
  154. // mode to create thumbnails dir
  155. 'tmbPathMode' => 0777,
  156. // thumbnails dir URL. Set it if store thumbnails outside root directory
  157. 'tmbURL' => '',
  158. // thumbnails size (px)
  159. 'tmbSize' => 48,
  160. // thumbnails crop (true - crop, false - scale image to fit thumbnail size)
  161. 'tmbCrop' => true,
  162. // thumbnails background color (hex #rrggbb or 'transparent')
  163. 'tmbBgColor' => '#ffffff',
  164. // image manipulations library
  165. 'imgLib' => 'auto',
  166. // how frequiently clean thumbnails dir (0 - never, 100 - every init request)
  167. 'tmbCleanProb' => 0,
  168. // on paste file - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext
  169. 'copyOverwrite' => true,
  170. // if true - join new and old directories content on paste
  171. 'copyJoin' => true,
  172. // on upload - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext
  173. 'uploadOverwrite' => true,
  174. // mimetypes allowed to upload
  175. 'uploadAllow' => array('all'),
  176. // mimetypes not allowed to upload
  177. 'uploadDeny' => array(),
  178. // order to proccess uploadAllow and uploadAllow options
  179. 'uploadOrder' => 'deny,allow',
  180. // maximum upload file size. NOTE - this is size for every uploaded files
  181. 'uploadMaxSize' => 0,
  182. // files dates format
  183. 'dateFormat' => 'j M Y H:i',
  184. // files time format
  185. 'timeFormat' => 'H:i',
  186. // allow to copy from this volume to other ones?
  187. 'copyFrom' => true,
  188. // allow to copy from other volumes to this one?
  189. 'copyTo' => true,
  190. // list of commands disabled on this root
  191. 'disabled' => array(),
  192. // regexp or function name to validate new file name
  193. 'acceptedName' => '/^[^\.]/',
  194. // function/class method to control files permissions
  195. 'accessControl' => null,
  196. // some data required by access control
  197. 'accessControlData' => null,
  198. // default permissions. not set hidden/locked here - take no effect
  199. 'defaults' => array(
  200. 'read' => true,
  201. 'write' => true
  202. ),
  203. // files attributes
  204. 'attributes' => array(),
  205. // Allowed archive's mimetypes to create. Leave empty for all available types.
  206. 'archiveMimes' => array(),
  207. // Manual config for archivers. See example below. Leave empty for auto detect
  208. 'archivers' => array(),
  209. // required to fix bug on macos
  210. 'utf8fix' => false,
  211. // й ё Й Ё Ø Å
  212. 'utf8patterns' => array("\u0438\u0306", "\u0435\u0308", "\u0418\u0306", "\u0415\u0308", "\u00d8A", "\u030a"),
  213. 'utf8replace' => array("\u0439", "\u0451", "\u0419", "\u0401", "\u00d8", "\u00c5")
  214. );
  215. /**
  216. * Defaults permissions
  217. *
  218. * @var array
  219. **/
  220. protected $defaults = array(
  221. 'read' => true,
  222. 'write' => true,
  223. 'locked' => false,
  224. 'hidden' => false
  225. );
  226. /**
  227. * Access control function/class
  228. *
  229. * @var mixed
  230. **/
  231. protected $attributes = array();
  232. /**
  233. * Access control function/class
  234. *
  235. * @var mixed
  236. **/
  237. protected $access = null;
  238. /**
  239. * Mime types allowed to upload
  240. *
  241. * @var array
  242. **/
  243. protected $uploadAllow = array();
  244. /**
  245. * Mime types denied to upload
  246. *
  247. * @var array
  248. **/
  249. protected $uploadDeny = array();
  250. /**
  251. * Order to validate uploadAllow and uploadDeny
  252. *
  253. * @var array
  254. **/
  255. protected $uploadOrder = array();
  256. /**
  257. * Maximum allowed upload file size.
  258. * Set as number or string with unit - "10M", "500K", "1G"
  259. *
  260. * @var int|string
  261. **/
  262. protected $uploadMaxSize = 0;
  263. /**
  264. * Mimetype detect method
  265. *
  266. * @var string
  267. **/
  268. protected $mimeDetect = 'auto';
  269. /**
  270. * Flag - mimetypes from externail file was loaded
  271. *
  272. * @var bool
  273. **/
  274. private static $mimetypesLoaded = false;
  275. /**
  276. * Finfo object for mimeDetect == 'finfo'
  277. *
  278. * @var object
  279. **/
  280. protected $finfo = null;
  281. /**
  282. * undocumented class variable
  283. *
  284. * @var string
  285. **/
  286. protected $diabled = array();
  287. /**
  288. * default extensions/mimetypes for mimeDetect == 'internal'
  289. *
  290. * @var array
  291. **/
  292. protected static $mimetypes = array(
  293. // applications
  294. 'ai' => 'application/postscript',
  295. 'eps' => 'application/postscript',
  296. 'exe' => 'application/x-executable',
  297. 'doc' => 'application/vnd.ms-word',
  298. 'xls' => 'application/vnd.ms-excel',
  299. 'ppt' => 'application/vnd.ms-powerpoint',
  300. 'pps' => 'application/vnd.ms-powerpoint',
  301. 'pdf' => 'application/pdf',
  302. 'xml' => 'application/xml',
  303. 'odt' => 'application/vnd.oasis.opendocument.text',
  304. 'swf' => 'application/x-shockwave-flash',
  305. 'torrent' => 'application/x-bittorrent',
  306. 'jar' => 'application/x-jar',
  307. // archives
  308. 'gz' => 'application/x-gzip',
  309. 'tgz' => 'application/x-gzip',
  310. 'bz' => 'application/x-bzip2',
  311. 'bz2' => 'application/x-bzip2',
  312. 'tbz' => 'application/x-bzip2',
  313. 'zip' => 'application/zip',
  314. 'rar' => 'application/x-rar',
  315. 'tar' => 'application/x-tar',
  316. '7z' => 'application/x-7z-compressed',
  317. // texts
  318. 'txt' => 'text/plain',
  319. 'php' => 'text/x-php',
  320. 'html' => 'text/html',
  321. 'htm' => 'text/html',
  322. 'js' => 'text/javascript',
  323. 'css' => 'text/css',
  324. 'rtf' => 'text/rtf',
  325. 'rtfd' => 'text/rtfd',
  326. 'py' => 'text/x-python',
  327. 'java' => 'text/x-java-source',
  328. 'rb' => 'text/x-ruby',
  329. 'sh' => 'text/x-shellscript',
  330. 'pl' => 'text/x-perl',
  331. 'xml' => 'text/xml',
  332. 'sql' => 'text/x-sql',
  333. 'c' => 'text/x-csrc',
  334. 'h' => 'text/x-chdr',
  335. 'cpp' => 'text/x-c++src',
  336. 'hh' => 'text/x-c++hdr',
  337. 'log' => 'text/plain',
  338. 'csv' => 'text/x-comma-separated-values',
  339. // images
  340. 'bmp' => 'image/x-ms-bmp',
  341. 'jpg' => 'image/jpeg',
  342. 'jpeg' => 'image/jpeg',
  343. 'gif' => 'image/gif',
  344. 'png' => 'image/png',
  345. 'tif' => 'image/tiff',
  346. 'tiff' => 'image/tiff',
  347. 'tga' => 'image/x-targa',
  348. 'psd' => 'image/vnd.adobe.photoshop',
  349. 'ai' => 'image/vnd.adobe.photoshop',
  350. 'xbm' => 'image/xbm',
  351. 'pxm' => 'image/pxm',
  352. //audio
  353. 'mp3' => 'audio/mpeg',
  354. 'mid' => 'audio/midi',
  355. 'ogg' => 'audio/ogg',
  356. 'oga' => 'audio/ogg',
  357. 'm4a' => 'audio/x-m4a',
  358. 'wav' => 'audio/wav',
  359. 'wma' => 'audio/x-ms-wma',
  360. // video
  361. 'avi' => 'video/x-msvideo',
  362. 'dv' => 'video/x-dv',
  363. 'mp4' => 'video/mp4',
  364. 'mpeg' => 'video/mpeg',
  365. 'mpg' => 'video/mpeg',
  366. 'mov' => 'video/quicktime',
  367. 'wm' => 'video/x-ms-wmv',
  368. 'flv' => 'video/x-flv',
  369. 'mkv' => 'video/x-matroska',
  370. 'webm' => 'video/webm',
  371. 'ogv' => 'video/ogg',
  372. 'ogm' => 'video/ogg'
  373. );
  374. /**
  375. * undocumented class variable
  376. *
  377. * @var string
  378. **/
  379. protected $separator = DIRECTORY_SEPARATOR;
  380. /*********************************************************************/
  381. /* INITIALIZATION */
  382. /*********************************************************************/
  383. /**
  384. * Prepare driver before mount volume.
  385. * Return true if volume is ready.
  386. *
  387. * @return bool
  388. * @author Dmitry (dio) Levashov
  389. **/
  390. protected function init() {
  391. return true;
  392. }
  393. /**
  394. * Configure after successfull mount.
  395. * By default set thumbnails path and image manipulation library.
  396. *
  397. * @return void
  398. * @author Dmitry (dio) Levashov
  399. **/
  400. protected function configure() {
  401. // set thumbnails path
  402. $path = $this->options['tmbPath'];
  403. if ($path) {
  404. if (!file_exists($path)) {
  405. if (@mkdir($path)) {
  406. chmod($path, $this->options['tmbPathMode']);
  407. } else {
  408. $path = '';
  409. }
  410. }
  411. if (is_dir($path) && is_readable($path)) {
  412. $this->tmbPath = $path;
  413. $this->tmbPathWritable = is_writable($path);
  414. }
  415. }
  416. // set image manipulation library
  417. $type = preg_match('/^(imagick|gd|auto)$/i', $this->options['imgLib'])
  418. ? strtolower($this->options['imgLib'])
  419. : 'auto';
  420. if (($type == 'imagick' || $type == 'auto') && extension_loaded('imagick')) {
  421. $this->imgLib = 'imagick';
  422. } else {
  423. $this->imgLib = function_exists('gd_info') ? 'gd' : '';
  424. }
  425. // clean thumbnails dir
  426. if ($this->tmbPath) {
  427. srand((double) microtime() * 1000000);
  428. if (rand(1, 200) <= $this->options['tmbCleanProb']) {
  429. $ls = scandir($this->tmbPath);
  430. for ($i=0, $s = count($ls); $i < $s; $i++) {
  431. $pinfo = pathinfo($ls[$i]);
  432. if (strtolower($pinfo['extension']) == 'png') {
  433. @unlink($this->tmbPath.DIRECTORY_SEPARATOR.$ls[$i]);
  434. }
  435. }
  436. }
  437. }
  438. }
  439. /*********************************************************************/
  440. /* PUBLIC API */
  441. /*********************************************************************/
  442. /**
  443. * Return driver id
  444. *
  445. * @return string
  446. * @author Dmitry (dio) Levashov
  447. **/
  448. public function driverId() {
  449. return $this->driverId;
  450. }
  451. /**
  452. * Return volume id
  453. *
  454. * @return string
  455. * @author Dmitry (dio) Levashov
  456. **/
  457. public function id() {
  458. return $this->id;
  459. }
  460. /**
  461. * undocumented function
  462. *
  463. * @return void
  464. * @author Dmitry Levashov
  465. **/
  466. public function name() {
  467. return strtolower(substr(get_class($this), strlen('elfinderdriver')));
  468. }
  469. /**
  470. * Return debug info for client
  471. *
  472. * @return array
  473. * @author Dmitry (dio) Levashov
  474. **/
  475. public function debug() {
  476. return array(
  477. 'mimeDetect' => $this->mimeDetect,
  478. 'imgLib' => $this->imgLib
  479. );
  480. }
  481. /**
  482. * "Mount" volume.
  483. * Return true if volume available for read or write,
  484. * false - otherwise
  485. *
  486. * @return bool
  487. * @author Dmitry (dio) Levashov
  488. * @author Alexey Sukhotin
  489. **/
  490. public function mount(array $opts) {
  491. if (empty($opts['path'])) {
  492. return false;
  493. }
  494. $this->options = array_merge($this->options, $opts);
  495. $this->id = $this->driverId.(!empty($this->options['id']) ? $this->options['id'] : elFinder::$volumesCnt++).'_';
  496. $this->root = $this->_normpath($this->options['path']);
  497. $this->separator = isset($this->options['separator']) ? $this->options['separator'] : DIRECTORY_SEPARATOR;
  498. // default file attribute
  499. $this->defaults = array(
  500. 'read' => isset($this->options['defaults']['read']) ? !!$this->options['defaults']['read'] : true,
  501. 'write' => isset($this->options['defaults']['write']) ? !!$this->options['defaults']['write'] : true,
  502. 'locked' => false,
  503. 'hidden' => false
  504. );
  505. // root attributes
  506. $this->attributes[] = array(
  507. 'pattern' => '~^'.preg_quote(DIRECTORY_SEPARATOR).'$~',
  508. 'locked' => true,
  509. 'hidden' => false
  510. );
  511. // set files attributes
  512. if (!empty($this->options['attributes']) && is_array($this->options['attributes'])) {
  513. foreach ($this->options['attributes'] as $a) {
  514. // attributes must contain pattern and at least one rule
  515. if (!empty($a['pattern']) || count($a) > 1) {
  516. $this->attributes[] = $a;
  517. }
  518. }
  519. }
  520. if (!empty($this->options['accessControl'])) {
  521. if (is_string($this->options['accessControl'])
  522. && function_exists($this->options['accessControl'])) {
  523. $this->access = $this->options['accessControl'];
  524. } elseif (is_array($this->options['accessControl'])
  525. && count($this->options['accessControl']) > 1
  526. && is_object($this->options['accessControl'][0])
  527. && method_exists($this->options['accessControl'][0], $this->options['accessControl'][1])) {
  528. $this->access = array($this->options['accessControl'][0], $this->options['accessControl'][1]);
  529. }
  530. }
  531. // debug($this->attributes);
  532. if (!$this->init()) {
  533. return false;
  534. }
  535. $this->today = mktime(0,0,0, date('m'), date('d'), date('Y'));
  536. $this->yesterday = $this->today-86400;
  537. // check some options is arrays
  538. $this->uploadAllow = isset($this->options['uploadAllow']) && is_array($this->options['uploadAllow'])
  539. ? $this->options['uploadAllow']
  540. : array();
  541. $this->uploadDeny = isset($this->options['uploadDeny']) && is_array($this->options['uploadDeny'])
  542. ? $this->options['uploadDeny']
  543. : array();
  544. $parts = explode(',', isset($this->options['uploadOrder']) ? $this->options['uploadOrder'] : 'deny,allow');
  545. $this->uploadOrder = array(trim($parts[0]), trim($parts[1]));
  546. if (!empty($this->options['uploadMaxSize'])) {
  547. $size = ''.$this->options['uploadMaxSize'];
  548. $unit = strtolower(substr($size, strlen($size) - 1));
  549. $n = 1;
  550. switch ($unit) {
  551. case 'k':
  552. $n = 1024;
  553. break;
  554. case 'm':
  555. $n = 1048576;
  556. break;
  557. case 'g':
  558. $n = 1073741824;
  559. }
  560. $this->uploadMaxSize = intval($size)*$n;
  561. }
  562. $this->disabled = isset($this->options['disabled']) && is_array($this->options['disabled'])
  563. ? $this->options['disabled']
  564. : array();
  565. $this->cryptLib = $this->options['cryptLib'];
  566. $this->mimeDetect = $this->options['mimeDetect'];
  567. // find available mimetype detect method
  568. $type = strtolower($this->options['mimeDetect']);
  569. $type = preg_match('/^(finfo|mime_content_type|internal|auto)$/i', $type) ? $type : 'auto';
  570. $regexp = '/text\/x\-(php|c\+\+)/';
  571. if (($type == 'finfo' || $type == 'auto')
  572. && class_exists('finfo')
  573. && preg_match($regexp, array_shift(explode(';', @finfo_file(finfo_open(FILEINFO_MIME), __FILE__))))) {
  574. $type = 'finfo';
  575. } elseif (($type == 'mime_content_type' || $type == 'auto')
  576. && function_exists('mime_content_type')
  577. && preg_match($regexp, array_shift(explode(';', mime_content_type(__FILE__))))) {
  578. $type = 'mime_content_type';
  579. } else {
  580. $type = 'internal';
  581. }
  582. $this->mimeDetect = $type;
  583. // load mimes from external file for mimeDetect == 'internal'
  584. // based on Alexey Sukhotin idea and patch: http://elrte.org/redmine/issues/163
  585. // file must be in file directory or in parent one
  586. if ($this->mimeDetect == 'internal' && !self::$mimetypesLoaded) {
  587. self::$mimetypesLoaded = true;
  588. $this->mimeDetect = 'internal';
  589. $file = false;
  590. if (!empty($this->options['mimefile']) && file_exists($this->options['mimefile'])) {
  591. $file = $this->options['mimefile'];
  592. } elseif (file_exists(dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types')) {
  593. $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types';
  594. } elseif (file_exists(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types')) {
  595. $file = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types';
  596. }
  597. if ($file && file_exists($file)) {
  598. $mimecf = file($file);
  599. foreach ($mimecf as $line_num => $line) {
  600. if (!preg_match('/^\s*#/', $line)) {
  601. $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
  602. for ($i = 1, $size = count($mime); $i < $size ; $i++) {
  603. if (!isset(self::$mimetypes[$mime[$i]])) {
  604. self::$mimetypes[$mime[$i]] = $mime[0];
  605. } else {
  606. // echo $mime[$i].' '.$mime[0].'<br>';
  607. }
  608. }
  609. }
  610. }
  611. }
  612. }
  613. // debug(self::$mimetypes);
  614. // set root path
  615. if (!$this->_isDir($this->root)) {
  616. return false;
  617. }
  618. $read = $this->attr($this->root, 'read');
  619. // echo $this->attr($this->root.'/.tmb', 'hidden');
  620. if (!$read && !$this->attr($this->root, 'write')) {
  621. return false;
  622. }
  623. if ($read) {
  624. // check startPath - path to open by default instead of root
  625. if ($this->options['startPath']) {
  626. $path = $this->_normpath($this->options['startPath']);
  627. if ($this->_isDir($path)
  628. && $this->attr($path, 'read')
  629. && !$this->attr($path, 'hidden')
  630. && $this->_inpath($path, $this->root)) {
  631. $this->startPath = $path;
  632. }
  633. }
  634. } else {
  635. $this->options['URL'] = '';
  636. $this->options['tmbURL'] = '';
  637. $this->options['tmbPath'] = '';
  638. // read only volume
  639. array_unshift($this->attributes, array(
  640. 'pattern' => '/.*/',
  641. 'read' => false
  642. ));
  643. }
  644. $this->rootName = empty($this->options['alias']) ? $this->_basename($this->root) : $this->options['alias'];
  645. $this->treeDeep = $this->options['treeDeep'] > 0 ? (int)$this->options['treeDeep'] : 1;
  646. $this->tmbSize = $this->options['tmbSize'] > 0 ? (int)$this->options['tmbSize'] : 48;
  647. $this->URL = $this->options['URL'];
  648. if ($this->URL && preg_match("|[^/?&=]$|", $this->URL)) {
  649. $this->URL .= '/';
  650. }
  651. $this->tmbURL = !empty($this->options['tmbURL']) ? $this->options['tmbURL'] : '';
  652. if ($this->tmbURL && preg_match("|[^/?&=]$|", $this->tmbURL)) {
  653. $this->tmbURL .= '/';
  654. }
  655. $this->nameValidator = is_string($this->options['acceptedName']) && !empty($this->options['acceptedName'])
  656. ? $this->options['acceptedName']
  657. : '';
  658. $this->_checkArchivers();
  659. // manual control archive types to create
  660. if (!empty($this->options['archiveMimes']) && is_array($this->options['archiveMimes'])) {
  661. foreach ($this->archivers['create'] as $mime => $v) {
  662. if (!in_array($mime, $this->options['archiveMimes'])) {
  663. unset($this->archivers['create'][$mime]);
  664. }
  665. }
  666. }
  667. // manualy add archivers
  668. if (!empty($this->options['archivers']['create']) && is_array($this->options['archivers']['create'])) {
  669. foreach ($this->options['archivers']['create'] as $mime => $conf) {
  670. if (strpos($mime, 'application/') === 0
  671. && !empty($conf['cmd'])
  672. && isset($conf['argc'])
  673. && !empty($conf['ext'])
  674. && !isset($this->archivers['create'][$mime])) {
  675. $this->archivers['create'][$mime] = $conf;
  676. }
  677. }
  678. }
  679. if (!empty($this->options['archivers']['extract']) && is_array($this->options['archivers']['extract'])) {
  680. foreach ($this->options['archivers']['extract'] as $mime => $conf) {
  681. if (substr($mime, 'application/') === 0
  682. && !empty($cons['cmd'])
  683. && isset($conf['argc'])
  684. && !empty($conf['ext'])
  685. && !isset($this->archivers['extract'][$mime])) {
  686. $this->archivers['extract'][$mime] = $conf;
  687. }
  688. }
  689. }
  690. $this->configure();
  691. return $this->mounted = true;
  692. }
  693. /**
  694. * Return error message from last failed action
  695. *
  696. * @return array
  697. * @author Dmitry (dio) Levashov
  698. **/
  699. public function error() {
  700. return $this->error;
  701. }
  702. /**
  703. * Return root folder hash
  704. *
  705. * @return string
  706. * @author Dmitry (dio) Levashov
  707. **/
  708. public function root() {
  709. return $this->encode($this->root);
  710. }
  711. /**
  712. * Return root or startPath hash
  713. *
  714. * @return string
  715. * @author Dmitry (dio) Levashov
  716. **/
  717. public function defaultPath() {
  718. return $this->encode($this->startPath ? $this->startPath : $this->root);
  719. }
  720. /**
  721. * Return file path started from root dir
  722. *
  723. * @param string $hash file hash
  724. * @return string
  725. * @author Dmitry (dio) Levashov
  726. **/
  727. public function path($hash) {
  728. return $this->_path($this->decode($hash));
  729. }
  730. /**
  731. * Return volume options required by client:
  732. *
  733. * @return array
  734. * @author Dmitry (dio) Levashov
  735. **/
  736. public function options($hash) {
  737. return array(
  738. 'path' => $this->path($hash),
  739. 'url' => $this->URL,
  740. 'tmbUrl' => $this->tmbURL,
  741. 'disabled' => $this->disabled,
  742. 'separator' => $this->separator,
  743. 'copyOverwrite' => intval($this->options['copyOverwrite']),
  744. 'archivers' => array(
  745. 'create' => array_keys($this->archivers['create']),
  746. 'extract' => array_keys($this->archivers['extract'])
  747. )
  748. );
  749. }
  750. /**
  751. * Return true if mime is required mimes list
  752. *
  753. * @param string $mime mime type to check
  754. * @param array $mimes allowed mime types list
  755. * @return bool
  756. * @author Dmitry (dio) Levashov
  757. **/
  758. public function mimeAccepted($mime, $mimes=array()) {
  759. return $mime == 'directory' || empty($mimes) || in_array($mime, $mimes) || in_array(substr($mime, 0, strpos($mime, '/')), $mimes);
  760. }
  761. /**
  762. * undocumented function
  763. *
  764. * @return void
  765. * @author Dmitry Levashov
  766. **/
  767. public function copyFromAllowed() {
  768. return !!$this->options['copyFrom'];
  769. }
  770. /**
  771. * undocumented function
  772. *
  773. * @return void
  774. * @author Dmitry Levashov
  775. **/
  776. public function copyToAllowed() {
  777. return !!$this->options['copyTo'];
  778. }
  779. /**
  780. * Return true if file exists
  781. *
  782. * @param string $hash file hash
  783. * @return bool
  784. * @author Dmitry (dio) Levashov
  785. **/
  786. public function fileExists($hash) {
  787. $path = $this->decode($hash);
  788. return $path && $this->_fileExists($path);
  789. }
  790. /**
  791. * Check if file is folder
  792. *
  793. * @param string $hash file hash
  794. * @return bool
  795. * @author Dmitry (dio) Levashov
  796. **/
  797. public function isDir($hash) {
  798. $path = $this->decode($hash);
  799. return $path && $this->_fileExists($path) && $this->_isDir($this->decode($hash));
  800. }
  801. /**
  802. * Check if file is not folder
  803. *
  804. * @param string $hash file hash
  805. * @return bool
  806. * @author Dmitry (dio) Levashov
  807. **/
  808. public function isFile($hash) {
  809. $path = $this->decode($hash);
  810. return $path && $this->_fileExists($path) && $this->_isFile($this->decode($hash));
  811. }
  812. /**
  813. * Check if file symlink
  814. *
  815. * @param string $hash file hash
  816. * @return bool
  817. * @author Dmitry (dio) Levashov
  818. **/
  819. public function isLink($hash) {
  820. $path = $this->decode($hash);
  821. return $path && $this->_fileExists($path) && $this->_isLink($this->decode($hash));
  822. }
  823. /**
  824. * Return true if folder is readable.
  825. * If hash is not set - check root folder
  826. *
  827. * @param string $hash file hash
  828. * @return bool
  829. * @author Dmitry (dio) Levashov
  830. **/
  831. public function isReadable($hash='') {
  832. $path = $hash ? $this->decode($hash) : $this->root;
  833. return $path && $this->_fileExists($path) && $this->attr($path, 'read');
  834. }
  835. /**
  836. * Return true if folder is writeable.
  837. * If hash is not set - check root folder
  838. *
  839. * @param string $hash file hash
  840. * @return bool
  841. * @author Dmitry (dio) Levashov
  842. **/
  843. public function isWritable($hash='') {
  844. $path = $hash ? $this->decode($hash) : $this->root;
  845. return $path && $this->_fileExists($path) && $this->attr($path, 'write');
  846. }
  847. /**
  848. * Return true if file is hidden
  849. *
  850. * @param string $hash file hash
  851. * @return void
  852. * @author Dmitry (dio) Levashov
  853. **/
  854. public function isHidden($hash) {
  855. $path = $this->decode($hash);
  856. return $path && $this->_fileExists($path) && $this->attr($path, 'hidden');
  857. }
  858. /**
  859. * Return true if file is locked
  860. *
  861. * @param string $hash file hash
  862. * @return void
  863. * @author Dmitry (dio) Levashov
  864. **/
  865. public function isLocked($hash) {
  866. $path = $this->decode($hash);
  867. return $path && $this->_fileExists($path) && $this->attr($path, 'locked');
  868. }
  869. /**
  870. * Return file parent folder hash
  871. *
  872. * @param string $hash file hash
  873. * @return string
  874. * @author Dmitry (dio) Levashov
  875. **/
  876. public function parent($hash) {
  877. $path = $this->decode($hash);
  878. return $path ? $this->_dirname($path) : '';
  879. }
  880. /**
  881. * Return file info or false on error
  882. *
  883. * @param string $hash file hash
  884. * @param bool $hidden return hidden file info
  885. * @return array|false
  886. * @author Dmitry (dio) Levashov
  887. **/
  888. public function file($hash, $hidden=false) {
  889. if (($file = $this->stat($this->decode($hash))) == false
  890. || !($hidden || empty($file['hidden']))) {
  891. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  892. }
  893. return $file;
  894. }
  895. /**
  896. * Return folder info
  897. *
  898. * @param string $hash folder hash
  899. * @param bool $hidden return hidden file info
  900. * @return array|false
  901. * @author Dmitry (dio) Levashov
  902. **/
  903. public function dir($hash, $hidden=false, $resolveLink=false) {
  904. if (($dir = $this->file($hash, $hidden)) == false) {
  905. return $this->setError(elFinder::ERROR_DIR_NOT_FOUND);
  906. }
  907. if ($dir['mime'] != 'directory') {
  908. return $this->setError(elFinder::ERROR_NOT_DIR);
  909. }
  910. if ($resolveLink && !empty($dir['alias'])) {
  911. if (!($target = $this->_readlink($this->decode($hash)))) {
  912. return $this->setError(elFinder::ERROR_DIR_NOT_FOUND);
  913. }
  914. if (!($dir = $this->stat($target)) || $this->attr($target, 'hidden')) {
  915. return $this->setError(elFinder::ERROR_DIR_NOT_FOUND);
  916. }
  917. if ($dir['mime'] != 'directory') {
  918. return $this->setError(elFinder::ERROR_NOT_DIR);
  919. }
  920. }
  921. return $dir;
  922. return $dir['mime'] == 'directory'
  923. ? $dir
  924. : $this->setError(elFinder::ERROR_NOT_DIR);
  925. }
  926. /**
  927. * Return directory content or false on error
  928. *
  929. * @param string $hash file hash
  930. * @param array $mimes allowed mimetypes list
  931. * @return array|false
  932. * @author Dmitry (dio) Levashov
  933. **/
  934. public function scandir($hash, $mimes=array()) {
  935. if (($dir = $this->dir($hash)) == false) {
  936. return false;
  937. }
  938. return $dir['read']
  939. ? $this->getScandir($this->decode($hash), $mimes)
  940. : $this->setError(elFinder::ERROR_PERM_DENIED);
  941. }
  942. /**
  943. * Return dir files names list
  944. *
  945. * @param string $hash file hash
  946. * @param array $mimes allowed mimetypes list
  947. * @return array
  948. * @author Dmitry (dio) Levashov
  949. **/
  950. public function ls($hash, $mimes=array()) {
  951. if (($dir = $this->dir($hash)) == false) {
  952. return false;
  953. }
  954. if (!$dir['read']) {
  955. $this->setError(elFinder::ERROR_PERM_DENIED);
  956. }
  957. $list = array();
  958. foreach ($this->_scandir($this->decode($hash)) as $p) {
  959. if (!$this->attr($p, 'hidden')
  960. && ($this->_isDir($p) || !$mimes || $this->mimeAccepted($this->mimetype($p), $mimes))) {
  961. $list[] = $this->_basename($p);
  962. }
  963. }
  964. return $list;
  965. }
  966. /**
  967. * Return subfolders for required one or false on error
  968. *
  969. * @param string $hash folder hash or empty string to get tree from root folder
  970. * @param int $deep subdir deep
  971. * @param string $exclude dir hash which subfolders must be exluded from result, required to not get stat twice on cwd subfolders
  972. * @return array|false
  973. * @author Dmitry (dio) Levashov
  974. **/
  975. public function tree($hash='', $deep=0, $exclude='') {
  976. $hash = $hash ? $hash : $this->encode($this->root);
  977. if (($dir = $this->dir($hash)) == false) {
  978. return false;
  979. }
  980. if (!$dir['read']) {
  981. return $this->setError(elFinder::ERROR_PERM_DENIED);
  982. }
  983. $path = $this->decode($hash);
  984. $dirs = $this->gettree($path, $deep > 0 ? $deep -1 : $this->treeDeep-1, $this->decode($exclude));
  985. array_unshift($dirs, $dir);
  986. return $dirs;
  987. }
  988. /**
  989. * Return part of dirs tree from required dir upside till root dir
  990. *
  991. * @param string $hash directory hash
  992. * @return array
  993. * @author Dmitry (dio) Levashov
  994. **/
  995. public function parents($hash) {
  996. if (($current = $this->dir($hash)) == false) {
  997. return false;
  998. }
  999. $path = $this->decode($hash);
  1000. $tree = array();
  1001. while ($path && $path != $this->root) {
  1002. $path = $this->_dirname($path);
  1003. if ($this->attr($path, 'hidden')) {
  1004. return $this->setError(elFinder::ERROR_DIR_NOT_FOUND);
  1005. }
  1006. if (!$this->attr($path, 'read')) {
  1007. return $this->setError(elFinder::ERROR_OPEN, $this->_basename($path), '<br>', elFinder::ERROR_PERM_DENIED);
  1008. }
  1009. $dir = $this->stat($path);
  1010. array_unshift($tree, $dir);
  1011. if ($path != $this->root) {
  1012. foreach ($this->gettree($path, 0) as $dir) {
  1013. if (!in_array($dir, $tree)) {
  1014. $tree[] = $dir;
  1015. }
  1016. }
  1017. }
  1018. }
  1019. return $tree ? $tree : array($current);
  1020. }
  1021. /**
  1022. * Create thumbnail for required file and return its name of false on failed
  1023. *
  1024. * @return string|false
  1025. * @author Dmitry (dio) Levashov
  1026. **/
  1027. public function tmb($hash) {
  1028. if ($path = $this->decode($hash)) {
  1029. return ($tmb = $this->gettmb($path)) ? $tmb : $this->createTmb($path);
  1030. }
  1031. return false;
  1032. }
  1033. /**
  1034. * Return file size / total directory size
  1035. *
  1036. * @param string file hash
  1037. * @return int
  1038. * @author Dmitry (dio) Levashov
  1039. **/
  1040. public function size($hash) {
  1041. return $this->countSize($this->decode($hash));
  1042. }
  1043. /**
  1044. * Open file for reading and return file pointer
  1045. *
  1046. * @param string file hash
  1047. * @return Resource
  1048. * @author Dmitry (dio) Levashov
  1049. **/
  1050. public function open($hash) {
  1051. $path = $this->decode($hash);
  1052. if (($file = $this->file($hash)) == false) {
  1053. return false;
  1054. }
  1055. if ($file['mime'] == 'directory') {
  1056. return false;
  1057. }
  1058. return $this->_fopen($path, 'rb');
  1059. }
  1060. /**
  1061. * Close file pointer
  1062. *
  1063. * @param Resource $fp file pointer
  1064. * @param string $hash file hash
  1065. * @return void
  1066. * @author Dmitry (dio) Levashov
  1067. **/
  1068. public function close($fp, $hash) {
  1069. $this->_fclose($fp, $this->decode($hash));
  1070. }
  1071. /**
  1072. * Create directory and return dir info
  1073. *
  1074. * @param string $dst destination directory
  1075. * @param string $name directory name
  1076. * @return array|false
  1077. * @author Dmitry (dio) Levashov
  1078. **/
  1079. public function mkdir($dst, $name, $copy=false) {
  1080. $path = $this->decode($dst);
  1081. if (($dir = $this->dir($dst)) == false) {
  1082. return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst);
  1083. }
  1084. if (!$dir['write']) {
  1085. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1086. }
  1087. if (!$this->nameAccepted($name)) {
  1088. return $this->setError(elFinder::ERROR_INVALID_NAME);
  1089. }
  1090. if ($copy && !$this->options['copyOverwrite']) {
  1091. $name = $this->uniqueName($path, $name, '-', false);
  1092. }
  1093. $dst = $this->_joinPath($path, $name);
  1094. if ($this->_fileExists($dst)) {
  1095. if ($copy) {
  1096. if (!$this->options['copyJoin'] && $this->attr($dst, 'write')) {
  1097. foreach ($this->_scandir($dst) as $p) {
  1098. $this->doRm($p);
  1099. }
  1100. }
  1101. return $this->stat($dst);
  1102. }
  1103. return $this->setError(elFinder::ERROR_EXISTS, $name);
  1104. }
  1105. return $this->_mkdir($path, $name) ? $this->stat($this->_joinPath($path, $name)) : false;
  1106. }
  1107. /**
  1108. * Create empty file and return its info
  1109. *
  1110. * @param string $dst destination directory
  1111. * @param string $name file name
  1112. * @return array|false
  1113. * @author Dmitry (dio) Levashov
  1114. **/
  1115. public function mkfile($dst, $name) {
  1116. $path = $this->decode($dst);
  1117. if (($dir = $this->dir($dst, true)) == false) {
  1118. return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#dst');
  1119. }
  1120. if (!$dir['write']) {
  1121. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1122. }
  1123. if (!$this->nameAccepted($name)) {
  1124. return $this->setError(elFinder::ERROR_INVALID_NAME, $name);
  1125. }
  1126. if ($this->_fileExists($this->_joinPath($path, $name))) {
  1127. return $this->setError(elFinder::ERROR_EXISTS, $name);
  1128. }
  1129. return $this->_mkfile($path, $name) ? $this->stat($this->_joinPath($path, $name)) : false;
  1130. }
  1131. /**
  1132. * Rename file and return file info
  1133. *
  1134. * @param string $hash file hash
  1135. * @param string $name new file name
  1136. * @return array|false
  1137. * @author Dmitry (dio) Levashov
  1138. **/
  1139. public function rename($hash, $name) {
  1140. $path = $this->decode($hash);
  1141. if (!($file = $this->file($hash))) {
  1142. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1143. }
  1144. $dir = $this->_dirname($path);
  1145. if ($this->attr($path, 'locked')) {
  1146. return $this->setError(elFinder::ERROR_LOCKED, $file['name']);
  1147. }
  1148. if (!$this->nameAccepted($name)) {
  1149. return $this->setError(elFinder::ERROR_INVALID_NAME, $name);
  1150. }
  1151. if ($name == $file['name']) {
  1152. return $file;
  1153. }
  1154. $dst = $this->_joinPath($dir, $name);
  1155. if ($this->_fileExists($dst)) {
  1156. return $this->setError(elFinder::ERROR_EXISTS, $file['name']);
  1157. }
  1158. if ($this->_move($path, $dir, $name)) {
  1159. $this->rmTmb($path);
  1160. return $this->stat($this->_joinPath($dir, $name));
  1161. }
  1162. return false;
  1163. }
  1164. /**
  1165. * Create file copy with suffix "copy number" and return its info
  1166. *
  1167. * @param string $hash file hash
  1168. * @return array|false
  1169. * @author Dmitry (dio) Levashov
  1170. **/
  1171. public function duplicate($hash) {
  1172. if (($file = $this->file($hash)) == false) {
  1173. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1174. }
  1175. $path = $this->decode($hash);
  1176. $dir = $this->_dirname($path);
  1177. return ($path = $this->doCopy($path, $dir, $this->uniqueName($dir, $file['name']))) == false
  1178. ? false
  1179. : $this->stat($path);
  1180. }
  1181. /**
  1182. * Return true if file mime type accepted for upload
  1183. *
  1184. * @param string $tmpPath temporary file path
  1185. * @param string $name file name
  1186. * @return bool
  1187. * @author Dmitry (dio) Levashov
  1188. **/
  1189. public function uploadAllow($tmpPath, $name) {
  1190. if (!$this->nameAccepted($name)) {
  1191. return $this->setError(elFinder::ERROR_INVALID_NAME, $name);
  1192. }
  1193. $mime = $this->mimetype($this->mimeDetect == 'internal' ? $name : $tmpPath);
  1194. $allow = in_array('all', $this->uploadAllow) || $this->mimeAccepted($mime, $this->uploadAllow);
  1195. $deny = in_array('all', $this->uploadDeny) || $this->mimeAccepted($mime, $this->uploadDeny);
  1196. // dont ask me what this mean. I forgot it, but its work :)
  1197. // for details see python connector
  1198. if (!($this->uploadOrder[0] == 'allow' ? $allow && !$deny : $allow || !$deny)) {
  1199. return $this->setError(elFinder::ERROR_MIME);
  1200. }
  1201. if ($this->uploadMaxSize > 0 && filesize($tmpPath) > $this->uploadMaxSize) {
  1202. return $this->setError(elFinder::ERROR_UPLOAD_SIZE);
  1203. }
  1204. return true;
  1205. }
  1206. /**
  1207. * Save file in required directory.
  1208. *
  1209. * @param resource $fp file pointer
  1210. * @param string $dst destination directory
  1211. * @param string $name file name
  1212. * @param string $cmd source command name
  1213. * @return array
  1214. * @author Dmitry (dio) Levashov
  1215. **/
  1216. public function save($fp, $dst, $name, $cmd='upload') {
  1217. if (($dir = $this->dir($dst, true, true)) == false) {
  1218. return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst);
  1219. }
  1220. if (!$dir['write']) {
  1221. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1222. }
  1223. if (!$this->nameAccepted($name)) {
  1224. return $this->setError(elFinder::ERROR_INVALID_NAME, $name);
  1225. }
  1226. $dst = $this->decode($dst);
  1227. $_dst = $this->_joinPath($dst, $name);
  1228. if ($this->_fileExists($_dst)) {
  1229. if (($cmd == 'upload' && !$this->options['uploadOverwrite'])
  1230. || ($cmd == 'copy' && !$this->options['copyOverwrite'])) {
  1231. $name = $this->uniqueName($dst, $name, '-', false);
  1232. } elseif (!$this->attr($_dst, 'write')) {
  1233. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1234. } elseif (!$this->doRm($_dst)) {
  1235. return false;
  1236. }
  1237. }
  1238. return ($path = $this->_save($fp, $dst, $name))
  1239. ? $this->stat($path)
  1240. : false;
  1241. }
  1242. /**
  1243. * Return file contents
  1244. *
  1245. * @param string $hash file hash
  1246. * @return string|false
  1247. * @author Dmitry (dio) Levashov
  1248. **/
  1249. public function getContents($hash) {
  1250. $file = $this->file($hash);
  1251. if (!$file) {
  1252. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1253. }
  1254. if ($file['mime'] == 'directory') {
  1255. return $this->setError(elFinder::ERROR_NOT_FILE);
  1256. }
  1257. if (!$file['read']) {
  1258. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1259. }
  1260. return $this->_getContents($this->decode($hash));
  1261. }
  1262. /**
  1263. * Put content in text file and return file info.
  1264. *
  1265. * @param string $hash file hash
  1266. * @param string $content new file content
  1267. * @return array
  1268. * @author Dmitry (dio) Levashov
  1269. **/
  1270. public function putContents($hash, $content) {
  1271. $path = $this->decode($hash);
  1272. if (!($file = $this->file($hash))) {
  1273. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1274. }
  1275. if (!$file['write']) {
  1276. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1277. }
  1278. return $this->_filePutContents($path, $content) ? $this->stat($path) : false;
  1279. }
  1280. /**
  1281. * Extract files from archive
  1282. *
  1283. * @param string $hash archive hash
  1284. * @return array|bool
  1285. * @author Dmitry (dio) Levashov,
  1286. * @author Alexey Sukhotin
  1287. **/
  1288. public function extract($hash) {
  1289. if (($file = $this->file($hash)) == false) {
  1290. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1291. }
  1292. $archiver = isset($this->archivers['extract'][$file['mime']])
  1293. ? $this->archivers['extract'][$file['mime']]
  1294. : false;
  1295. if (!$archiver) {
  1296. return $this->setError(elFinder::ERROR_NOT_ARCHIVE);
  1297. }
  1298. $path = $this->decode($hash);
  1299. if (!$file['read'] || !$this->attr($this->_dirname($path), 'write')) {
  1300. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1301. }
  1302. $before = $this->scandir($file['phash']);
  1303. if (!$this->_extract($path, $archiver)) {
  1304. return false;
  1305. }
  1306. $after = $this->scandir($file['phash']);
  1307. $diff = array();
  1308. foreach ($after as $file) {
  1309. if (!in_array($file, $before)) {
  1310. $diff[] = $file;
  1311. }
  1312. }
  1313. return $diff;
  1314. }
  1315. /**
  1316. * Add files to archive
  1317. *
  1318. * @return void
  1319. **/
  1320. public function archive($hashes, $mime) {
  1321. $archiver = isset($this->archivers['create'][$mime])
  1322. ? $this->archivers['create'][$mime]
  1323. : false;
  1324. if (!$archiver) {
  1325. return $this->setError(elFinder::ERROR_ARCHIVE_TYPE);
  1326. }
  1327. $files = array();
  1328. foreach ($hashes as $hash) {
  1329. if (($file = $this->file($hash)) == false) {
  1330. return $this->error(elFinder::ERROR_FILE_NOT_FOUND, '#'+$hash);
  1331. }
  1332. if (!$file['read']) {
  1333. return $this->error(elFinder::ERROR_PERM_DENIED);
  1334. }
  1335. $path = $this->decode($hash);
  1336. if (!isset($dir)) {
  1337. $dir = $this->_dirname($path);
  1338. if (!$this->attr($dir, 'write')) {
  1339. return $this->error(elFinder::ERROR_PERM_DENIED);
  1340. }
  1341. }
  1342. $files[] = $this->_basename($path);
  1343. }
  1344. $name = (count($files) == 1 ? $files[0] : 'Archive').'.'.$archiver['ext'];
  1345. $name = $this->uniqueName($dir, $name, '');
  1346. $archive = $this->_archive($dir, $files, $name, $archiver);
  1347. return $archive ? $this->stat($archive) : false;
  1348. }
  1349. /**
  1350. * Remove file/dir
  1351. *
  1352. * @param string $hash file hash
  1353. * @return bool
  1354. * @author Dmitry (dio) Levashov
  1355. **/
  1356. public function rm($hash) {
  1357. return $this->doRm($this->decode($hash));
  1358. }
  1359. /**
  1360. * undocumented function
  1361. *
  1362. * @param string $q search string
  1363. * @param array $mimes
  1364. * @return array
  1365. * @author Dmitry (dio) Levashov
  1366. **/
  1367. public function search($q, $mimes) {
  1368. return $this->doSearch($this->root, $q, $mimes);
  1369. }
  1370. /**
  1371. * Return image dimensions
  1372. *
  1373. * @param string $hash file hash
  1374. * @return array
  1375. * @author Dmitry (dio) Levashov
  1376. **/
  1377. public function dimensions($hash) {
  1378. if (($file = $this->file($hash)) == false) {
  1379. return false;
  1380. }
  1381. return $this->_dimensions($this->decode($hash), $file['mime']);
  1382. }
  1383. /**
  1384. * Save error message
  1385. *
  1386. * @param int|array error number | array(error number, arguments)
  1387. * @return false
  1388. * @author Dmitry(dio) Levashov
  1389. **/
  1390. protected function setError($error) {
  1391. $this->error = func_get_args();
  1392. return false;
  1393. }
  1394. /*********************************************************************/
  1395. /* FS API */
  1396. /*********************************************************************/
  1397. /***************** paths *******************/
  1398. /**
  1399. * Encode path into hash
  1400. *
  1401. * @param string file path
  1402. * @return string
  1403. * @author Dmitry (dio) Levashov
  1404. * @author Troex Nevelin
  1405. **/
  1406. protected function encode($path) {
  1407. if ($path) {
  1408. // cut ROOT from $path for security reason, even if hacker decodes the path he will not know the root
  1409. $p = $this->_relpath($path);
  1410. // if reqesting root dir $path will be empty, then assign '/' as we cannot leave it blank for crypt
  1411. if (!$p) {
  1412. $p = DIRECTORY_SEPARATOR;
  1413. }
  1414. // TODO crypt path and return hash
  1415. $hash = $this->crypt($p);
  1416. // hash is used as id in HTML that means it must contain vaild chars
  1417. // make base64 html safe and append prefix in begining
  1418. $hash = strtr(base64_encode($hash), '+/=', '-_.');
  1419. // remove dots '.' at the end, before it was '=' in base64
  1420. $hash = rtrim($hash, '.');
  1421. // append volume id to make hash unique
  1422. return $this->id.$hash;
  1423. }
  1424. }
  1425. /**
  1426. * Decode path from hash
  1427. *
  1428. * @param string file hash
  1429. * @return string
  1430. * @author Dmitry (dio) Levashov
  1431. * @author Troex Nevelin
  1432. **/
  1433. protected function decode($hash) {
  1434. if (strpos($hash, $this->id) === 0) {
  1435. // cut volume id after it was prepended in encode
  1436. $h = substr($hash, strlen($this->id));
  1437. // replace HTML safe base64 to normal
  1438. $h = base64_decode(strtr($h, '-_.', '+/='));
  1439. // TODO uncrypt hash and return path
  1440. $path = $this->uncrypt($h);
  1441. // append ROOT to path after it was cut in encode
  1442. return $this->_abspath($path);//$this->root.($path == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR.$path);
  1443. }
  1444. }
  1445. /**
  1446. * Return crypted path
  1447. * Not implemented
  1448. *
  1449. * @param string path
  1450. * @return mixed
  1451. * @author Dmitry (dio) Levashov
  1452. **/
  1453. protected function crypt($path) {
  1454. return $path;
  1455. }
  1456. /**
  1457. * Return uncrypted path
  1458. * Not implemented
  1459. *
  1460. * @param mixed hash
  1461. * @return mixed
  1462. * @author Dmitry (dio) Levashov
  1463. **/
  1464. protected function uncrypt($hash) {
  1465. return $hash;
  1466. }
  1467. /**
  1468. * Validate file name based on $this->options['acceptedName'] regexp
  1469. *
  1470. * @param string $name file name
  1471. * @return bool
  1472. * @author Dmitry (dio) Levashov
  1473. **/
  1474. protected function nameAccepted($name) {
  1475. if ($this->nameValidator) {
  1476. if (function_exists($this->nameValidator)) {
  1477. $f = $this->nameValidator;
  1478. return $f($name);
  1479. }
  1480. return preg_match($this->nameValidator, $name);
  1481. }
  1482. return true;
  1483. }
  1484. /**
  1485. * Return new unique name based on file name and suffix
  1486. *
  1487. * @param string $path file path
  1488. * @param string $suffix suffix append to name
  1489. * @return string
  1490. * @author Dmitry (dio) Levashov
  1491. **/
  1492. protected function uniqueName($dir, $name, $suffix = ' copy', $checkNum=true) {
  1493. $ext = '';
  1494. if (!$this->_isDir($this->_joinPath($dir, $name))) {
  1495. if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) {
  1496. $ext = '.'.$m[1];
  1497. $name = substr($name, 0, strlen($name)-strlen($m[0]));
  1498. }
  1499. }
  1500. if ($checkNum && preg_match('/('.$suffix.')(\d*)$/i', $name, $m)) {
  1501. $i = (int)$m[2];
  1502. $name = substr($name, 0, strlen($name)-strlen($m[2]));
  1503. } else {
  1504. $i = 0;
  1505. $name .= $suffix;
  1506. }
  1507. $max = $i+100000;
  1508. while ($i <= $max) {
  1509. $n = $name.($i > 0 ? $i : '').$ext;
  1510. if (!$this->_fileExists($this->_joinPath($dir, $n))) {
  1511. return $n;
  1512. }
  1513. $i++;
  1514. }
  1515. return $name.md5($dir).$ext;
  1516. }
  1517. /*********************** file stat *********************/
  1518. /**
  1519. * Check file attribute
  1520. *
  1521. * @param string $path file path
  1522. * @param string $name attribute name (read|write|locked|hidden)
  1523. * @return bool
  1524. * @author Dmitry (dio) Levashov
  1525. **/
  1526. protected function attr($path, $name) {
  1527. if (!isset($this->defaults[$name])) {
  1528. return false;
  1529. }
  1530. $defaults = $perm1 = $perm2 = $perm3 = $this->defaults[$name];
  1531. switch ($name) {
  1532. case 'read': $perm1 = $this->_isReadable($path); break;
  1533. case 'write': $perm1 = $this->_isWritable($path); break;
  1534. case 'locked': $perm1 = $this->_isLocked($path); break;
  1535. case 'hidden': $perm1 = $this->_isHidden($path); break;
  1536. }
  1537. $path = $this->separator.$this->_relpath($path);
  1538. if ($this->access) {
  1539. if (is_array($this->access)) {
  1540. $obj = $this->access[0];
  1541. $method = $this->access[1];
  1542. $perm2 = $obj->{$method}($name, $path, $this->options['accessControlData'], $this);
  1543. } else {
  1544. $func = $this->access;
  1545. $perm2 = $func($name, $path, $this->options['accessControlData'], $this);
  1546. }
  1547. }
  1548. for ($i = 0, $c = count($this->attributes); $i < $c; $i++) {
  1549. $attrs = $this->attributes[$i];
  1550. if (isset($attrs[$name]) && isset($attrs['pattern']) && preg_match($attrs['pattern'], $path)) {
  1551. $perm3 = $attrs[$name];
  1552. break;
  1553. }
  1554. }
  1555. $ret = $name == 'read' || $name == 'write'
  1556. ? $defaults & $perm1 & $perm2 & $perm3
  1557. : $defaults ^ $perm1 ^ $perm2 ^ $perm3;
  1558. return $ret;
  1559. }
  1560. /**
  1561. * Return fileinfo
  1562. *
  1563. * @param string $path file cache
  1564. * @return array
  1565. * @author Dmitry (dio) Levashov
  1566. **/
  1567. protected function stat($path) {
  1568. $root = $path == $this->root;
  1569. $link = !$root && $this->_isLink($path);
  1570. if (!$path || (!$this->_fileExists($path) && !$link)) {
  1571. return false;
  1572. }
  1573. $dir = $this->_isDir($path);
  1574. $file = array(
  1575. 'hash' => $this->encode($path),
  1576. 'phash' => $root ? '' : $this->encode(dirname($path)),
  1577. 'name' => $root ? $this->rootName : $this->_basename($path)
  1578. );
  1579. if ($link) {
  1580. $stat = $this->_lstat($path);
  1581. $file['size'] = $stat['size'];
  1582. $file['date'] = $this->formatDate($stat['mtime']);
  1583. } else {
  1584. $file['size'] = $dir ? 0 : $this->_filesize($path);
  1585. $file['date'] = $this->formatDate($this->_filemtime($path));
  1586. }
  1587. if ($link) {
  1588. if (($target = $this->_readlink($path)) != false) {
  1589. $file['mime'] = $this->mimetype($target);
  1590. $file['alias'] = $this->_path($target);
  1591. $file['read'] = (int)$this->attr($path, 'read');
  1592. $file['write'] = (int)$this->attr($path, 'write');
  1593. } else {
  1594. $file['mime'] = 'symlink-broken';
  1595. $file['read'] = 0;
  1596. $file['write'] = 0;
  1597. }
  1598. } else {
  1599. $file['mime'] = $dir ? 'directory' : $this->mimetype($path);
  1600. $file['read'] = (int)$this->attr($path, 'read');
  1601. $file['write'] = (int)$this->attr($path, 'write');
  1602. }
  1603. if ($this->attr($path, 'locked')) {
  1604. $file['locked'] = 1;
  1605. }
  1606. if ($this->attr($path, 'hidden')) {
  1607. $file['hidden'] = 1;
  1608. }
  1609. if ($this->options['utf8fix']) {
  1610. $file['name'] = json_decode(str_replace($this->options['utf8patterns'], $this->options['utf8replace'], json_encode($file['name'])));
  1611. }
  1612. if ($root) {
  1613. $file['volumeid'] = $this->id;
  1614. }
  1615. if ($file['read'] && !isset($file['hidden'])) {
  1616. if ($dir) {
  1617. if (!$link && $this->_subdirs($path)) {
  1618. $file['dirs'] = 1;
  1619. }
  1620. } else {
  1621. if (($tmb = $this->gettmb($path)) != false) {
  1622. $file['tmb'] = $tmb;
  1623. } elseif ($this->canCreateTmb($path, $file['mime'])) {
  1624. $file['tmb'] = 1;
  1625. }
  1626. }
  1627. }
  1628. return $file;
  1629. }
  1630. /**
  1631. * Return file mimetype
  1632. *
  1633. * @param string $path file path
  1634. * @return string
  1635. * @author Dmitry (dio) Levashov
  1636. **/
  1637. protected function mimetype($path) {
  1638. $type = '';
  1639. if ($this->mimeDetect == 'finfo') {
  1640. if (empty($this->finfo)) {
  1641. $this->finfo = finfo_open(FILEINFO_MIME);
  1642. }
  1643. $type = @finfo_file($this->finfo, $path);
  1644. } elseif ($type == 'mime_content_type') {
  1645. $type = mime_content_type($path);
  1646. } else {
  1647. $pinfo = pathinfo($path);
  1648. $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : '';
  1649. $type = isset(self::$mimetypes[$ext]) ? self::$mimetypes[$ext] : 'unknown';
  1650. }
  1651. $type = explode(';', $type);
  1652. $type = trim($type[0]);
  1653. if ($type == 'unknown') {
  1654. if ($this->_isLink($path)) {
  1655. $target = $this->_readlink($path);
  1656. $type = $target ? $this->mimetype($target) : 'symlink-broken';
  1657. } else if ($this->_isDir($path)) {
  1658. $type = 'directory';
  1659. } elseif ($this->_filesize($path) == 0 || preg_match('/\.(ini|conf)$/i', $path)) {
  1660. $type = 'text/plain';
  1661. }
  1662. } elseif ($type == 'application/x-empty') {
  1663. // finfo return this mime for empty files
  1664. $type = 'text/plain';
  1665. } elseif ($type == 'application/x-zip') {
  1666. // http://elrte.org/redmine/issues/163
  1667. $type = 'application/zip';
  1668. }
  1669. return $type;
  1670. }
  1671. /**
  1672. * Return file/total directory size
  1673. *
  1674. * @param string $path file path
  1675. * @return int
  1676. * @author Dmitry (dio) Levashov
  1677. **/
  1678. protected function countSize($path) {
  1679. if (!$this->_fileExists($path)
  1680. || !$this->attr($path, 'read')
  1681. || $this->attr($path, 'hidden')) {
  1682. return 0;
  1683. }
  1684. if ($this->_isLink($path)) {
  1685. $lstat = $this->_lstat($path);
  1686. return $lstat['size'];
  1687. }
  1688. if ($this->_isFile($path)) {
  1689. return $this->_filesize($path);
  1690. }
  1691. $size = 0;
  1692. foreach ($this->_scandir($path) as $p) {
  1693. $name = $this->_basename($p);
  1694. if ($name != '.' && $p != '..') {
  1695. $size += $this->countSize($p);
  1696. }
  1697. }
  1698. return $size;
  1699. }
  1700. /***************** get content *******************/
  1701. /**
  1702. * Return required dir files info
  1703. *
  1704. * @param string $path dir path
  1705. * @param array $mimes only dirs files this mimes include in result
  1706. * @return array
  1707. * @author Dmitry (dio) Levashov
  1708. **/
  1709. protected function getScandir($path, $mimes=array()) {
  1710. $files = array();
  1711. foreach ($this->_scandir($path) as $p) {
  1712. if (!$this->attr($p, 'hidden')
  1713. && ($this->_isDir($p) || !$mimes || $this->mimeAccepted($this->mimetype($p), $mimes))
  1714. && ($file = $this->stat($p)) != false) {
  1715. $files[] = $file;
  1716. }
  1717. }
  1718. return $files;
  1719. }
  1720. /**
  1721. * Return subdirs tree
  1722. *
  1723. * @param string $path parent dir path
  1724. * @param int $deep tree deep
  1725. * @return array
  1726. * @author Dmitry (dio) Levashov
  1727. **/
  1728. protected function gettree($path, $deep, $exclude='') {
  1729. $dirs = array();
  1730. foreach ($this->_scandir($path) as $p) {
  1731. if (!$this->attr($p, 'hidden')
  1732. && $this->_isDir($p)
  1733. && $path != $exclude
  1734. && ($dir = $this->stat($p))) {
  1735. $dirs[] = $dir;
  1736. if ($deep > 0 && isset($dir['dirs'])) {
  1737. $dirs = array_merge($dirs, $this->gettree($p, $deep-1));
  1738. }
  1739. }
  1740. }
  1741. return $dirs;
  1742. }
  1743. /**
  1744. * undocumented function
  1745. *
  1746. * @return void
  1747. * @author Dmitry Levashov
  1748. **/
  1749. protected function doSearch($path, $q, $mimes) {
  1750. $result = array();
  1751. foreach($this->_scandir($path) as $p) {
  1752. $mime = $this->mimetype($p);
  1753. if ($this->attr($p, 'hidden') || !$this->mimeAccepted($mime)) {
  1754. continue;
  1755. }
  1756. $name = $this->_basename($p);
  1757. if (strpos($name, $q) !== false) {
  1758. $stat = $this->stat($p);
  1759. $stat['path'] = $this->_path($p);
  1760. if ($this->URL) {
  1761. $stat['url'] = $this->URL.str_replace($this->separator, '/', substr($p, strlen($this->root)+1));
  1762. }
  1763. $result[] = $stat;
  1764. }
  1765. if ($mime == 'directory' && $this->attr($p, 'read') && !$this->_isLink($p)) {
  1766. $result = array_merge($result, $this->doSearch($p, $q, $mimes));
  1767. }
  1768. }
  1769. return $result;
  1770. }
  1771. /********************** manuipulations ******************/
  1772. /**
  1773. * Remove file/ recursive remove dir
  1774. *
  1775. * @param string $path file path
  1776. * @return bool
  1777. * @author Dmitry (dio) Levashov
  1778. **/
  1779. protected function doRm($path) {
  1780. if (!$this->_fileExists($path)) {
  1781. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1782. }
  1783. $dirname = $this->_dirname($path);
  1784. $name = $this->_basename($path);
  1785. if ($this->attr($path, 'locked')) {
  1786. return $this->setError(elFinder::ERROR_LOCKED, $name);
  1787. }
  1788. if ($this->_isLink($path) || $this->_isFile($path)) {
  1789. $this->rmTmb($path);
  1790. return $this->_unlink($path);
  1791. } elseif ($this->_isDir($path)) {
  1792. foreach ($this->_scandir($path) as $p) {
  1793. $name = $this->_basename($p);
  1794. if ($name != '.' && $name != '..' && !$this->doRm($p)) {
  1795. return false;
  1796. }
  1797. }
  1798. return $this->_rmdir($path);
  1799. }
  1800. }
  1801. /**
  1802. * Copy file/recursive copy dir
  1803. *
  1804. * @param string $source source path
  1805. * @param string $target target dir path
  1806. * @param string $name new file name
  1807. * @return string|false
  1808. * @author Dmitry (dio) Levashov
  1809. **/
  1810. protected function doCopy($source, $dst, $name='') {
  1811. if (!$this->_fileExists($source)) {
  1812. return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
  1813. }
  1814. if (!$this->attr($source, 'read')) {
  1815. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1816. }
  1817. if (!$this->_isDir($dst)) {
  1818. return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, $dst['name']);
  1819. }
  1820. if (!$this->attr($dst, 'write')) {
  1821. return $this->setError(elFinder::ERROR_PERM_DENIED);
  1822. }
  1823. if ($this->_inpath($dst, $source)) {
  1824. return $this->setError(elFinder::ERROR_COPY_INTO_ITSELF, $source['name']);
  1825. }
  1826. if (!$name) {
  1827. $name = $this->_basename($source);
  1828. }
  1829. $_dst = $this->_joinPath($dst, $name);
  1830. if ($this->_fileExists($_dst)) {
  1831. if ($this->attr($_dst, 'locked')) {
  1832. return $this->setError(elFinder::ERROR_LOCKED, $name);
  1833. }
  1834. if (!$this->doRm($_dst)) {
  1835. return false;
  1836. }
  1837. }
  1838. if ($this->_isLink($source)) {
  1839. return ($link = $this->_readlink($source)) != false && $this->_symlink($link, $dst, $name)
  1840. ? $this->_joinPath($dst, $name)
  1841. : false;
  1842. }
  1843. if ($this->_isFile($source)) {
  1844. return $this->_copy($source, $dst, $name) ? $this->_joinPath($dst, $name) : false;
  1845. }
  1846. if ($this->_isDir($source)) {
  1847. if (!$this->_mkdir($dst, $name) || ($ls = $this->_scandir($source)) === false) {
  1848. return false;
  1849. }
  1850. $dst = $this->_joinPath($dst, $name);
  1851. foreach ($ls as $path) {
  1852. $name = $this->_basename($path);
  1853. if ($name != '.' && $name != '..' && !$this->attr($path, 'hidden')) {
  1854. if (!$this->doCopy($path, $dst)) {
  1855. return false;
  1856. }
  1857. }
  1858. }
  1859. return $dst;
  1860. }
  1861. return false;
  1862. }
  1863. /************************* thumbnails **************************/
  1864. /**
  1865. * Return thumbnail file name for required file
  1866. *
  1867. * @param string $path file path
  1868. * @return string
  1869. * @author Dmitry (dio) Levashov
  1870. **/
  1871. protected function tmbname($path) {
  1872. return md5($path).'.png';
  1873. }
  1874. /**
  1875. * Return thumnbnail name if exists
  1876. *
  1877. * @param string $path file path
  1878. * @return string|false
  1879. * @author Dmitry (dio) Levashov
  1880. **/
  1881. protected function gettmb($path) {
  1882. if ($this->tmbURL && $this->tmbPath) {
  1883. // file itself thumnbnail
  1884. if (strpos($path, $this->tmbPath) === 0) {
  1885. return basename($path);
  1886. }
  1887. $name = $this->tmbname($path);
  1888. if (file_exists($this->tmbPath.DIRECTORY_SEPARATOR.$name)) {
  1889. return $name;
  1890. }
  1891. }
  1892. return false;
  1893. }
  1894. /**
  1895. * Return true if thumnbnail for required file can be created
  1896. *
  1897. * @param string $path thumnbnail path
  1898. * @param string $mime file mimetype
  1899. * @return string|bool
  1900. * @author Dmitry (dio) Levashov
  1901. **/
  1902. protected function canCreateTmb($path, $mime) {
  1903. return $this->tmbPath
  1904. && $this->tmbURL
  1905. && $this->tmbPathWritable
  1906. && strpos($path, $this->tmbPath) === false // do not create thumnbnail for thumnbnail
  1907. && $this->imgLib
  1908. && strpos($mime, 'image') === 0
  1909. && ($this->imgLib == 'gd' ? $mime == 'image/jpeg' || $mime == 'image/png' || $mime == 'mime/gif' : true);
  1910. }
  1911. /**
  1912. * Return x/y coord for crop image thumbnail
  1913. *
  1914. * @param int $w image width
  1915. * @param int $h image height
  1916. * @param int $size thumbnail size
  1917. * @param bool $crop crop image fragment for thumbnail
  1918. * @return array
  1919. * @author Dmitry (dio) Levashov
  1920. * @author Alexey Sukhotin
  1921. **/
  1922. protected function tmbEffects($w, $h, $tmbSize, $crop = true) {
  1923. $x = 0;
  1924. $y = 0;
  1925. $size_w = 0;
  1926. $size_h = 0;
  1927. if ($crop == false) {
  1928. /* Calculating image scale width and height */
  1929. $xscale = $w / $tmbSize;
  1930. $yscale = $h / $tmbSize;
  1931. if ($yscale > $xscale) {
  1932. $newwidth = round($w * (1 / $yscale));
  1933. $newheight = round($h * (1 / $yscale));
  1934. } else {
  1935. $newwidth = round($w * (1 / $xscale));
  1936. $newheight = round($h * (1 / $xscale));
  1937. }
  1938. /* Keeping original dimensions if image fitting into thumbnail without scale */
  1939. if ($w <= $tmbSize && $h <= $tmbSize) {
  1940. $newwidth = $w;
  1941. $newheight = $h;
  1942. }
  1943. /* Calculating coordinates for aligning thumbnail */
  1944. $y = ceil(($tmbSize - $newheight) / 2);
  1945. $x = ceil(($tmbSize - $newwidth) / 2);
  1946. $size_w = $newwidth;
  1947. $size_h = $newheight;
  1948. } else {
  1949. $size_w = $size_h = min($w, $h);
  1950. /* calculating coordinates for cropping thumbnail */
  1951. if ($w > $h) {
  1952. $x = ceil(($w - $h)/2);
  1953. } else {
  1954. $y = ceil(($h - $w)/2);
  1955. }
  1956. }
  1957. return array($x, $y, $size_w, $size_h);
  1958. }
  1959. /**
  1960. * Create thumnbnail and return it's URL on success
  1961. *
  1962. * @param string $path file path
  1963. * @param string $mime file mime type
  1964. * @return string|false
  1965. * @author Dmitry (dio) Levashov
  1966. **/
  1967. protected function createTmb($path) {
  1968. $mime = $this->mimetype($path);
  1969. if (!$this->canCreateTmb($path, $mime)) {
  1970. return false;
  1971. }
  1972. $name = $this->tmbName($path);
  1973. $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
  1974. // copy image in tmbPath so some drivers does not store files on local fs
  1975. if (($src = $this->_fopen($path, 'rb')) == false
  1976. || ($trg = @fopen($tmb, 'wb')) == false) {
  1977. return false;
  1978. }
  1979. while (!feof($src)) {
  1980. fwrite($trg, fread($src, 8192));
  1981. }
  1982. $this->_fclose($src, $path);
  1983. fclose($trg);
  1984. if (($s = @getimagesize($tmb)) == false) {
  1985. return false;
  1986. }
  1987. $result = false;
  1988. $tmbSize = $this->tmbSize;
  1989. list($x, $y, $size_w, $size_h) = $this->tmbEffects($s[0], $s[1], $tmbSize, $this->options['tmbCrop']);
  1990. switch ($this->imgLib) {
  1991. case 'imagick':
  1992. try {
  1993. $img = new imagick($tmb);
  1994. } catch (Exception $e) {
  1995. return false;
  1996. }
  1997. $img->contrastImage(1);
  1998. if ($this->options['tmbCrop'] == false) {
  1999. $img1 = new Imagick();
  2000. $img1->newImage($tmbSize, $tmbSize, new ImagickPixel($this->options['tmbBgColor']));
  2001. $img1->setImageFormat('png');
  2002. $img->resizeImage($size_w, $size_h, NULL, true);
  2003. $img1->compositeImage( $img, imagick::COMPOSITE_OVER, $x, $y );
  2004. $result = $img1->writeImage($tmb);
  2005. } else {
  2006. $result = $img->cropThumbnailImage($tmbSize, $tmbSize) && $img->writeImage($tmb);
  2007. }
  2008. break;
  2009. case 'gd':
  2010. if ($s['mime'] == 'image/jpeg') {
  2011. $img = imagecreatefromjpeg($tmb);
  2012. } elseif ($s['mime'] == 'image/png') {
  2013. $img = imagecreatefrompng($tmb);
  2014. } elseif ($s['mime'] == 'image/gif') {
  2015. $img = imagecreatefromgif($tmb);
  2016. } elseif ($s['mime'] == 'image/xbm') {
  2017. $img = imagecreatefromxbm($tmb);
  2018. }
  2019. if ($img && false != ($tmp = imagecreatetruecolor($tmbSize, $tmbSize))) {
  2020. if ($this->options['tmbCrop'] == false) {
  2021. if ($this->options['tmbBgColor'] == 'transparent') {
  2022. list($r, $g, $b) = array(0, 0, 255);
  2023. } else {
  2024. list($r, $g, $b) = sscanf($this->options['tmbBgColor'], "#%02x%02x%02x");
  2025. }
  2026. $bgcolor = imagecolorallocate($tmp, $r, $g, $b);
  2027. if ($this->options['tmbBgColor'] == 'transparent') {
  2028. $bgcolor = imagecolortransparent($tmp, $bgcolor);
  2029. }
  2030. imagefill($tmp, 0, 0, $bgcolor);
  2031. if (!imagecopyresampled($tmp, $img, $x, $y, 0, 0, $size_w, $size_h, $s[0], $s[1])) {
  2032. return false;
  2033. }
  2034. } else {
  2035. if (!imagecopyresampled($tmp, $img, 0, 0, $x, $y, $tmbSize, $tmbSize, $size_w, $size_h)) {
  2036. return false;
  2037. }
  2038. }
  2039. $result = imagepng($tmp, $tmb, 7);
  2040. imagedestroy($img);
  2041. imagedestroy($tmp);
  2042. }
  2043. break;
  2044. }
  2045. return $result ? $name : false;
  2046. }
  2047. /**
  2048. * Execute shell command
  2049. *
  2050. * @param string $command command line
  2051. * @param array $output stdout strings
  2052. * @param array $return_var process exit code
  2053. * @param array $error_output stderr strings
  2054. * @return int exit code
  2055. * @author Alexey Sukhotin
  2056. **/
  2057. protected function procExec($command , array &$output = null, &$return_var = -1, array &$error_output = null) {
  2058. $descriptorspec = array(
  2059. 0 => array("pipe", "r"), // stdin
  2060. 1 => array("pipe", "w"), // stdout
  2061. 2 => array("pipe", "w") // stderr
  2062. );
  2063. $process = proc_open($command, $descriptorspec, $pipes, null, null);
  2064. if (is_resource($process)) {
  2065. fclose($pipes[0]);
  2066. $tmpout = '';
  2067. $tmperr = '';
  2068. if( !feof( $pipes[1] ) ) {
  2069. $output[] = fgets($pipes[1], 1024);
  2070. }
  2071. if( !feof( $pipes[2] ) ) {
  2072. $error_output[] = fgets($pipes[2], 1024);
  2073. }
  2074. fclose($pipes[1]);
  2075. fclose($pipes[2]);
  2076. $return_var = proc_close($process);
  2077. }
  2078. return $return_var;
  2079. }
  2080. /**
  2081. * Remove thumbnail
  2082. *
  2083. * @param string $path file path
  2084. * @return void
  2085. * @author Dmitry (dio) Levashov
  2086. **/
  2087. protected function rmTmb($path) {
  2088. $path = $this->tmbPath.DIRECTORY_SEPARATOR.$this->tmbName($path);
  2089. if (file_exists($path)) {
  2090. @unlink($path);
  2091. }
  2092. }
  2093. /*********************** misc *************************/
  2094. /**
  2095. * Return smart formatted date
  2096. *
  2097. * @param int $ts file timestamp
  2098. * @return string
  2099. * @author Dmitry (dio) Levashov
  2100. **/
  2101. protected function formatDate($ts) {
  2102. if ($ts > $this->today) {
  2103. return 'Today '.date($this->options['timeFormat'], $ts);
  2104. }
  2105. if ($ts > $this->yesterday) {
  2106. return 'Yesterday '.date($this->options['timeFormat'], $ts);
  2107. }
  2108. return date($this->options['dateFormat'], $ts);
  2109. }
  2110. /**==================================* abstract methods *====================================**/
  2111. /*********************** paths/urls *************************/
  2112. /**
  2113. * Return parent directory path
  2114. *
  2115. * @param string $path file path
  2116. * @return string
  2117. * @author Dmitry (dio) Levashov
  2118. **/
  2119. abstract protected function _dirname($path);
  2120. /**
  2121. * Return file name
  2122. *
  2123. * @param string $path file path
  2124. * @return string
  2125. * @author Dmitry (dio) Levashov
  2126. **/
  2127. abstract protected function _basename($path);
  2128. /**
  2129. * Join dir name and file name and return full path.
  2130. * Some drivers (db) use int as path - so we give to concat path to driver itself
  2131. *
  2132. * @param string $dir dir path
  2133. * @param string $name file name
  2134. * @return string
  2135. * @author Dmitry (dio) Levashov
  2136. **/
  2137. abstract protected function _joinPath($dir, $name);
  2138. /**
  2139. * Return normalized path
  2140. *
  2141. * @param string $path file path
  2142. * @return string
  2143. * @author Dmitry (dio) Levashov
  2144. **/
  2145. abstract protected function _normpath($path);
  2146. /**
  2147. * Return file path related to root dir
  2148. *
  2149. * @param string $path file path
  2150. * @return string
  2151. * @author Dmitry (dio) Levashov
  2152. **/
  2153. abstract protected function _relpath($path);
  2154. /**
  2155. * Convert path related to root dir into real path
  2156. *
  2157. * @param string $path rel file path
  2158. * @return string
  2159. * @author Dmitry (dio) Levashov
  2160. **/
  2161. abstract protected function _abspath($path);
  2162. /**
  2163. * Return fake path started from root dir.
  2164. * Required to show path on client side.
  2165. *
  2166. * @param string $path file path
  2167. * @return string
  2168. * @author Dmitry (dio) Levashov
  2169. **/
  2170. abstract protected function _path($path);
  2171. /**
  2172. * Return true if $path is children of $parent
  2173. *
  2174. * @param string $path path to check
  2175. * @param string $parent parent path
  2176. * @return bool
  2177. * @author Dmitry (dio) Levashov
  2178. **/
  2179. abstract protected function _inpath($path, $parent);
  2180. /*********************** check type *************************/
  2181. /**
  2182. * Return true if file exists
  2183. *
  2184. * @param string $path file path
  2185. * @return bool
  2186. * @author Dmitry (dio) Levashov
  2187. **/
  2188. abstract protected function _fileExists($path);
  2189. /**
  2190. * Return true if path is a directory
  2191. *
  2192. * @param string file path
  2193. * @return bool
  2194. * @author Dmitry (dio) Levashov
  2195. **/
  2196. abstract protected function _isDir($path);
  2197. /**
  2198. * Return true if path is a file
  2199. *
  2200. * @param string file path
  2201. * @return bool
  2202. * @author Dmitry (dio) Levashov
  2203. **/
  2204. abstract protected function _isFile($path);
  2205. /**
  2206. * Return true if path is a symlink
  2207. *
  2208. * @param string file path
  2209. * @return bool
  2210. * @author Dmitry (dio) Levashov
  2211. **/
  2212. abstract protected function _isLink($path);
  2213. /***************** file attributes ********************/
  2214. /**
  2215. * Return true if path is readable
  2216. *
  2217. * @param string file path
  2218. * @return bool
  2219. * @author Dmitry (dio) Levashov
  2220. **/
  2221. abstract protected function _isReadable($path);
  2222. /**
  2223. * Return true if path is writable
  2224. *
  2225. * @param string file path
  2226. * @return bool
  2227. * @author Dmitry (dio) Levashov
  2228. **/
  2229. abstract protected function _isWritable($path);
  2230. /**
  2231. * Return true if path is locked
  2232. *
  2233. * @param string file path
  2234. * @return bool
  2235. * @author Dmitry (dio) Levashov
  2236. **/
  2237. abstract protected function _isLocked($path);
  2238. /**
  2239. * Return true if path is hidden
  2240. *
  2241. * @param string file path
  2242. * @return bool
  2243. * @author Dmitry (dio) Levashov
  2244. **/
  2245. abstract protected function _isHidden($path);
  2246. /***************** file stat ********************/
  2247. /**
  2248. * Return file size
  2249. *
  2250. * @param string $path file path
  2251. * @return int
  2252. * @author Dmitry (dio) Levashov
  2253. **/
  2254. abstract protected function _filesize($path);
  2255. /**
  2256. * Return file modification time
  2257. *
  2258. * @param string $path file path
  2259. * @return int
  2260. * @author Dmitry (dio) Levashov
  2261. **/
  2262. abstract protected function _filemtime($path);
  2263. /**
  2264. * Return true if path is dir and has at least one childs directory
  2265. *
  2266. * @param string $path dir path
  2267. * @return bool
  2268. * @author Dmitry (dio) Levashov
  2269. **/
  2270. abstract protected function _subdirs($path);
  2271. /**
  2272. * Return object width and height
  2273. * Ususaly used for images, but can be realize for video etc...
  2274. *
  2275. * @param string $path file path
  2276. * @param string $mime file mime type
  2277. * @return string
  2278. * @author Dmitry (dio) Levashov
  2279. **/
  2280. abstract protected function _dimensions($path, $mime);
  2281. /**
  2282. * Return symlink stat (required only size and mtime)
  2283. *
  2284. * @param string $path link path
  2285. * @return array
  2286. * @author Dmitry (dio) Levashov
  2287. **/
  2288. abstract protected function _lstat($path);
  2289. /******************** file/dir content *********************/
  2290. /**
  2291. * Return symlink target file
  2292. *
  2293. * @param string $path link path
  2294. * @return string
  2295. * @author Dmitry (dio) Levashov
  2296. **/
  2297. abstract protected function _readlink($path);
  2298. /**
  2299. * Return files list in directory
  2300. *
  2301. * @param string $path dir path
  2302. * @return array
  2303. * @author Dmitry (dio) Levashov
  2304. **/
  2305. abstract protected function _scandir($path);
  2306. /**
  2307. * Open file and return file pointer
  2308. *
  2309. * @param string $path file path
  2310. * @param bool $write open file for writing
  2311. * @return resource|false
  2312. * @author Dmitry (dio) Levashov
  2313. **/
  2314. abstract protected function _fopen($path, $mode="rb");
  2315. /**
  2316. * Close opened file
  2317. *
  2318. * @param resource $fp file pointer
  2319. * @return bool
  2320. * @author Dmitry (dio) Levashov
  2321. **/
  2322. abstract protected function _fclose($fp, $path);
  2323. /******************** file/dir manipulations *************************/
  2324. /**
  2325. * Create dir
  2326. *
  2327. * @param string $path parent dir path
  2328. * @param string $name new directory name
  2329. * @return bool
  2330. * @author Dmitry (dio) Levashov
  2331. **/
  2332. abstract protected function _mkdir($path, $name);
  2333. /**
  2334. * Create file
  2335. *
  2336. * @param string $path parent dir path
  2337. * @param string $name new file name
  2338. * @return bool
  2339. * @author Dmitry (dio) Levashov
  2340. **/
  2341. abstract protected function _mkfile($path, $name);
  2342. /**
  2343. * Create symlink
  2344. *
  2345. * @param string $target link target
  2346. * @param string $path symlink dir
  2347. * @param string $name symlink name
  2348. * @return bool
  2349. * @author Dmitry (dio) Levashov
  2350. **/
  2351. abstract protected function _symlink($target, $path, $name='');
  2352. /**
  2353. * Copy file into another file (only inside one volume)
  2354. *
  2355. * @param string $source source file path
  2356. * @param string $target target dir path
  2357. * @param string $name file name
  2358. * @return bool
  2359. * @author Dmitry (dio) Levashov
  2360. **/
  2361. abstract protected function _copy($source, $targetDir, $name='');
  2362. /**
  2363. * Move file into another parent dir (only inside one volume)
  2364. *
  2365. * @param string $source source file path
  2366. * @param string $target target dir path
  2367. * @param string $name file name
  2368. * @return bool
  2369. * @author Dmitry (dio) Levashov
  2370. **/
  2371. abstract protected function _move($source, $targetDir, $name='');
  2372. /**
  2373. * Remove file
  2374. *
  2375. * @param string $path file path
  2376. * @return bool
  2377. * @author Dmitry (dio) Levashov
  2378. **/
  2379. abstract protected function _unlink($path);
  2380. /**
  2381. * Remove dir
  2382. *
  2383. * @param string $path dir path
  2384. * @return bool
  2385. * @author Dmitry (dio) Levashov
  2386. **/
  2387. abstract protected function _rmdir($path);
  2388. /**
  2389. * Create new file and write into it from file pointer.
  2390. * Return new file path or false on error.
  2391. *
  2392. * @param resource $fp file pointer
  2393. * @param string $dir target dir path
  2394. * @param string $name file name
  2395. * @return bool|string
  2396. * @author Dmitry (dio) Levashov
  2397. **/
  2398. abstract protected function _save($fp, $dir, $name);
  2399. /**
  2400. * Get file contents
  2401. *
  2402. * @param string $path file path
  2403. * @return string|false
  2404. * @author Dmitry (dio) Levashov
  2405. **/
  2406. abstract protected function _getContents($path);
  2407. /**
  2408. * Write a string to a file
  2409. *
  2410. * @param string $path file path
  2411. * @param string $content new file content
  2412. * @return bool
  2413. * @author Dmitry (dio) Levashov
  2414. **/
  2415. abstract protected function _filePutContents($path, $content);
  2416. /**
  2417. * Extract files from archive
  2418. *
  2419. * @param string $path file path
  2420. * @param array $arc archiver options
  2421. * @return bool
  2422. * @author Dmitry (dio) Levashov,
  2423. * @author Alexey Sukhotin
  2424. **/
  2425. abstract protected function _extract($path, $arc);
  2426. /**
  2427. * Create archive and return its path
  2428. *
  2429. * @param string $dir target dir
  2430. * @param array $files files names list
  2431. * @param string $name archive name
  2432. * @param array $arc archiver options
  2433. * @return string|bool
  2434. * @author Dmitry (dio) Levashov,
  2435. * @author Alexey Sukhotin
  2436. **/
  2437. abstract protected function _archive($dir, $files, $name, $arc);
  2438. /**
  2439. * Detect available archivers
  2440. *
  2441. * @return void
  2442. * @author Dmitry (dio) Levashov,
  2443. * @author Alexey Sukhotin
  2444. **/
  2445. abstract protected function _checkArchivers();
  2446. } // END class
  2447. ?>