Issues (2268)

htdocs/class/file/folder.php (1 issue)

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