PluginProbe ʕ •ᴥ•ʔ
File Manager Pro – Filester / 2.1.3
File Manager Pro – Filester v2.1.3
2.1.3 2.1.2 2.1.1 trunk 1.6.1 1.7.6 1.8 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 2.0 2.0.1 2.0.2 2.1.0
filester / includes / File_manager / lib / php / elFinderVolumeMySQL.class.php
filester / includes / File_manager / lib / php Last commit date
.tmp 18 hours ago editors 18 hours ago libs 18 hours ago plugins 18 hours ago resources 18 hours ago MySQLStorage.sql 18 hours ago autoload.php 18 hours ago elFinder.class.php 18 hours ago elFinderConnector.class.php 18 hours ago elFinderFlysystemGoogleDriveNetmount.php 18 hours ago elFinderPlugin.php 18 hours ago elFinderSession.php 18 hours ago elFinderSessionInterface.php 18 hours ago elFinderVolumeBox.class.php 18 hours ago elFinderVolumeDriver.class.php 18 hours ago elFinderVolumeDropbox.class.php 18 hours ago elFinderVolumeDropbox2.class.php 18 hours ago elFinderVolumeFTP.class.php 18 hours ago elFinderVolumeGoogleDrive.class.php 18 hours ago elFinderVolumeGroup.class.php 18 hours ago elFinderVolumeLocalFileSystem.class.php 18 hours ago elFinderVolumeMySQL.class.php 18 hours ago elFinderVolumeOneDrive.class.php 18 hours ago elFinderVolumeSFTPphpseclib.class.php 18 hours ago elFinderVolumeTrash.class.php 18 hours ago elFinderVolumeTrashMySQL.class.php 18 hours ago mime.types 18 hours ago
elFinderVolumeMySQL.class.php
1150 lines
1 <?php
2
3 /**
4 * Simple elFinder driver for MySQL.
5 *
6 * @author Dmitry (dio) Levashov
7 **/
8 class elFinderVolumeMySQL extends elFinderVolumeDriver
9 {
10
11 /**
12 * Driver id
13 * Must be started from letter and contains [a-z0-9]
14 * Used as part of volume id
15 *
16 * @var string
17 **/
18 protected $driverId = 'm';
19
20 /**
21 * Database object
22 *
23 * @var mysqli
24 **/
25 protected $db = null;
26
27 /**
28 * Tables to store files
29 *
30 * @var string
31 **/
32 protected $tbf = '';
33
34 /**
35 * Directory for tmp files
36 * If not set driver will try to use tmbDir as tmpDir
37 *
38 * @var string
39 **/
40 protected $tmpPath = '';
41
42 /**
43 * Numbers of sql requests (for debug)
44 *
45 * @var int
46 **/
47 protected $sqlCnt = 0;
48
49 /**
50 * Last db error message
51 *
52 * @var string
53 **/
54 protected $dbError = '';
55
56 /**
57 * This root has parent id
58 *
59 * @var boolean
60 */
61 protected $rootHasParent = false;
62
63 /**
64 * Constructor
65 * Extend options with required fields
66 *
67 * @author Dmitry (dio) Levashov
68 */
69 public function __construct()
70 {
71 $opts = array(
72 'host' => 'localhost',
73 'user' => '',
74 'pass' => '',
75 'db' => '',
76 'port' => null,
77 'socket' => null,
78 'files_table' => 'elfinder_file',
79 'tmbPath' => '',
80 'tmpPath' => '',
81 'rootCssClass' => 'elfinder-navbar-root-sql',
82 'noSessionCache' => array('hasdirs'),
83 'isLocalhost' => false
84 );
85 $this->options = array_merge($this->options, $opts);
86 $this->options['mimeDetect'] = 'internal';
87 }
88
89 /*********************************************************************/
90 /* INIT AND CONFIGURE */
91 /*********************************************************************/
92
93 /**
94 * Prepare driver before mount volume.
95 * Connect to db, check required tables and fetch root path
96 *
97 * @return bool
98 * @author Dmitry (dio) Levashov
99 **/
100 protected function init()
101 {
102
103 if (!($this->options['host'] || $this->options['socket'])
104 || !$this->options['user']
105 || !$this->options['pass']
106 || !$this->options['db']
107 || !$this->options['path']
108 || !$this->options['files_table']) {
109 return $this->setError('Required options "host", "socket", "user", "pass", "db", "path" or "files_table" are undefined.');
110 }
111
112 $err = null;
113 if ($this->db = @new mysqli($this->options['host'], $this->options['user'], $this->options['pass'], $this->options['db'], $this->options['port'], $this->options['socket'])) {
114 if ($this->db && $this->db->connect_error) {
115 $err = $this->db->connect_error;
116 }
117 } else {
118 $err = mysqli_connect_error();
119 }
120 if ($err) {
121 return $this->setError(array('Unable to connect to MySQL server.', $err));
122 }
123
124 if (!$this->needOnline && empty($this->ARGS['init'])) {
125 $this->db->close();
126 $this->db = null;
127 return true;
128 }
129
130 $this->db->set_charset('utf8');
131
132 if ($res = $this->db->query('SHOW TABLES')) {
133 while ($row = $res->fetch_array()) {
134 if ($row[0] == $this->options['files_table']) {
135 $this->tbf = $this->options['files_table'];
136 break;
137 }
138 }
139 }
140
141 if (!$this->tbf) {
142 return $this->setError('The specified database table cannot be found.');
143 }
144
145 if (($root = $this->normalizePathId($this->options['path'])) === null) {
146 return $this->setError('The MySQL volume root path must be a numeric object id.');
147 }
148 $this->options['path'] = $root;
149
150 $this->updateCache($this->options['path'], $this->_stat($this->options['path']));
151
152 // enable command archive
153 $this->options['useRemoteArchive'] = true;
154
155 // check isLocalhost
156 $this->isLocalhost = $this->options['isLocalhost'] || $this->options['host'] === 'localhost' || $this->options['host'] === '127.0.0.1' || $this->options['host'] === '::1';
157
158 return true;
159 }
160
161
162 /**
163 * Set tmp path
164 *
165 * @return void
166 * @throws elFinderAbortException
167 * @author Dmitry (dio) Levashov
168 */
169 protected function configure()
170 {
171 parent::configure();
172
173 if (($tmp = $this->options['tmpPath'])) {
174 if (!file_exists($tmp)) {
175 if (mkdir($tmp)) {
176 chmod($tmp, $this->options['tmbPathMode']);
177 }
178 }
179
180 $this->tmpPath = is_dir($tmp) && is_writable($tmp) ? $tmp : false;
181 }
182 if (!$this->tmpPath && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
183 $this->tmpPath = $tmp;
184 }
185
186 // fallback of $this->tmp
187 if (!$this->tmpPath && $this->tmbPathWritable) {
188 $this->tmpPath = $this->tmbPath;
189 }
190
191 $this->mimeDetect = 'internal';
192 }
193
194 /**
195 * Close connection
196 *
197 * @return void
198 * @author Dmitry (dio) Levashov
199 **/
200 public function umount()
201 {
202 $this->db && $this->db->close();
203 }
204
205 /**
206 * Return debug info for client
207 *
208 * @return array
209 * @author Dmitry (dio) Levashov
210 **/
211 public function debug()
212 {
213 $debug = parent::debug();
214 $debug['sqlCount'] = $this->sqlCnt;
215 if ($this->dbError) {
216 $debug['dbError'] = $this->dbError;
217 }
218 return $debug;
219 }
220
221 /**
222 * Perform sql query and return result.
223 * Increase sqlCnt and save error if occured
224 *
225 * @param string $sql query
226 *
227 * @return bool|mysqli_result
228 * @author Dmitry (dio) Levashov
229 */
230 protected function query($sql)
231 {
232 $this->sqlCnt++;
233 $res = $this->db->query($sql);
234 if (!$res) {
235 $this->dbError = $this->db->error;
236 }
237 return $res;
238 }
239
240 /**
241 * Perform sql prepared statement and return result.
242 * Increase sqlCnt and save error if occurred.
243 *
244 * @param mysqli_stmt $stmt
245 * @return bool
246 */
247 protected function execute($stmt)
248 {
249 $this->sqlCnt++;
250 $res = $stmt->execute();
251 if (!$res) {
252 $this->dbError = $this->db->error;
253 }
254 return $res;
255 }
256
257 /**
258 * Normalize a filesystem path into the numeric MySQL object id used by this driver.
259 *
260 * @param mixed $path
261 * @return string|null
262 */
263 protected function normalizePathId($path)
264 {
265 if (is_int($path)) {
266 return $path >= 0 ? (string)$path : null;
267 }
268
269 if (is_string($path) && ctype_digit($path)) {
270 return (string)(int)$path;
271 }
272
273 return null;
274 }
275
276 /**
277 * Return normalized numeric object id for SQL usage.
278 *
279 * @param mixed $path
280 * @return int|null
281 */
282 protected function pathId($path)
283 {
284 $path = $this->normalizePathId($path);
285
286 return $path === null ? null : (int)$path;
287 }
288
289 /**
290 * Decode path from hash and reject non-numeric ids for the MySQL driver.
291 *
292 * @param string $hash file hash
293 * @return string
294 */
295 protected function decode($hash)
296 {
297 $path = parent::decode($hash);
298
299 if ($path === '') {
300 return '';
301 }
302
303 $path = $this->normalizePathId($path);
304
305 return $path === null ? '' : $path;
306 }
307
308 /**
309 * Create empty object with required mimetype
310 *
311 * @param string $path parent dir path
312 * @param string $name object name
313 * @param string $mime mime type
314 *
315 * @return bool
316 * @author Dmitry (dio) Levashov
317 **/
318 protected function make($path, $name, $mime)
319 {
320 if (($parentId = $this->pathId($path)) === null) {
321 return false;
322 }
323
324 $sql = 'INSERT INTO %s (`parent_id`, `name`, `size`, `mtime`, `mime`, `content`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES (%d, \'%s\', 0, %d, \'%s\', \'\', \'%d\', \'%d\', \'%d\', \'%d\', 0, 0)';
325 $sql = sprintf($sql, $this->tbf, $parentId, $this->db->real_escape_string($name), time(), $this->db->real_escape_string($mime), $this->defaults['read'], $this->defaults['write'], $this->defaults['locked'], $this->defaults['hidden']);
326 // echo $sql;
327 return $this->query($sql) && $this->db->affected_rows > 0;
328 }
329
330 /*********************************************************************/
331 /* FS API */
332 /*********************************************************************/
333
334 /**
335 * Cache dir contents
336 *
337 * @param string $path dir path
338 *
339 * @return string
340 * @author Dmitry Levashov
341 **/
342 protected function cacheDir($path)
343 {
344 $this->dirsCache[$path] = array();
345
346 if (($parentId = $this->pathId($path)) === null) {
347 return $this->dirsCache[$path];
348 }
349
350 $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
351 FROM ' . $this->tbf . ' AS f
352 LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
353 WHERE f.parent_id=%d
354 GROUP BY f.id, ch.id';
355 $sql = sprintf($sql, $parentId);
356
357 $res = $this->query($sql);
358 if ($res) {
359 while ($row = $res->fetch_assoc()) {
360 $id = $row['id'];
361 if ($row['parent_id'] && $id != $this->root) {
362 $row['phash'] = $this->encode($row['parent_id']);
363 }
364
365 if ($row['mime'] == 'directory') {
366 unset($row['width']);
367 unset($row['height']);
368 $row['size'] = 0;
369 } else {
370 unset($row['dirs']);
371 }
372
373 unset($row['id']);
374 unset($row['parent_id']);
375
376
377 if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) {
378 $this->dirsCache[$path][] = $id;
379 }
380 }
381 }
382
383 return $this->dirsCache[$path];
384 }
385
386 /**
387 * Return array of parents paths (ids)
388 *
389 * @param int $path file path (id)
390 *
391 * @return array
392 * @author Dmitry (dio) Levashov
393 **/
394 protected function getParents($path)
395 {
396 $parents = array();
397
398 while ($path) {
399 if ($file = $this->stat($path)) {
400 array_unshift($parents, $path);
401 $path = isset($file['phash']) ? $this->decode($file['phash']) : false;
402 }
403 }
404
405 if (count($parents)) {
406 array_pop($parents);
407 }
408 return $parents;
409 }
410
411 /**
412 * Return correct file path for LOAD_FILE method
413 *
414 * @param string $path file path (id)
415 *
416 * @return string
417 * @author Troex Nevelin
418 **/
419 protected function loadFilePath($path)
420 {
421 $realPath = realpath($path);
422 if (DIRECTORY_SEPARATOR == '\\') { // windows
423 $realPath = str_replace('\\', '\\\\', $realPath);
424 }
425 return $this->db->real_escape_string($realPath);
426 }
427
428 /**
429 * Recursive files search
430 *
431 * @param string $path dir path
432 * @param string $q search string
433 * @param array $mimes
434 *
435 * @return array
436 * @throws elFinderAbortException
437 * @author Dmitry (dio) Levashov
438 */
439 protected function doSearch($path, $q, $mimes)
440 {
441 if (!empty($this->doSearchCurrentQuery['matchMethod'])) {
442 // has custom match method use elFinderVolumeDriver::doSearch()
443 return parent::doSearch($path, $q, $mimes);
444 }
445
446 $dirs = array();
447 $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
448
449 if ($path != $this->root || $this->rootHasParent) {
450 $dirs = $inpath = array(intval($path));
451 while ($inpath) {
452 $in = '(' . join(',', $inpath) . ')';
453 $inpath = array();
454 $sql = 'SELECT f.id FROM %s AS f WHERE f.parent_id IN ' . $in . ' AND `mime` = \'directory\'';
455 $sql = sprintf($sql, $this->tbf);
456 if ($res = $this->query($sql)) {
457 $_dir = array();
458 while ($dat = $res->fetch_assoc()) {
459 $inpath[] = $dat['id'];
460 }
461 $dirs = array_merge($dirs, $inpath);
462 }
463 }
464 }
465
466 $result = array();
467
468 if ($mimes) {
469 $whrs = array();
470 foreach ($mimes as $mime) {
471 if (strpos($mime, '/') === false) {
472 $whrs[] = sprintf('f.mime LIKE \'%s/%%\'', $this->db->real_escape_string($mime));
473 } else {
474 $whrs[] = sprintf('f.mime = \'%s\'', $this->db->real_escape_string($mime));
475 }
476 }
477 $whr = join(' OR ', $whrs);
478 } else {
479 $whr = sprintf('f.name LIKE \'%%%s%%\'', $this->db->real_escape_string($q));
480 }
481 if ($dirs) {
482 $whr = '(' . $whr . ') AND (`parent_id` IN (' . join(',', $dirs) . '))';
483 }
484
485 $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
486 FROM %s AS f
487 WHERE %s';
488
489 $sql = sprintf($sql, $this->tbf, $whr);
490
491 if (($res = $this->query($sql))) {
492 while ($row = $res->fetch_assoc()) {
493 if ($timeout && $timeout < time()) {
494 $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
495 break;
496 }
497
498 if (!$this->mimeAccepted($row['mime'], $mimes)) {
499 continue;
500 }
501 $id = $row['id'];
502 if ($id == $this->root) {
503 continue;
504 }
505 if ($row['parent_id'] && $id != $this->root) {
506 $row['phash'] = $this->encode($row['parent_id']);
507 }
508 $row['path'] = $this->_path($id);
509
510 if ($row['mime'] == 'directory') {
511 unset($row['width']);
512 unset($row['height']);
513 } else {
514 unset($row['dirs']);
515 }
516
517 unset($row['id']);
518 unset($row['parent_id']);
519
520 if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) {
521 $result[] = $stat;
522 }
523 }
524 }
525 return $result;
526 }
527
528
529 /*********************** paths/urls *************************/
530
531 /**
532 * Return parent directory path
533 *
534 * @param string $path file path
535 *
536 * @return string
537 * @author Dmitry (dio) Levashov
538 **/
539 protected function _dirname($path)
540 {
541 return ($stat = $this->stat($path)) ? (!empty($stat['phash']) ? $this->decode($stat['phash']) : $this->root) : false;
542 }
543
544 /**
545 * Return file name
546 *
547 * @param string $path file path
548 *
549 * @return string
550 * @author Dmitry (dio) Levashov
551 **/
552 protected function _basename($path)
553 {
554 return (($stat = $this->stat($path)) && isset($stat['name'])) ? $stat['name'] : false;
555 }
556
557 /**
558 * Join dir name and file name and return full path
559 *
560 * @param string $dir
561 * @param string $name
562 *
563 * @return string
564 * @author Dmitry (dio) Levashov
565 **/
566 protected function _joinPath($dir, $name)
567 {
568 if (($parentId = $this->pathId($dir)) === null) {
569 return -1;
570 }
571
572 $sql = 'SELECT id FROM ' . $this->tbf . ' WHERE parent_id=%d AND name=\'' . $this->db->real_escape_string($name) . '\'';
573 $sql = sprintf($sql, $parentId);
574
575 if (($res = $this->query($sql)) && ($r = $res->fetch_assoc())) {
576 $this->updateCache($r['id'], $this->_stat($r['id']));
577 return $r['id'];
578 }
579 return -1;
580 }
581
582 /**
583 * Return normalized path, this works the same as os.path.normpath() in Python
584 *
585 * @param string $path path
586 *
587 * @return string
588 * @author Troex Nevelin
589 **/
590 protected function _normpath($path)
591 {
592 return $path;
593 }
594
595 /**
596 * Return file path related to root dir
597 *
598 * @param string $path file path
599 *
600 * @return string
601 * @author Dmitry (dio) Levashov
602 **/
603 protected function _relpath($path)
604 {
605 return $path;
606 }
607
608 /**
609 * Convert path related to root dir into real path
610 *
611 * @param string $path file path
612 *
613 * @return string
614 * @author Dmitry (dio) Levashov
615 **/
616 protected function _abspath($path)
617 {
618 return $path;
619 }
620
621 /**
622 * Return fake path started from root dir
623 *
624 * @param string $path file path
625 *
626 * @return string
627 * @author Dmitry (dio) Levashov
628 **/
629 protected function _path($path)
630 {
631 if (($file = $this->stat($path)) == false) {
632 return '';
633 }
634
635 $parentsIds = $this->getParents($path);
636 $path = '';
637 foreach ($parentsIds as $id) {
638 $dir = $this->stat($id);
639 $path .= $dir['name'] . $this->separator;
640 }
641 return $path . $file['name'];
642 }
643
644 /**
645 * Return true if $path is children of $parent
646 *
647 * @param string $path path to check
648 * @param string $parent parent path
649 *
650 * @return bool
651 * @author Dmitry (dio) Levashov
652 **/
653 protected function _inpath($path, $parent)
654 {
655 return $path == $parent
656 ? true
657 : in_array($parent, $this->getParents($path));
658 }
659
660 /***************** file stat ********************/
661 /**
662 * Return stat for given path.
663 * Stat contains following fields:
664 * - (int) size file size in b. required
665 * - (int) ts file modification time in unix time. required
666 * - (string) mime mimetype. required for folders, others - optionally
667 * - (bool) read read permissions. required
668 * - (bool) write write permissions. required
669 * - (bool) locked is object locked. optionally
670 * - (bool) hidden is object hidden. optionally
671 * - (string) alias for symlinks - link target path relative to root path. optionally
672 * - (string) target for symlinks - link target path. optionally
673 * If file does not exists - returns empty array or false.
674 *
675 * @param string $path file path
676 *
677 * @return array|false
678 * @author Dmitry (dio) Levashov
679 **/
680 protected function _stat($path)
681 {
682 if (($fileId = $this->pathId($path)) === null) {
683 return array();
684 }
685
686 $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
687 FROM ' . $this->tbf . ' AS f
688 LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
689 WHERE f.id=%d
690 GROUP BY f.id, ch.id';
691 $sql = sprintf($sql, $fileId);
692
693 $res = $this->query($sql);
694
695 if ($res) {
696 $stat = $res->fetch_assoc();
697 if ($stat['id'] == $this->root) {
698 $this->rootHasParent = true;
699 $stat['parent_id'] = '';
700 }
701 if ($stat['parent_id']) {
702 $stat['phash'] = $this->encode($stat['parent_id']);
703 }
704 if ($stat['mime'] == 'directory') {
705 unset($stat['width']);
706 unset($stat['height']);
707 $stat['size'] = 0;
708 } else {
709 if (!$stat['mime']) {
710 unset($stat['mime']);
711 }
712 unset($stat['dirs']);
713 }
714 unset($stat['id']);
715 unset($stat['parent_id']);
716 return $stat;
717
718 }
719 return array();
720 }
721
722 /**
723 * Return true if path is dir and has at least one childs directory
724 *
725 * @param string $path dir path
726 *
727 * @return bool
728 * @author Dmitry (dio) Levashov
729 **/
730 protected function _subdirs($path)
731 {
732 return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
733 }
734
735 /**
736 * Return object width and height
737 * Usualy used for images, but can be realize for video etc...
738 *
739 * @param string $path file path
740 * @param string $mime file mime type
741 *
742 * @return string
743 * @author Dmitry (dio) Levashov
744 **/
745 protected function _dimensions($path, $mime)
746 {
747 return ($stat = $this->stat($path)) && isset($stat['width']) && isset($stat['height']) ? $stat['width'] . 'x' . $stat['height'] : '';
748 }
749
750 /******************** file/dir content *********************/
751
752 /**
753 * Return files list in directory.
754 *
755 * @param string $path dir path
756 *
757 * @return array
758 * @author Dmitry (dio) Levashov
759 **/
760 protected function _scandir($path)
761 {
762 return isset($this->dirsCache[$path])
763 ? $this->dirsCache[$path]
764 : $this->cacheDir($path);
765 }
766
767 /**
768 * Open file and return file pointer
769 *
770 * @param string $path file path
771 * @param string $mode open file mode (ignored in this driver)
772 *
773 * @return resource|false
774 * @author Dmitry (dio) Levashov
775 **/
776 protected function _fopen($path, $mode = 'rb')
777 {
778 if (($fileId = $this->pathId($path)) === null) {
779 return false;
780 }
781
782 $fp = $this->tmpPath
783 ? fopen($this->getTempFile($path), 'w+')
784 : $this->tmpfile();
785
786
787 if ($fp) {
788 if (($res = $this->query(sprintf('SELECT content FROM %s WHERE id=%d', $this->tbf, $fileId)))
789 && ($r = $res->fetch_assoc())) {
790 fwrite($fp, $r['content']);
791 rewind($fp);
792 return $fp;
793 } else {
794 $this->_fclose($fp, $path);
795 }
796 }
797
798 return false;
799 }
800
801 /**
802 * Close opened file
803 *
804 * @param resource $fp file pointer
805 * @param string $path
806 *
807 * @return void
808 * @author Dmitry (dio) Levashov
809 */
810 protected function _fclose($fp, $path = '')
811 {
812 is_resource($fp) && fclose($fp);
813 if ($path) {
814 $file = $this->getTempFile($path);
815 is_file($file) && unlink($file);
816 }
817 }
818
819 /******************** file/dir manipulations *************************/
820
821 /**
822 * Create dir and return created dir path or false on failed
823 *
824 * @param string $path parent dir path
825 * @param string $name new directory name
826 *
827 * @return string|bool
828 * @author Dmitry (dio) Levashov
829 **/
830 protected function _mkdir($path, $name)
831 {
832 return $this->make($path, $name, 'directory') ? $this->_joinPath($path, $name) : false;
833 }
834
835 /**
836 * Create file and return it's path or false on failed
837 *
838 * @param string $path parent dir path
839 * @param string $name new file name
840 *
841 * @return string|bool
842 * @author Dmitry (dio) Levashov
843 **/
844 protected function _mkfile($path, $name)
845 {
846 return $this->make($path, $name, '') ? $this->_joinPath($path, $name) : false;
847 }
848
849 /**
850 * Create symlink. FTP driver does not support symlinks.
851 *
852 * @param string $target link target
853 * @param string $path symlink path
854 * @param string $name
855 *
856 * @return bool
857 * @author Dmitry (dio) Levashov
858 */
859 protected function _symlink($target, $path, $name)
860 {
861 return false;
862 }
863
864 /**
865 * Copy file into another file
866 *
867 * @param string $source source file path
868 * @param string $targetDir target directory path
869 * @param string $name new file name
870 *
871 * @return bool
872 * @author Dmitry (dio) Levashov
873 **/
874 protected function _copy($source, $targetDir, $name)
875 {
876 if (($sourceId = $this->pathId($source)) === null || ($targetParentId = $this->pathId($targetDir)) === null) {
877 return false;
878 }
879
880 $this->clearcache();
881 $id = $this->_joinPath($targetDir, $name);
882
883 $sql = $id > 0
884 ? 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, $sourceId)
885 : 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, $targetParentId, $this->db->real_escape_string($name), time(), $this->tbf, $sourceId);
886
887 return $this->query($sql);
888 }
889
890 /**
891 * Move file into another parent dir.
892 * Return new file path or false.
893 *
894 * @param string $source source file path
895 * @param $targetDir
896 * @param string $name file name
897 *
898 * @return bool|string
899 * @internal param string $target target dir path
900 * @author Dmitry (dio) Levashov
901 */
902 protected function _move($source, $targetDir, $name)
903 {
904 if (($sourceId = $this->pathId($source)) === null || ($targetParentId = $this->pathId($targetDir)) === null) {
905 return false;
906 }
907
908 $sql = 'UPDATE %s SET parent_id=%d, name=\'%s\' WHERE id=%d LIMIT 1';
909 $sql = sprintf($sql, $this->tbf, $targetParentId, $this->db->real_escape_string($name), $sourceId);
910 return $this->query($sql) && $this->db->affected_rows > 0 ? $sourceId : false;
911 }
912
913 /**
914 * Remove file
915 *
916 * @param string $path file path
917 *
918 * @return bool
919 * @author Dmitry (dio) Levashov
920 **/
921 protected function _unlink($path)
922 {
923 if (($fileId = $this->pathId($path)) === null) {
924 return false;
925 }
926
927 return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime!=\'directory\' LIMIT 1', $this->tbf, $fileId)) && $this->db->affected_rows;
928 }
929
930 /**
931 * Remove dir
932 *
933 * @param string $path dir path
934 *
935 * @return bool
936 * @author Dmitry (dio) Levashov
937 **/
938 protected function _rmdir($path)
939 {
940 if (($dirId = $this->pathId($path)) === null) {
941 return false;
942 }
943
944 return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime=\'directory\' LIMIT 1', $this->tbf, $dirId)) && $this->db->affected_rows;
945 }
946
947 /**
948 * undocumented function
949 *
950 * @param $path
951 * @param $fp
952 *
953 * @author Dmitry Levashov
954 */
955 protected function _setContent($path, $fp)
956 {
957 elFinder::rewind($fp);
958 $fstat = fstat($fp);
959 $size = $fstat['size'];
960
961
962 }
963
964 /**
965 * Create new file and write into it from file pointer.
966 * Return new file path or false on error.
967 *
968 * @param resource $fp file pointer
969 * @param string $dir target dir path
970 * @param string $name file name
971 * @param array $stat file stat (required by some virtual fs)
972 *
973 * @return bool|string
974 * @author Dmitry (dio) Levashov
975 **/
976 protected function _save($fp, $dir, $name, $stat)
977 {
978 if (($dirId = $this->pathId($dir)) === null) {
979 return false;
980 }
981
982 $this->clearcache();
983
984 $mime = !empty($stat['mime']) ? $stat['mime'] : $this->mimetype($name, true);
985 $w = !empty($stat['width']) ? $stat['width'] : 0;
986 $h = !empty($stat['height']) ? $stat['height'] : 0;
987 $ts = !empty($stat['ts']) ? $stat['ts'] : time();
988
989 $id = $this->_joinPath($dir, $name);
990 if (!isset($stat['size'])) {
991 $stat = fstat($fp);
992 $size = $stat['size'];
993 } else {
994 $size = $stat['size'];
995 }
996
997 if ($this->isLocalhost && ($tmpfile = tempnam($this->tmpPath, $this->id))) {
998 if (($trgfp = fopen($tmpfile, 'wb')) == false) {
999 unlink($tmpfile);
1000 } else {
1001 elFinder::rewind($fp);
1002 stream_copy_to_stream($fp, $trgfp);
1003 fclose($trgfp);
1004 chmod($tmpfile, 0644);
1005
1006 $sql = $id > 0
1007 ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', ?, ?, LOAD_FILE(?), ?, ?, ?, ?, ?)'
1008 : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (?, ?, LOAD_FILE(?), ?, ?, ?, ?, ?)';
1009 $stmt = $this->db->prepare(sprintf($sql, $this->tbf));
1010 $path = $this->loadFilePath($tmpfile);
1011 $stmt->bind_param("issiisii", $dirId, $name, $path, $size, $ts, $mime, $w, $h);
1012
1013 $res = $this->execute($stmt);
1014 unlink($tmpfile);
1015
1016 if ($res) {
1017 return $id > 0 ? $id : $this->db->insert_id;
1018 }
1019 }
1020 }
1021
1022
1023 $content = '';
1024 elFinder::rewind($fp);
1025 while (!feof($fp)) {
1026 $content .= fread($fp, 8192);
1027 }
1028
1029 $sql = $id > 0
1030 ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', ?, ?, ?, ?, ?, ?, ?, ?)'
1031 : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (?, ?, ?, ?, ?, ?, ?, ?)';
1032 $stmt = $this->db->prepare(sprintf($sql, $this->tbf));
1033 $stmt->bind_param("issiisii", $dirId, $name, $content, $size, $ts, $mime, $w, $h);
1034
1035 unset($content);
1036
1037 if ($this->execute($stmt)) {
1038 return $id > 0 ? $id : $this->db->insert_id;
1039 }
1040
1041 return false;
1042 }
1043
1044 /**
1045 * Get file contents
1046 *
1047 * @param string $path file path
1048 *
1049 * @return string|false
1050 * @author Dmitry (dio) Levashov
1051 **/
1052 protected function _getContents($path)
1053 {
1054 if (($fileId = $this->pathId($path)) === null) {
1055 return false;
1056 }
1057
1058 return ($res = $this->query(sprintf('SELECT content FROM %s WHERE id=%d', $this->tbf, $fileId))) && ($r = $res->fetch_assoc()) ? $r['content'] : false;
1059 }
1060
1061 /**
1062 * Write a string to a file
1063 *
1064 * @param string $path file path
1065 * @param string $content new file content
1066 *
1067 * @return bool
1068 * @author Dmitry (dio) Levashov
1069 **/
1070 protected function _filePutContents($path, $content)
1071 {
1072 if (($fileId = $this->pathId($path)) === null) {
1073 return false;
1074 }
1075
1076 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(), $fileId));
1077 }
1078
1079 /**
1080 * Detect available archivers
1081 *
1082 * @return void
1083 **/
1084 protected function _checkArchivers()
1085 {
1086 return;
1087 }
1088
1089 /**
1090 * chmod implementation
1091 *
1092 * @param string $path
1093 * @param string $mode
1094 *
1095 * @return bool
1096 */
1097 protected function _chmod($path, $mode)
1098 {
1099 return false;
1100 }
1101
1102 /**
1103 * Unpack archive
1104 *
1105 * @param string $path archive path
1106 * @param array $arc archiver command and arguments (same as in $this->archivers)
1107 *
1108 * @return void
1109 * @author Dmitry (dio) Levashov
1110 * @author Alexey Sukhotin
1111 **/
1112 protected function _unpack($path, $arc)
1113 {
1114 return;
1115 }
1116
1117 /**
1118 * Extract files from archive
1119 *
1120 * @param string $path archive path
1121 * @param array $arc archiver command and arguments (same as in $this->archivers)
1122 *
1123 * @return true
1124 * @author Dmitry (dio) Levashov,
1125 * @author Alexey Sukhotin
1126 **/
1127 protected function _extract($path, $arc)
1128 {
1129 return false;
1130 }
1131
1132 /**
1133 * Create archive and return its path
1134 *
1135 * @param string $dir target dir
1136 * @param array $files files names list
1137 * @param string $name archive name
1138 * @param array $arc archiver options
1139 *
1140 * @return string|bool
1141 * @author Dmitry (dio) Levashov,
1142 * @author Alexey Sukhotin
1143 **/
1144 protected function _archive($dir, $files, $name, $arc)
1145 {
1146 return false;
1147 }
1148
1149 } // END class
1150