Issues (1107)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/elFinderVolumeMySQL.class.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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