elFinderVolumeMySQL.class.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. <?php
  2. /**
  3. * Simple elFinder driver for MySQL.
  4. *
  5. * @author Dmitry (dio) Levashov
  6. **/
  7. class elFinderVolumeMySQL extends elFinderVolumeDriver {
  8. /**
  9. * Driver id
  10. * Must be started from letter and contains [a-z0-9]
  11. * Used as part of volume id
  12. *
  13. * @var string
  14. **/
  15. protected $driverId = 'm';
  16. /**
  17. * Database object
  18. *
  19. * @var mysqli
  20. **/
  21. protected $db = null;
  22. /**
  23. * Tables to store files
  24. *
  25. * @var string
  26. **/
  27. protected $tbf = '';
  28. /**
  29. * Directory for tmp files
  30. * If not set driver will try to use tmbDir as tmpDir
  31. *
  32. * @var string
  33. **/
  34. protected $tmpPath = '';
  35. /**
  36. * Numbers of sql requests (for debug)
  37. *
  38. * @var int
  39. **/
  40. protected $sqlCnt = 0;
  41. /**
  42. * Last db error message
  43. *
  44. * @var string
  45. **/
  46. protected $dbError = '';
  47. /**
  48. * This root has parent id
  49. *
  50. * @var boolean
  51. */
  52. protected $rootHasParent = false;
  53. /**
  54. * Constructor
  55. * Extend options with required fields
  56. *
  57. * @author Dmitry (dio) Levashov
  58. */
  59. public function __construct() {
  60. $opts = array(
  61. 'host' => 'localhost',
  62. 'user' => '',
  63. 'pass' => '',
  64. 'db' => '',
  65. 'port' => null,
  66. 'socket' => null,
  67. 'files_table' => 'elfinder_file',
  68. 'tmbPath' => '',
  69. 'tmpPath' => '',
  70. 'rootCssClass' => 'elfinder-navbar-root-sql',
  71. 'noSessionCache' => array('hasdirs')
  72. );
  73. $this->options = array_merge($this->options, $opts);
  74. $this->options['mimeDetect'] = 'internal';
  75. }
  76. /*********************************************************************/
  77. /* INIT AND CONFIGURE */
  78. /*********************************************************************/
  79. /**
  80. * Prepare driver before mount volume.
  81. * Connect to db, check required tables and fetch root path
  82. *
  83. * @return bool
  84. * @author Dmitry (dio) Levashov
  85. **/
  86. protected function init() {
  87. if (!($this->options['host'] || $this->options['socket'])
  88. || !$this->options['user']
  89. || !$this->options['pass']
  90. || !$this->options['db']
  91. || !$this->options['path']
  92. || !$this->options['files_table']) {
  93. return false;
  94. }
  95. $this->db = new mysqli($this->options['host'], $this->options['user'], $this->options['pass'], $this->options['db'], $this->options['port'], $this->options['socket']);
  96. if ($this->db->connect_error || mysqli_connect_error()) {
  97. return false;
  98. }
  99. $this->db->set_charset('utf8');
  100. if ($res = $this->db->query('SHOW TABLES')) {
  101. while ($row = $res->fetch_array()) {
  102. if ($row[0] == $this->options['files_table']) {
  103. $this->tbf = $this->options['files_table'];
  104. break;
  105. }
  106. }
  107. }
  108. if (!$this->tbf) {
  109. return false;
  110. }
  111. $this->updateCache($this->options['path'], $this->_stat($this->options['path']));
  112. // enable command archive
  113. $this->options['useRemoteArchive'] = true;
  114. return true;
  115. }
  116. /**
  117. * Set tmp path
  118. *
  119. * @return void
  120. * @author Dmitry (dio) Levashov
  121. **/
  122. protected function configure() {
  123. parent::configure();
  124. if (($tmp = $this->options['tmpPath'])) {
  125. if (!file_exists($tmp)) {
  126. if (mkdir($tmp)) {
  127. chmod($tmp, $this->options['tmbPathMode']);
  128. }
  129. }
  130. $this->tmpPath = is_dir($tmp) && is_writable($tmp) ? $tmp : false;
  131. }
  132. if (!$this->tmpPath && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
  133. $this->tmpPath = $tmp;
  134. }
  135. // fallback of $this->tmp
  136. if (!$this->tmpPath && $this->tmbPathWritable) {
  137. $this->tmpPath = $this->tmbPath;
  138. }
  139. $this->mimeDetect = 'internal';
  140. }
  141. /**
  142. * Close connection
  143. *
  144. * @return void
  145. * @author Dmitry (dio) Levashov
  146. **/
  147. public function umount() {
  148. $this->db->close();
  149. }
  150. /**
  151. * Return debug info for client
  152. *
  153. * @return array
  154. * @author Dmitry (dio) Levashov
  155. **/
  156. public function debug() {
  157. $debug = parent::debug();
  158. $debug['sqlCount'] = $this->sqlCnt;
  159. if ($this->dbError) {
  160. $debug['dbError'] = $this->dbError;
  161. }
  162. return $debug;
  163. }
  164. /**
  165. * Perform sql query and return result.
  166. * Increase sqlCnt and save error if occured
  167. *
  168. * @param string $sql query
  169. * @return misc
  170. * @author Dmitry (dio) Levashov
  171. **/
  172. protected function query($sql) {
  173. $this->sqlCnt++;
  174. $res = $this->db->query($sql);
  175. if (!$res) {
  176. $this->dbError = $this->db->error;
  177. }
  178. return $res;
  179. }
  180. /**
  181. * Create empty object with required mimetype
  182. *
  183. * @param string $path parent dir path
  184. * @param string $name object name
  185. * @param string $mime mime type
  186. * @return bool
  187. * @author Dmitry (dio) Levashov
  188. **/
  189. protected function make($path, $name, $mime) {
  190. $sql = 'INSERT INTO %s (`parent_id`, `name`, `size`, `mtime`, `mime`, `content`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES (\'%s\', \'%s\', 0, %d, \'%s\', \'\', \'%d\', \'%d\', \'%d\', \'%d\', 0, 0)';
  191. $sql = sprintf($sql, $this->tbf, $path, $this->db->real_escape_string($name), time(), $mime, $this->defaults['read'], $this->defaults['write'], $this->defaults['locked'], $this->defaults['hidden']);
  192. // echo $sql;
  193. return $this->query($sql) && $this->db->affected_rows > 0;
  194. }
  195. /*********************************************************************/
  196. /* FS API */
  197. /*********************************************************************/
  198. /**
  199. * Cache dir contents
  200. *
  201. * @param string $path dir path
  202. * @return string
  203. * @author Dmitry Levashov
  204. **/
  205. protected function cacheDir($path) {
  206. $this->dirsCache[$path] = array();
  207. $sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, IF(ch.id, 1, 0) AS dirs
  208. FROM '.$this->tbf.' AS f
  209. LEFT JOIN '.$this->tbf.' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
  210. WHERE f.parent_id=\''.$path.'\'
  211. GROUP BY f.id, ch.id';
  212. $res = $this->query($sql);
  213. if ($res) {
  214. while ($row = $res->fetch_assoc()) {
  215. $id = $row['id'];
  216. if ($row['parent_id'] && $id != $this->root) {
  217. $row['phash'] = $this->encode($row['parent_id']);
  218. }
  219. if ($row['mime'] == 'directory') {
  220. unset($row['width']);
  221. unset($row['height']);
  222. $row['size'] = 0;
  223. } else {
  224. unset($row['dirs']);
  225. }
  226. unset($row['id']);
  227. unset($row['parent_id']);
  228. if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) {
  229. $this->dirsCache[$path][] = $id;
  230. }
  231. }
  232. }
  233. return $this->dirsCache[$path];
  234. }
  235. /**
  236. * Return array of parents paths (ids)
  237. *
  238. * @param int $path file path (id)
  239. * @return array
  240. * @author Dmitry (dio) Levashov
  241. **/
  242. protected function getParents($path) {
  243. $parents = array();
  244. while ($path) {
  245. if ($file = $this->stat($path)) {
  246. array_unshift($parents, $path);
  247. $path = isset($file['phash']) ? $this->decode($file['phash']) : false;
  248. }
  249. }
  250. if (count($parents)) {
  251. array_pop($parents);
  252. }
  253. return $parents;
  254. }
  255. /**
  256. * Return correct file path for LOAD_FILE method
  257. *
  258. * @param string $path file path (id)
  259. * @return string
  260. * @author Troex Nevelin
  261. **/
  262. protected function loadFilePath($path) {
  263. $realPath = realpath($path);
  264. if (DIRECTORY_SEPARATOR == '\\') { // windows
  265. $realPath = str_replace('\\', '\\\\', $realPath);
  266. }
  267. return $this->db->real_escape_string($realPath);
  268. }
  269. /**
  270. * Recursive files search
  271. *
  272. * @param string $path dir path
  273. * @param string $q search string
  274. * @param array $mimes
  275. * @return array
  276. * @author Dmitry (dio) Levashov
  277. **/
  278. protected function doSearch($path, $q, $mimes) {
  279. if (!empty($this->doSearchCurrentQuery['matchMethod'])) {
  280. // has custom match method use elFinderVolumeDriver::doSearch()
  281. return parent::doSearch($path, $q, $mimes);
  282. }
  283. $dirs = array();
  284. $timeout = $this->options['searchTimeout']? $this->searchStart + $this->options['searchTimeout'] : 0;
  285. if ($path != $this->root || $this->rootHasParent) {
  286. $dirs = $inpath = array(intval($path));
  287. while($inpath) {
  288. $in = '('.join(',', $inpath).')';
  289. $inpath = array();
  290. $sql = 'SELECT f.id FROM %s AS f WHERE f.parent_id IN '.$in.' AND `mime` = \'directory\'';
  291. $sql = sprintf($sql, $this->tbf);
  292. if ($res = $this->query($sql)) {
  293. $_dir = array();
  294. while ($dat = $res->fetch_assoc()) {
  295. $inpath[] = $dat['id'];
  296. }
  297. $dirs = array_merge($dirs, $inpath);
  298. }
  299. }
  300. }
  301. $result = array();
  302. if ($mimes) {
  303. $whrs = array();
  304. foreach($mimes as $mime) {
  305. if (strpos($mime, '/') === false) {
  306. $whrs[] = sprintf('f.mime LIKE \'%s/%%\'', $this->db->real_escape_string($mime));
  307. } else {
  308. $whrs[] = sprintf('f.mime = \'%s\'', $this->db->real_escape_string($mime));
  309. }
  310. }
  311. $whr = join(' OR ', $whrs);
  312. } else {
  313. $whr = sprintf('f.name LIKE \'%%%s%%\'', $this->db->real_escape_string($q));
  314. }
  315. if ($dirs) {
  316. $whr = '(' . $whr . ') AND (`parent_id` IN (' . join(',', $dirs) . '))';
  317. }
  318. $sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, 0 AS dirs
  319. FROM %s AS f
  320. WHERE %s';
  321. $sql = sprintf($sql, $this->tbf, $whr);
  322. if (($res = $this->query($sql))) {
  323. while ($row = $res->fetch_assoc()) {
  324. if ($timeout && $timeout < time()) {
  325. $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
  326. break;
  327. }
  328. if (!$this->mimeAccepted($row['mime'], $mimes)) {
  329. continue;
  330. }
  331. $id = $row['id'];
  332. if ($id == $this->root) {
  333. continue;
  334. }
  335. if ($row['parent_id'] && $id != $this->root) {
  336. $row['phash'] = $this->encode($row['parent_id']);
  337. }
  338. $row['path'] = $this->_path($id);
  339. if ($row['mime'] == 'directory') {
  340. unset($row['width']);
  341. unset($row['height']);
  342. } else {
  343. unset($row['dirs']);
  344. }
  345. unset($row['id']);
  346. unset($row['parent_id']);
  347. if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) {
  348. $result[] = $stat;
  349. }
  350. }
  351. }
  352. return $result;
  353. }
  354. /*********************** paths/urls *************************/
  355. /**
  356. * Return parent directory path
  357. *
  358. * @param string $path file path
  359. * @return string
  360. * @author Dmitry (dio) Levashov
  361. **/
  362. protected function _dirname($path) {
  363. return ($stat = $this->stat($path)) ? (!empty($stat['phash']) ? $this->decode($stat['phash']) : $this->root) : false;
  364. }
  365. /**
  366. * Return file name
  367. *
  368. * @param string $path file path
  369. * @return string
  370. * @author Dmitry (dio) Levashov
  371. **/
  372. protected function _basename($path) {
  373. return ($stat = $this->stat($path)) ? $stat['name'] : false;
  374. }
  375. /**
  376. * Join dir name and file name and return full path
  377. *
  378. * @param string $dir
  379. * @param string $name
  380. * @return string
  381. * @author Dmitry (dio) Levashov
  382. **/
  383. protected function _joinPath($dir, $name) {
  384. $sql = 'SELECT id FROM '.$this->tbf.' WHERE parent_id=\''.$dir.'\' AND name=\''.$this->db->real_escape_string($name).'\'';
  385. if (($res = $this->query($sql)) && ($r = $res->fetch_assoc())) {
  386. $this->updateCache($r['id'], $this->_stat($r['id']));
  387. return $r['id'];
  388. }
  389. return -1;
  390. }
  391. /**
  392. * Return normalized path, this works the same as os.path.normpath() in Python
  393. *
  394. * @param string $path path
  395. * @return string
  396. * @author Troex Nevelin
  397. **/
  398. protected function _normpath($path) {
  399. return $path;
  400. }
  401. /**
  402. * Return file path related to root dir
  403. *
  404. * @param string $path file path
  405. * @return string
  406. * @author Dmitry (dio) Levashov
  407. **/
  408. protected function _relpath($path) {
  409. return $path;
  410. }
  411. /**
  412. * Convert path related to root dir into real path
  413. *
  414. * @param string $path file path
  415. * @return string
  416. * @author Dmitry (dio) Levashov
  417. **/
  418. protected function _abspath($path) {
  419. return $path;
  420. }
  421. /**
  422. * Return fake path started from root dir
  423. *
  424. * @param string $path file path
  425. * @return string
  426. * @author Dmitry (dio) Levashov
  427. **/
  428. protected function _path($path) {
  429. if (($file = $this->stat($path)) == false) {
  430. return '';
  431. }
  432. $parentsIds = $this->getParents($path);
  433. $path = '';
  434. foreach ($parentsIds as $id) {
  435. $dir = $this->stat($id);
  436. $path .= $dir['name'].$this->separator;
  437. }
  438. return $path.$file['name'];
  439. }
  440. /**
  441. * Return true if $path is children of $parent
  442. *
  443. * @param string $path path to check
  444. * @param string $parent parent path
  445. * @return bool
  446. * @author Dmitry (dio) Levashov
  447. **/
  448. protected function _inpath($path, $parent) {
  449. return $path == $parent
  450. ? true
  451. : in_array($parent, $this->getParents($path));
  452. }
  453. /***************** file stat ********************/
  454. /**
  455. * Return stat for given path.
  456. * Stat contains following fields:
  457. * - (int) size file size in b. required
  458. * - (int) ts file modification time in unix time. required
  459. * - (string) mime mimetype. required for folders, others - optionally
  460. * - (bool) read read permissions. required
  461. * - (bool) write write permissions. required
  462. * - (bool) locked is object locked. optionally
  463. * - (bool) hidden is object hidden. optionally
  464. * - (string) alias for symlinks - link target path relative to root path. optionally
  465. * - (string) target for symlinks - link target path. optionally
  466. *
  467. * If file does not exists - returns empty array or false.
  468. *
  469. * @param string $path file path
  470. * @return array|false
  471. * @author Dmitry (dio) Levashov
  472. **/
  473. protected function _stat($path) {
  474. $sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, IF(ch.id, 1, 0) AS dirs
  475. FROM '.$this->tbf.' AS f
  476. LEFT JOIN '.$this->tbf.' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
  477. WHERE f.id=\''.$path.'\'
  478. GROUP BY f.id, ch.id';
  479. $res = $this->query($sql);
  480. if ($res) {
  481. $stat = $res->fetch_assoc();
  482. if ($stat['id'] == $this->root) {
  483. $this->rootHasParent = true;
  484. $stat['parent_id'] = '';
  485. }
  486. if ($stat['parent_id']) {
  487. $stat['phash'] = $this->encode($stat['parent_id']);
  488. }
  489. if ($stat['mime'] == 'directory') {
  490. unset($stat['width']);
  491. unset($stat['height']);
  492. $stat['size'] = 0;
  493. } else {
  494. if (!$stat['mime']) {
  495. unset($stat['mime']);
  496. }
  497. unset($stat['dirs']);
  498. }
  499. unset($stat['id']);
  500. unset($stat['parent_id']);
  501. return $stat;
  502. }
  503. return array();
  504. }
  505. /**
  506. * Return true if path is dir and has at least one childs directory
  507. *
  508. * @param string $path dir path
  509. * @return bool
  510. * @author Dmitry (dio) Levashov
  511. **/
  512. protected function _subdirs($path) {
  513. return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
  514. }
  515. /**
  516. * Return object width and height
  517. * Usualy used for images, but can be realize for video etc...
  518. *
  519. * @param string $path file path
  520. * @param string $mime file mime type
  521. * @return string
  522. * @author Dmitry (dio) Levashov
  523. **/
  524. protected function _dimensions($path, $mime) {
  525. return ($stat = $this->stat($path)) && isset($stat['width']) && isset($stat['height']) ? $stat['width'].'x'.$stat['height'] : '';
  526. }
  527. /******************** file/dir content *********************/
  528. /**
  529. * Return files list in directory.
  530. *
  531. * @param string $path dir path
  532. * @return array
  533. * @author Dmitry (dio) Levashov
  534. **/
  535. protected function _scandir($path) {
  536. return isset($this->dirsCache[$path])
  537. ? $this->dirsCache[$path]
  538. : $this->cacheDir($path);
  539. }
  540. /**
  541. * Open file and return file pointer
  542. *
  543. * @param string $path file path
  544. * @param string $mode open file mode (ignored in this driver)
  545. * @return resource|false
  546. * @author Dmitry (dio) Levashov
  547. **/
  548. protected function _fopen($path, $mode='rb') {
  549. $fp = $this->tmbPath
  550. ? fopen($this->getTempFile($path), 'w+')
  551. : $this->tmpfile();
  552. if ($fp) {
  553. if (($res = $this->query('SELECT content FROM '.$this->tbf.' WHERE id=\''.$path.'\''))
  554. && ($r = $res->fetch_assoc())) {
  555. fwrite($fp, $r['content']);
  556. rewind($fp);
  557. return $fp;
  558. } else {
  559. $this->_fclose($fp, $path);
  560. }
  561. }
  562. return false;
  563. }
  564. /**
  565. * Close opened file
  566. *
  567. * @param resource $fp file pointer
  568. * @param string $path
  569. * @return bool
  570. * @author Dmitry (dio) Levashov
  571. */
  572. protected function _fclose($fp, $path='') {
  573. is_resource($fp) && fclose($fp);
  574. if ($path) {
  575. $file = $this->getTempFile($path);
  576. is_file($file) && unlink($file);
  577. }
  578. }
  579. /******************** file/dir manipulations *************************/
  580. /**
  581. * Create dir and return created dir path or false on failed
  582. *
  583. * @param string $path parent dir path
  584. * @param string $name new directory name
  585. * @return string|bool
  586. * @author Dmitry (dio) Levashov
  587. **/
  588. protected function _mkdir($path, $name) {
  589. return $this->make($path, $name, 'directory') ? $this->_joinPath($path, $name) : false;
  590. }
  591. /**
  592. * Create file and return it's path or false on failed
  593. *
  594. * @param string $path parent dir path
  595. * @param string $name new file name
  596. * @return string|bool
  597. * @author Dmitry (dio) Levashov
  598. **/
  599. protected function _mkfile($path, $name) {
  600. return $this->make($path, $name, '') ? $this->_joinPath($path, $name) : false;
  601. }
  602. /**
  603. * Create symlink. FTP driver does not support symlinks.
  604. *
  605. * @param string $target link target
  606. * @param string $path symlink path
  607. * @param string $name
  608. * @return bool
  609. * @author Dmitry (dio) Levashov
  610. */
  611. protected function _symlink($target, $path, $name) {
  612. return false;
  613. }
  614. /**
  615. * Copy file into another file
  616. *
  617. * @param string $source source file path
  618. * @param string $targetDir target directory path
  619. * @param string $name new file name
  620. * @return bool
  621. * @author Dmitry (dio) Levashov
  622. **/
  623. protected function _copy($source, $targetDir, $name) {
  624. $this->clearcache();
  625. $id = $this->_joinPath($targetDir, $name);
  626. $sql = $id > 0
  627. ? sprintf('REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height, `read`, `write`, `locked`, `hidden`) (SELECT %d, %d, name, content, size, mtime, mime, width, height, `read`, `write`, `locked`, `hidden` FROM %s WHERE id=%d)', $this->tbf, $id, $this->_dirname($id), $this->tbf, $source)
  628. : sprintf('INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height, `read`, `write`, `locked`, `hidden`) SELECT %d, \'%s\', content, size, %d, mime, width, height, `read`, `write`, `locked`, `hidden` FROM %s WHERE id=%d', $this->tbf, $targetDir, $this->db->real_escape_string($name), time(), $this->tbf, $source);
  629. return $this->query($sql);
  630. }
  631. /**
  632. * Move file into another parent dir.
  633. * Return new file path or false.
  634. *
  635. * @param string $source source file path
  636. * @param $targetDir
  637. * @param string $name file name
  638. * @return bool|string
  639. * @internal param string $target target dir path
  640. * @author Dmitry (dio) Levashov
  641. */
  642. protected function _move($source, $targetDir, $name) {
  643. $sql = 'UPDATE %s SET parent_id=%d, name=\'%s\' WHERE id=%d LIMIT 1';
  644. $sql = sprintf($sql, $this->tbf, $targetDir, $this->db->real_escape_string($name), $source);
  645. return $this->query($sql) && $this->db->affected_rows > 0 ? $source : false;
  646. }
  647. /**
  648. * Remove file
  649. *
  650. * @param string $path file path
  651. * @return bool
  652. * @author Dmitry (dio) Levashov
  653. **/
  654. protected function _unlink($path) {
  655. return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime!=\'directory\' LIMIT 1', $this->tbf, $path)) && $this->db->affected_rows;
  656. }
  657. /**
  658. * Remove dir
  659. *
  660. * @param string $path dir path
  661. * @return bool
  662. * @author Dmitry (dio) Levashov
  663. **/
  664. protected function _rmdir($path) {
  665. return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime=\'directory\' LIMIT 1', $this->tbf, $path)) && $this->db->affected_rows;
  666. }
  667. /**
  668. * undocumented function
  669. *
  670. * @param $path
  671. * @param $fp
  672. * @author Dmitry Levashov
  673. */
  674. protected function _setContent($path, $fp) {
  675. elFinder::rewind($fp);
  676. $fstat = fstat($fp);
  677. $size = $fstat['size'];
  678. }
  679. /**
  680. * Create new file and write into it from file pointer.
  681. * Return new file path or false on error.
  682. *
  683. * @param resource $fp file pointer
  684. * @param string $dir target dir path
  685. * @param string $name file name
  686. * @param array $stat file stat (required by some virtual fs)
  687. * @return bool|string
  688. * @author Dmitry (dio) Levashov
  689. **/
  690. protected function _save($fp, $dir, $name, $stat) {
  691. $this->clearcache();
  692. $mime = $stat['mime'];
  693. $w = !empty($stat['width']) ? $stat['width'] : 0;
  694. $h = !empty($stat['height']) ? $stat['height'] : 0;
  695. $id = $this->_joinPath($dir, $name);
  696. elFinder::rewind($fp);
  697. $stat = fstat($fp);
  698. $size = $stat['size'];
  699. if (($tmpfile = tempnam($this->tmpPath, $this->id))) {
  700. if (($trgfp = fopen($tmpfile, 'wb')) == false) {
  701. unlink($tmpfile);
  702. } else {
  703. while (!feof($fp)) {
  704. fwrite($trgfp, fread($fp, 8192));
  705. }
  706. fclose($trgfp);
  707. chmod($tmpfile, 0644);
  708. $sql = $id > 0
  709. ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES ('.$id.', %d, \'%s\', LOAD_FILE(\'%s\'), %d, %d, \'%s\', %d, %d)'
  710. : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (%d, \'%s\', LOAD_FILE(\'%s\'), %d, %d, \'%s\', %d, %d)';
  711. $sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->loadFilePath($tmpfile), $size, time(), $mime, $w, $h);
  712. $res = $this->query($sql);
  713. unlink($tmpfile);
  714. if ($res) {
  715. return $id > 0 ? $id : $this->db->insert_id;
  716. }
  717. }
  718. }
  719. $content = '';
  720. elFinder::rewind($fp);
  721. while (!feof($fp)) {
  722. $content .= fread($fp, 8192);
  723. }
  724. $sql = $id > 0
  725. ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES ('.$id.', %d, \'%s\', \'%s\', %d, %d, \'%s\', %d, %d)'
  726. : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (%d, \'%s\', \'%s\', %d, %d, \'%s\', %d, %d)';
  727. $sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->db->real_escape_string($content), $size, time(), $mime, $w, $h);
  728. unset($content);
  729. if ($this->query($sql)) {
  730. return $id > 0 ? $id : $this->db->insert_id;
  731. }
  732. return false;
  733. }
  734. /**
  735. * Get file contents
  736. *
  737. * @param string $path file path
  738. * @return string|false
  739. * @author Dmitry (dio) Levashov
  740. **/
  741. protected function _getContents($path) {
  742. return ($res = $this->query(sprintf('SELECT content FROM %s WHERE id=%d', $this->tbf, $path))) && ($r = $res->fetch_assoc()) ? $r['content'] : false;
  743. }
  744. /**
  745. * Write a string to a file
  746. *
  747. * @param string $path file path
  748. * @param string $content new file content
  749. * @return bool
  750. * @author Dmitry (dio) Levashov
  751. **/
  752. protected function _filePutContents($path, $content) {
  753. return $this->query(sprintf('UPDATE %s SET content=\'%s\', size=%d, mtime=%d WHERE id=%d LIMIT 1', $this->tbf, $this->db->real_escape_string($content), strlen($content), time(), $path));
  754. }
  755. /**
  756. * Detect available archivers
  757. *
  758. * @return void
  759. **/
  760. protected function _checkArchivers() {
  761. return;
  762. }
  763. /**
  764. * chmod implementation
  765. *
  766. * @param string $path
  767. * @param string $mode
  768. * @return bool
  769. */
  770. protected function _chmod($path, $mode) {
  771. return false;
  772. }
  773. /**
  774. * Unpack archive
  775. *
  776. * @param string $path archive path
  777. * @param array $arc archiver command and arguments (same as in $this->archivers)
  778. * @return void
  779. * @author Dmitry (dio) Levashov
  780. * @author Alexey Sukhotin
  781. **/
  782. protected function _unpack($path, $arc) {
  783. return;
  784. }
  785. /**
  786. * Recursive symlinks search
  787. *
  788. * @param string $path file/dir path
  789. * @return bool
  790. * @author Dmitry (dio) Levashov
  791. **/
  792. protected function _findSymlinks($path) {
  793. return false;
  794. }
  795. /**
  796. * Extract files from archive
  797. *
  798. * @param string $path archive path
  799. * @param array $arc archiver command and arguments (same as in $this->archivers)
  800. * @return true
  801. * @author Dmitry (dio) Levashov,
  802. * @author Alexey Sukhotin
  803. **/
  804. protected function _extract($path, $arc) {
  805. return false;
  806. }
  807. /**
  808. * Create archive and return its path
  809. *
  810. * @param string $dir target dir
  811. * @param array $files files names list
  812. * @param string $name archive name
  813. * @param array $arc archiver options
  814. * @return string|bool
  815. * @author Dmitry (dio) Levashov,
  816. * @author Alexey Sukhotin
  817. **/
  818. protected function _archive($dir, $files, $name, $arc) {
  819. return false;
  820. }
  821. } // END class