XoopsFolderHandler::pwd()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Folder engine For XOOPS
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2005-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             class
15
 * @subpackage          file
16
 * @since               2.3.0
17
 * @author              Taiwen Jiang <[email protected]>
18
 */
19
20
/**
21
 * Convenience class for handling directories.
22
 *
23
 * PHP versions 4 and 5
24
 *
25
 * CakePHP(tm) :  Rapid Development Framework <https://www.cakephp.org/>
26
 * Copyright 2005-2008, Cake Software Foundation, Inc.
27
 *                                     1785 E. Sahara Avenue, Suite 490-204
28
 *                                     Las Vegas, Nevada 89104
29
 *
30
 * Licensed under The MIT License
31
 * Redistributions of files must retain the above copyright notice.
32
 *
33
 * @filesource
34
 * @copyright  Copyright 2005-2008, Cake Software Foundation, Inc.
35
 * @link       https://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
36
 * @package    cake
37
 * @subpackage cake.cake.libs
38
 * @since      CakePHP(tm) v 0.2.9
39
 * @modifiedby $LastChangedBy: beckmi $
40
 * @lastmodified $Date: 2015-06-06 17:59:41 -0400 (Sat, 06 Jun 2015) $
41
 * @license    https://www.opensource.org/licenses/mit-license.php The MIT License
42
 */
43
44
/**
45
 * Folder structure browser, lists folders and files.
46
 *
47
 * Long description for class
48
 *
49
 * @package    cake
50
 * @subpackage cake.cake.libs
51
 */
52
class XoopsFolderHandler
53
{
54
    /**
55
     * Path to Folder.
56
     *
57
     * @var string
58
     * @access public
59
     */
60
    public $path;
61
62
    /**
63
     * Sortedness.
64
     *
65
     * @var boolean
66
     * @access public
67
     */
68
    public $sort = false;
69
70
    /**
71
     * mode to be used on create.
72
     *
73
     * @var boolean
74
     * @access public
75
     */
76
    public $mode = '0755';
77
78
    /**
79
     * holds messages from last method.
80
     *
81
     * @var array
82
     * @access private
83
     */
84
    public $messages = array();
85
86
    /**
87
     * holds errors from last method.
88
     *
89
     * @var array
90
     * @access private
91
     */
92
    public $errors = array();
93
94
    /**
95
     * holds array of complete directory paths.
96
     *
97
     * @var array
98
     * @access private
99
     */
100
    public $directories;
101
102
    /**
103
     * holds array of complete file paths.
104
     *
105
     * @var array
106
     * @access private
107
     */
108
    public $files;
109
110
    /**
111
     * Constructor.
112
     *
113
     * @param bool|string $path   Path to folder
114
     * @param boolean     $create Create folder if not found
115
     * @param mixed       $mode   Mode (CHMOD) to apply to created folder, false to ignore
116
     */
117
    public function __construct($path = false, $create = true, $mode = false)
118
    {
119
        if (empty($path)) {
120
            $path = XOOPS_VAR_PATH . '/caches/xoops_cache';
121
        }
122
        if ($mode) {
123
            $this->mode = intval($mode, 8);
0 ignored issues
show
Documentation Bug introduced by
The property $mode was declared of type boolean, but intval($mode, 8) is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
124
        }
125
        if (!file_exists($path) && $create == true) {
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type boolean; however, parameter $filename of file_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

125
        if (!file_exists(/** @scrutinizer ignore-type */ $path) && $create == true) {
Loading history...
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
126
            $this->create($path, $this->mode);
127
        }
128
        if (!$this->isAbsolute($path)) {
129
            $path = realpath($path);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type boolean; however, parameter $path of realpath() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
            $path = realpath(/** @scrutinizer ignore-type */ $path);
Loading history...
130
        }
131
        $this->cd($path);
132
    }
133
134
    /**
135
     * Return current path.
136
     *
137
     * @return string Current path
138
     * @access public
139
     */
140
    public function pwd()
141
    {
142
        return $this->path;
143
    }
144
145
    /**
146
     * Change directory to $desired_path.
147
     *
148
     * @param string $path Path to the directory to change to
149
     *
150
     * @return string|false The new path. Returns false on failure
151
     * @access   public
152
     */
153
    public function cd($path)
154
    {
155
        $path = $this->realpath($path);
156
        if (is_string($path) && is_dir($path) && file_exists($path)) {
157
            return $this->path = $path;
158
        }
159
160
        return false;
161
    }
162
163
    /**
164
     * Returns an array of the contents of the current directory, or false on failure.
165
     * The returned array holds two arrays: one of dirs and one of files.
166
     *
167
     * @param boolean $sort
168
     * @param mixed   $exceptions either an array or boolean true will no grab dot files
169
     *
170
     * @return mixed Contents of current directory as an array, false on failure
171
     * @access public
172
     */
173
    public function read($sort = true, $exceptions = false)
174
    {
175
        $dirs = $files = array();
176
        $dir  = opendir($this->path);
177
        if ($dir !== false) {
178
            while (false !== ($n = readdir($dir))) {
179
                $item = false;
180
                if (is_array($exceptions)) {
181
                    if (!in_array($n, $exceptions)) {
182
                        $item = $n;
183
                    }
184
                } else {
185
                    if ((!preg_match('/^\\.+$/', $n) && $exceptions === false) || ($exceptions === true && !preg_match('/^\\.(.*)$/', $n))) {
186
                        $item = $n;
187
                    }
188
                }
189
                if ($item !== false) {
190
                    if (is_dir($this->addPathElement($this->path, $item))) {
191
                        $dirs[] = $item;
192
                    } else {
193
                        $files[] = $item;
194
                    }
195
                }
196
            }
197
            if ($sort || $this->sort) {
198
                sort($dirs);
199
                sort($files);
200
            }
201
            closedir($dir);
202
        }
203
204
        return array(
205
            $dirs,
206
            $files);
207
    }
208
209
    /**
210
     * Returns an array of all matching files in current directory.
211
     *
212
     * @param string $regexp_pattern Preg_match pattern (Defaults to: .*)
213
     * @param bool   $sort
214
     *
215
     * @return array Files that match given pattern
216
     * @access   public
217
     */
218
    public function find($regexp_pattern = '.*', $sort = false)
219
    {
220
        $data = $this->read($sort);
221
        if (!is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
222
            return array();
223
        }
224
        list($dirs, $files) = $data;
225
        $found = array();
226
        foreach ($files as $file) {
227
            if (preg_match("/^{$regexp_pattern}$/i", $file)) {
228
                $found[] = $file;
229
            }
230
        }
231
232
        return $found;
233
    }
234
235
    /**
236
     * Returns an array of all matching files in and below current directory.
237
     *
238
     * @param string $pattern Preg_match pattern (Defaults to: .*)
239
     * @param bool   $sort
240
     *
241
     * @return array Files matching $pattern
242
     * @access public
243
     */
244
    public function findRecursive($pattern = '.*', $sort = false)
245
    {
246
        $startsOn = $this->path;
247
        $out      = $this->_findRecursive($pattern, $sort);
248
        $this->cd($startsOn);
249
250
        return $out;
251
    }
252
253
    /**
254
     * Private helper function for findRecursive.
255
     *
256
     * @param string $pattern Pattern to match against
257
     * @param bool   $sort
258
     *
259
     * @return array Files matching pattern
260
     * @access private
261
     */
262
    public function _findRecursive($pattern, $sort = false)
263
    {
264
        list($dirs, $files) = $this->read($sort);
265
        $found = array();
266
        foreach ($files as $file) {
267
            if (preg_match("/^{$pattern}$/i", $file)) {
268
                $found[] = $this->addPathElement($this->path, $file);
269
            }
270
        }
271
        $start = $this->path;
272
        foreach ($dirs as $dir) {
273
            $this->cd($this->addPathElement($start, $dir));
274
            $newFound = $this->findRecursive($pattern);
275
276
            foreach ($newFound as $item) {
277
                $found[] = $item;
278
            }
279
        }
280
281
        return $found;
282
    }
283
284
    /**
285
     * Returns true if given $path is a Windows path.
286
     *
287
     * @param string $path Path to check
288
     *
289
     * @return boolean true if windows path, false otherwise
290
     * @access public
291
     * @static
292
     */
293
    public function isWindowsPath($path)
294
    {
295
        if (preg_match('/^[A-Z]:\\\\/i', (string)$path)) {
296
            return true;
297
        }
298
299
        return false;
300
    }
301
302
    /**
303
     * Returns true if given $path is an absolute path.
304
     *
305
     * @param string $path Path to check
306
     *
307
     * @return bool
308
     * @access public
309
     * @static
310
     */
311
    public function isAbsolute($path)
312
    {
313
        $match = preg_match('/^\\//', $path) || preg_match('/^[A-Z]:\\//i', $path);
314
315
        return $match;
316
    }
317
318
    /**
319
     * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
320
     *
321
     * @param string $path Path to check
322
     *
323
     * @return string Set of slashes ("\\" or "/")
324
     * @access public
325
     * @static
326
     */
327
    public function normalizePath($path)
328
    {
329
        if ($this->isWindowsPath($path)) {
330
            return '\\';
331
        }
332
333
        return '/';
334
    }
335
336
    /**
337
     * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
338
     *
339
     * @param string $path Path to check
340
     *
341
     * @return string Set of slashes ("\\" or "/")
342
     * @access public
343
     * @static
344
     */
345
    public function correctSlashFor($path)
346
    {
347
        if ($this->isWindowsPath($path)) {
348
            return '\\';
349
        }
350
351
        return '/';
352
    }
353
354
    /**
355
     * Returns $path with added terminating slash (corrected for Windows or other OS).
356
     *
357
     * @param string $path Path to check
358
     *
359
     * @return string Path with ending slash
360
     * @access public
361
     * @static
362
     */
363
    public function slashTerm($path)
364
    {
365
        if ($this->isSlashTerm($path)) {
366
            return $path;
367
        }
368
369
        return $path . $this->correctSlashFor($path);
370
    }
371
372
    /**
373
     * Returns $path with $element added, with correct slash in-between.
374
     *
375
     * @param string $path    Path
376
     * @param string $element Element to and at end of path
377
     *
378
     * @return string Combined path
379
     * @access public
380
     * @static
381
     */
382
    public function addPathElement($path, $element)
383
    {
384
        return $this->slashTerm($path) . $element;
385
    }
386
387
    /**
388
     * Returns true if the File is in a given XoopsPath.
389
     *
390
     * @param string $path
391
     *
392
     * @return bool
393
     * @access public
394
     */
395
    public function inXoopsPath($path = '')
396
    {
397
        $dir    = substr($this->slashTerm(XOOPS_ROOT_PATH), 0, -1);
398
        $newdir = $dir . $path;
399
400
        return $this->inPath($newdir);
401
    }
402
403
    /**
404
     * Returns true if the File is in given path.
405
     *
406
     * @param string $path
407
     * @param bool   $reverse
408
     *
409
     * @return bool
410
     * @access public
411
     */
412
    public function inPath($path = '', $reverse = false)
413
    {
414
        $dir     = $this->slashTerm($path);
415
        $current = $this->slashTerm($this->pwd());
416
        if (!$reverse) {
417
            $return = preg_match('/^(.*)' . preg_quote($dir, '/') . '(.*)/', $current);
418
        } else {
419
            $return = preg_match('/^(.*)' . preg_quote($current, '/') . '(.*)/', $dir);
420
        }
421
        if ($return == 1) {
422
            return true;
423
        } else {
424
            return false;
425
        }
426
    }
427
428
    /**
429
     * Change the mode on a directory structure recursively.
430
     *
431
     * @param string   $path       The path to chmod
432
     * @param bool|int $mode       octal value 0755
433
     * @param boolean  $recursive  chmod recursively
434
     * @param array    $exceptions array of files, directories to skip
435
     *
436
     * @return boolean Returns TRUE on success, FALSE on failure
437
     * @access public
438
     */
439
    public function chmod($path, $mode = false, $recursive = true, $exceptions = array())
440
    {
441
        if (!$mode) {
442
            $mode = $this->mode;
443
        }
444
        if ($recursive === false && is_dir($path)) {
445
            if (chmod($path, intval($mode, 8))) {
446
                $this->messages[] = sprintf('%s changed to %s', $path, $mode);
447
448
                return true;
449
            } else {
450
                $this->errors[] = sprintf('%s NOT changed to %s', $path, $mode);
451
452
                return false;
453
            }
454
        }
455
        if (is_dir($path)) {
456
            list($paths) = $this->tree($path);
457
            foreach ($paths as $key => $fullpath) {
458
                $check = explode('/', $fullpath);
459
                $count = count($check);
460
461
                if (in_array($check[$count - 1], $exceptions)) {
462
                    continue;
463
                }
464
465
                if (chmod($fullpath, intval($mode, 8))) {
466
                    $this->messages[] = sprintf('%s changed to %s', $fullpath, $mode);
467
                } else {
468
                    $this->errors[] = sprintf('%s NOT changed to %s', $fullpath, $mode);
469
                }
470
            }
471
            if (empty($this->errors)) {
472
                return true;
473
            }
474
        }
475
476
        return false;
477
    }
478
479
    /**
480
     * Returns an array of nested directories and files in each directory
481
     *
482
     * @param string  $path   the directory path to build the tree from
483
     * @param boolean $hidden return hidden files and directories
484
     * @param string  $type   either file or dir. null returns both files and directories
485
     *
486
     * @return mixed array of nested directories and files in each directory
487
     * @access public
488
     */
489
    public function tree($path, $hidden = true, $type = null)
490
    {
491
        $path              = rtrim($path, '/');
492
        $this->files       = array();
493
        $this->directories = array(
494
            $path);
495
        $directories       = array();
496
        while (count($this->directories)) {
497
            $dir = array_pop($this->directories);
498
            $this->_tree($dir, $hidden);
499
            $directories[] =  $dir;
500
        }
501
        if ($type === null) {
502
            return array(
503
                $directories,
504
                $this->files);
505
        }
506
        if ($type === 'dir') {
507
            return $directories;
508
        }
509
510
        return $this->files;
511
    }
512
513
    /**
514
     * Private method to list directories and files in each directory
515
     *
516
     * @param string $path
517
     * @param        $hidden
518
     *
519
     * @internal param $ $ = boolean $hidden
520
     * @access   private
521
     */
522
    public function _tree($path, $hidden)
523
    {
524
        if (is_dir($path)) {
525
            $dirHandle = opendir($path);
526
            while (false !== ($item = readdir($dirHandle))) {
527
                $found = false;
528
                if (($hidden === true && $item !== '.' && $item !== '..') || ($hidden === false && !preg_match('/^\\.(.*)$/', $item))) {
529
                    $found = $path . '/' . $item;
530
                }
531
                if ($found !== false) {
532
                    if (is_dir($found)) {
533
                        $this->directories[] =  $found;
534
                    } else {
535
                        $this->files[] =  $found;
536
                    }
537
                }
538
            }
539
            closedir($dirHandle);
540
        }
541
    }
542
543
    /**
544
     * Create a directory structure recursively.
545
     *
546
     * @param string   $pathname The directory structure to create
547
     * @param bool|int $mode     octal value 0755
548
     *
549
     * @return boolean Returns TRUE on success, FALSE on failure
550
     * @access public
551
     */
552
    public function create($pathname, $mode = false)
553
    {
554
        if (is_dir($pathname) || empty($pathname)) {
555
            return true;
556
        }
557
        if (!$mode) {
558
            $mode = $this->mode;
559
        }
560
        if (is_file($pathname)) {
561
            $this->errors[] = sprintf('%s is a file', $pathname);
562
563
            return true;
564
        }
565
        $nextPathname = substr($pathname, 0, strrpos($pathname, '/'));
566
        if ($this->create($nextPathname, $mode)) {
567
            if (!file_exists($pathname)) {
568
                if (mkdir($pathname, intval($mode, 8))) {
569
                    $this->messages[] = sprintf('%s created', $pathname);
570
571
                    return true;
572
                } else {
573
                    $this->errors[] = sprintf('%s NOT created', $pathname);
574
575
                    return false;
576
                }
577
            }
578
        }
579
580
        return true;
581
    }
582
583
    /**
584
     * Returns the size in bytes of this Folder.
585
     *
586
     * @return int $size
587
     * @access   public
588
     */
589
    public function dirsize()
590
    {
591
        $size      = 0;
592
        $directory = $this->slashTerm($this->path);
593
        $stack     = array($directory);
594
        $count     = count($stack);
595
        for ($i = 0, $j = $count; $i < $j; ++$i) {
596
            if (is_file($stack[$i])) {
597
                $size += filesize($stack[$i]);
598
            } else {
599
                if (is_dir($stack[$i])) {
600
                    $dir = dir($stack[$i]);
601
                    if ($dir) {
602
                        while (false !== ($entry = $dir->read())) {
603
                            if ($entry === '.' || $entry === '..') {
604
                                continue;
605
                            }
606
                            $add = $stack[$i] . $entry;
607
                            if (is_dir($stack[$i] . $entry)) {
608
                                $add = $this->slashTerm($add);
609
                            }
610
                            $stack[] = $add;
611
                        }
612
                        $dir->close();
613
                    }
614
                }
615
            }
616
            $j = count($stack);
617
        }
618
619
        return $size;
620
    }
621
622
    /**
623
     * Recursively Remove directories if system allow.
624
     *
625
     * @param string $path Path of directory to delete
626
     *
627
     * @return boolean Success
628
     * @access public
629
     */
630
    public function delete($path)
631
    {
632
        $path = $this->slashTerm($path);
633
        if (is_dir($path) === true) {
634
            $files        = glob($path . '*', GLOB_NOSORT);
0 ignored issues
show
Unused Code introduced by
The assignment to $files is dead and can be removed.
Loading history...
635
            $normal_files = glob($path . '*');
636
            $hidden_files = glob($path . '\.?*');
637
            $files        = array_merge($normal_files, $hidden_files);
638
            if (is_array($files)) {
0 ignored issues
show
introduced by
The condition is_array($files) is always true.
Loading history...
639
                foreach ($files as $file) {
640
                    if (preg_match("/(\.|\.\.)$/", $file)) {
641
                        continue;
642
                    }
643
                    if (is_file($file) === true) {
644
                        if (unlink($file)) {
645
                            $this->messages[] = sprintf('%s removed', $path);
646
                        } else {
647
                            $this->errors[] = sprintf('%s NOT removed', $path);
648
                        }
649
                    } else {
650
                        if (is_dir($file) === true) {
651
                            if ($this->delete($file) === false) {
652
                                return false;
653
                            }
654
                        }
655
                    }
656
                }
657
            }
658
            $path = substr($path, 0, strlen($path) - 1);
659
            if (rmdir($path) === false) {
660
                $this->errors[] = sprintf('%s NOT removed', $path);
661
662
                return false;
663
            } else {
664
                $this->messages[] = sprintf('%s removed', $path);
665
            }
666
        }
667
668
        return true;
669
    }
670
671
    /**
672
     * Copies files and directories from one directory to another
673
     *
674
     * @param array|string $options An array of options or a string representing the target directory
675
     *                              If a string is provided, it will be used as the target directory and other options will be set to their default values
676
     * @return bool Returns true on success, false on failure
677
     */
678
    public function copy($options = array())
679
    {
680
        $to = null;
681
        if (is_string($options)) {
682
            $to      = $options;
683
            $options = array();
684
        }
685
        $options = array_merge(array(
686
                                   'to'   => $to,
687
                                   'from' => $this->path,
688
                                   'mode' => $this->mode,
689
                                   'skip' => array()), $options);
690
691
        $fromDir = $options['from'];
692
        $toDir   = $options['to'];
693
        $mode    = $options['mode'];
694
        if (!$this->cd($fromDir)) {
695
            $this->errors[] = sprintf('%s not found', $fromDir);
696
697
            return false;
698
        }
699
        if (!is_dir($toDir)) {
700
            mkdir($toDir, $mode);
701
        }
702
        if (!is_writable($toDir)) {
703
            $this->errors[] = sprintf('%s not writable', $toDir);
704
705
            return false;
706
        }
707
        $exceptions = array_merge(array(
708
                                      '.',
709
                                      '..',
710
                                      '.svn'), $options['skip']);
711
        $handle     = opendir($fromDir);
712
        if ($handle) {
0 ignored issues
show
introduced by
$handle is of type resource, thus it always evaluated to false.
Loading history...
713
            while (false !== ($item = readdir($handle))) {
714
                if (!in_array($item, $exceptions)) {
715
                    $from = $this->addPathElement($fromDir, $item);
716
                    $to   = $this->addPathElement($toDir, $item);
717
                    if (is_file($from)) {
718
                        if (copy($from, $to)) {
719
                            chmod($to, intval($mode, 8));
720
                            touch($to, filemtime($from));
721
                            $this->messages[] = sprintf('%s copied to %s', $from, $to);
722
                        } else {
723
                            $this->errors[] = sprintf('%s NOT copied to %s', $from, $to);
724
                        }
725
                    }
726
727
                    if (is_dir($from)) {
728
                        if (!is_dir($to)) {
729
                            if (mkdir($to, intval($mode, 8)) || is_dir($to)) {
730
                                chmod($to, intval($mode, 8));
731
                                $this->messages[] = sprintf('%s created', $to);
732
733
                                $options['to'] = $to;
734
                                $options['from'] = $from;
735
736
                                $this->copy($options);
737
                            } else {
738
                                // Ensure $this->errors is an array before adding an element
739
                                if (is_array($this->errors)) {
740
                                    $this->errors[] = sprintf('%s not created', $to);
741
                                }
742
                            }
743
                        }
744
                    }
745
                }
746
            }
747
            closedir($handle);
748
        } else {
749
            return false;
750
        }
751
        if (!empty($this->errors)) {
752
            return false;
753
        }
754
755
        return true;
756
    }
757
758
    /**
759
     * Recursive directory move.
760
     *
761
     * @param array|string $options (to, from, chmod, skip)
762
     *
763
     * @return string|boolean Success
764
     * @access public
765
     */
766
    public function move($options)
767
    {
768
        $to = null;
769
        if (is_string($options)) {
770
            $to      = $options;
771
            $options = (array)$options;
772
        }
773
        $options = array_merge(array(
774
                                   'to'   => $to,
775
                                   'from' => $this->path,
776
                                   'mode' => $this->mode,
777
                                   'skip' => array()), $options);
778
        if ($this->copy($options)) {
779
            if ($this->delete($options['from'])) {
780
                return $this->cd($options['to']);
781
            }
782
        }
783
784
        return false;
785
    }
786
787
    /**
788
     * get messages from latest method
789
     *
790
     * @return array
791
     * @access public
792
     */
793
    public function messages()
794
    {
795
        return $this->messages;
796
    }
797
798
    /**
799
     * get error from latest method
800
     *
801
     * @return array
802
     * @access public
803
     */
804
    public function errors()
805
    {
806
        return $this->errors;
807
    }
808
809
    /**
810
     * Get the real path (taking ".." and such into account)
811
     *
812
     * @param string $path Path to resolve
813
     *
814
     * @return string|false The resolved path
815
     */
816
    public function realpath($path)
817
    {
818
        $path = trim($path);
819
        if (strpos($path, '..') === false) {
820
            if (!$this->isAbsolute($path)) {
821
                $path = $this->addPathElement($this->path, $path);
822
            }
823
824
            return $path;
825
        }
826
        $parts    = explode('/', $path);
827
        $newparts = array();
828
        $newpath  = $path[0] === '/' ? '/' : '';
829
        while (($part = array_shift($parts)) !== null) {
830
            if ($part === '.' || $part == '') {
831
                continue;
832
            }
833
            if ($part === '..') {
834
                if (count($newparts) > 0) {
835
                    array_pop($newparts);
836
                    continue;
837
                } else {
838
                    return false;
839
                }
840
            }
841
            $newparts[] = $part;
842
        }
843
        $newpath .= implode('/', $newparts);
844
        if ((strlen($path) > 1) && $path[strlen($path) - 1] === '/') {
845
            $newpath .= '/';
846
        }
847
848
        return $newpath;
849
    }
850
851
    /**
852
     * Returns true if given $path ends in a slash (i.e. is slash-terminated).
853
     *
854
     * @param string $path Path to check
855
     *
856
     * @return boolean true if path ends with slash, false otherwise
857
     * @access public
858
     * @static
859
     */
860
    public function isSlashTerm($path)
861
    {
862
        if (preg_match('/[\/\\\]$/', (string)$path)) {
863
            return true;
864
        }
865
866
        return false;
867
    }
868
}
869