~tsep-dev/tsep/0.9-beta

« back to all changes in this revision

Viewing changes to branches/symfony/cake/libs/folder.php

  • Committer: geoffreyfishing
  • Date: 2011-01-11 23:46:12 UTC
  • Revision ID: svn-v4:ae0de26e-ed09-4cbe-9a20-e40b4c60ac6c::125
Created a symfony branch for future migration to symfony

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Convenience class for handling directories.
 
4
 *
 
5
 * PHP versions 4 and 5
 
6
 *
 
7
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 
8
 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
 
9
 *
 
10
 * Licensed under The MIT License
 
11
 * Redistributions of files must retain the above copyright notice.
 
12
 *
 
13
 * @copyright     Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
 
14
 * @link          http://cakephp.org CakePHP(tm) Project
 
15
 * @package       cake
 
16
 * @subpackage    cake.cake.libs
 
17
 * @since         CakePHP(tm) v 0.2.9
 
18
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 
19
 */
 
20
 
 
21
/**
 
22
 * Included libraries.
 
23
 *
 
24
 */
 
25
if (!class_exists('Object')) {
 
26
        require LIBS . 'object.php';
 
27
}
 
28
 
 
29
/**
 
30
 * Folder structure browser, lists folders and files.
 
31
 * Provides an Object interface for Common directory related tasks.
 
32
 *
 
33
 * @package       cake
 
34
 * @subpackage    cake.cake.libs
 
35
 */
 
36
class Folder extends Object {
 
37
 
 
38
/**
 
39
 * Path to Folder.
 
40
 *
 
41
 * @var string
 
42
 * @access public
 
43
 */
 
44
        var $path = null;
 
45
 
 
46
/**
 
47
 * Sortedness. Whether or not list results
 
48
 * should be sorted by name.
 
49
 *
 
50
 * @var boolean
 
51
 * @access public
 
52
 */
 
53
        var $sort = false;
 
54
 
 
55
/**
 
56
 * Mode to be used on create. Does nothing on windows platforms.
 
57
 *
 
58
 * @var integer
 
59
 * @access public
 
60
 */
 
61
        var $mode = 0755;
 
62
 
 
63
/**
 
64
 * Holds messages from last method.
 
65
 *
 
66
 * @var array
 
67
 * @access private
 
68
 */
 
69
        var $__messages = array();
 
70
 
 
71
/**
 
72
 * Holds errors from last method.
 
73
 *
 
74
 * @var array
 
75
 * @access private
 
76
 */
 
77
        var $__errors = false;
 
78
 
 
79
/**
 
80
 * Holds array of complete directory paths.
 
81
 *
 
82
 * @var array
 
83
 * @access private
 
84
 */
 
85
        var $__directories;
 
86
 
 
87
/**
 
88
 * Holds array of complete file paths.
 
89
 *
 
90
 * @var array
 
91
 * @access private
 
92
 */
 
93
        var $__files;
 
94
 
 
95
/**
 
96
 * Constructor.
 
97
 *
 
98
 * @param string $path Path to folder
 
99
 * @param boolean $create Create folder if not found
 
100
 * @param mixed $mode Mode (CHMOD) to apply to created folder, false to ignore
 
101
 */
 
102
        function __construct($path = false, $create = false, $mode = false) {
 
103
                parent::__construct();
 
104
                if (empty($path)) {
 
105
                        $path = TMP;
 
106
                }
 
107
                if ($mode) {
 
108
                        $this->mode = $mode;
 
109
                }
 
110
 
 
111
                if (!file_exists($path) && $create === true) {
 
112
                        $this->create($path, $this->mode);
 
113
                }
 
114
                if (!Folder::isAbsolute($path)) {
 
115
                        $path = realpath($path);
 
116
                }
 
117
                if (!empty($path)) {
 
118
                        $this->cd($path);
 
119
                }
 
120
        }
 
121
 
 
122
/**
 
123
 * Return current path.
 
124
 *
 
125
 * @return string Current path
 
126
 * @access public
 
127
 */
 
128
        function pwd() {
 
129
                return $this->path;
 
130
        }
 
131
 
 
132
/**
 
133
 * Change directory to $path.
 
134
 *
 
135
 * @param string $path Path to the directory to change to
 
136
 * @return string The new path. Returns false on failure
 
137
 * @access public
 
138
 */
 
139
        function cd($path) {
 
140
                $path = $this->realpath($path);
 
141
                if (is_dir($path)) {
 
142
                        return $this->path = $path;
 
143
                }
 
144
                return false;
 
145
        }
 
146
 
 
147
/**
 
148
 * Returns an array of the contents of the current directory.
 
149
 * The returned array holds two arrays: One of directories and one of files.
 
150
 *
 
151
 * @param boolean $sort Whether you want the results sorted, set this and the sort property
 
152
 *   to false to get unsorted results.
 
153
 * @param mixed $exceptions Either an array or boolean true will not grab dot files
 
154
 * @param boolean $fullPath True returns the full path
 
155
 * @return mixed Contents of current directory as an array, an empty array on failure
 
156
 * @access public
 
157
 */
 
158
        function read($sort = true, $exceptions = false, $fullPath = false) {
 
159
                $dirs = $files = array();
 
160
 
 
161
                if (!$this->pwd()) {
 
162
                        return array($dirs, $files);
 
163
                }
 
164
                if (is_array($exceptions)) {
 
165
                        $exceptions = array_flip($exceptions);
 
166
                }
 
167
                $skipHidden = isset($exceptions['.']) || $exceptions === true;
 
168
 
 
169
                if (false === ($dir = @opendir($this->path))) {
 
170
                        return array($dirs, $files);
 
171
                }
 
172
 
 
173
                while (false !== ($item = readdir($dir))) {
 
174
                        if ($item === '.' || $item === '..' || ($skipHidden && $item[0] === '.') || isset($exceptions[$item])) {
 
175
                                continue;
 
176
                        }
 
177
 
 
178
                        $path = Folder::addPathElement($this->path, $item);
 
179
                        if (is_dir($path)) {
 
180
                                $dirs[] = $fullPath ? $path : $item;
 
181
                        } else {
 
182
                                $files[] = $fullPath ? $path : $item;
 
183
                        }
 
184
                }
 
185
 
 
186
                if ($sort || $this->sort) {
 
187
                        sort($dirs);
 
188
                        sort($files);
 
189
                }
 
190
 
 
191
                closedir($dir);
 
192
                return array($dirs, $files);
 
193
        }
 
194
 
 
195
/**
 
196
 * Returns an array of all matching files in current directory.
 
197
 *
 
198
 * @param string $pattern Preg_match pattern (Defaults to: .*)
 
199
 * @param boolean $sort Whether results should be sorted.
 
200
 * @return array Files that match given pattern
 
201
 * @access public
 
202
 */
 
203
        function find($regexpPattern = '.*', $sort = false) {
 
204
                list($dirs, $files) = $this->read($sort);
 
205
                return array_values(preg_grep('/^' . $regexpPattern . '$/i', $files)); ;
 
206
        }
 
207
 
 
208
/**
 
209
 * Returns an array of all matching files in and below current directory.
 
210
 *
 
211
 * @param string $pattern Preg_match pattern (Defaults to: .*)
 
212
 * @param boolean $sort Whether results should be sorted.
 
213
 * @return array Files matching $pattern
 
214
 * @access public
 
215
 */
 
216
        function findRecursive($pattern = '.*', $sort = false) {
 
217
                if (!$this->pwd()) {
 
218
                        return array();
 
219
                }
 
220
                $startsOn = $this->path;
 
221
                $out = $this->_findRecursive($pattern, $sort);
 
222
                $this->cd($startsOn);
 
223
                return $out;
 
224
        }
 
225
 
 
226
/**
 
227
 * Private helper function for findRecursive.
 
228
 *
 
229
 * @param string $pattern Pattern to match against
 
230
 * @param boolean $sort Whether results should be sorted.
 
231
 * @return array Files matching pattern
 
232
 * @access private
 
233
 */
 
234
        function _findRecursive($pattern, $sort = false) {
 
235
                list($dirs, $files) = $this->read($sort);
 
236
                $found = array();
 
237
 
 
238
                foreach ($files as $file) {
 
239
                        if (preg_match('/^' . $pattern . '$/i', $file)) {
 
240
                                $found[] = Folder::addPathElement($this->path, $file);
 
241
                        }
 
242
                }
 
243
                $start = $this->path;
 
244
 
 
245
                foreach ($dirs as $dir) {
 
246
                        $this->cd(Folder::addPathElement($start, $dir));
 
247
                        $found = array_merge($found, $this->findRecursive($pattern, $sort));
 
248
                }
 
249
                return $found;
 
250
        }
 
251
 
 
252
/**
 
253
 * Returns true if given $path is a Windows path.
 
254
 *
 
255
 * @param string $path Path to check
 
256
 * @return boolean true if windows path, false otherwise
 
257
 * @access public
 
258
 * @static
 
259
 */
 
260
        function isWindowsPath($path) {
 
261
                return (bool)preg_match('/^[A-Z]:\\\\/i', $path);
 
262
        }
 
263
 
 
264
/**
 
265
 * Returns true if given $path is an absolute path.
 
266
 *
 
267
 * @param string $path Path to check
 
268
 * @return bool true if path is absolute.
 
269
 * @access public
 
270
 * @static
 
271
 */
 
272
        function isAbsolute($path) {
 
273
                return !empty($path) && ($path[0] === '/' || preg_match('/^[A-Z]:\\\\/i', $path));
 
274
        }
 
275
 
 
276
/**
 
277
 * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
 
278
 *
 
279
 * @param string $path Path to check
 
280
 * @return string Set of slashes ("\\" or "/")
 
281
 * @access public
 
282
 * @static
 
283
 */
 
284
        function normalizePath($path) {
 
285
                return Folder::correctSlashFor($path);
 
286
        }
 
287
 
 
288
/**
 
289
 * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
 
290
 *
 
291
 * @param string $path Path to check
 
292
 * @return string Set of slashes ("\\" or "/")
 
293
 * @access public
 
294
 * @static
 
295
 */
 
296
        function correctSlashFor($path) {
 
297
                return (Folder::isWindowsPath($path)) ? '\\' : '/';
 
298
        }
 
299
 
 
300
/**
 
301
 * Returns $path with added terminating slash (corrected for Windows or other OS).
 
302
 *
 
303
 * @param string $path Path to check
 
304
 * @return string Path with ending slash
 
305
 * @access public
 
306
 * @static
 
307
 */
 
308
        function slashTerm($path) {
 
309
                if (Folder::isSlashTerm($path)) {
 
310
                        return $path;
 
311
                }
 
312
                return $path . Folder::correctSlashFor($path);
 
313
        }
 
314
 
 
315
/**
 
316
 * Returns $path with $element added, with correct slash in-between.
 
317
 *
 
318
 * @param string $path Path
 
319
 * @param string $element Element to and at end of path
 
320
 * @return string Combined path
 
321
 * @access public
 
322
 * @static
 
323
 */
 
324
        function addPathElement($path, $element) {
 
325
                return rtrim($path, DS) . DS . $element;
 
326
        }
 
327
 
 
328
/**
 
329
 * Returns true if the File is in a given CakePath.
 
330
 *
 
331
 * @param string $path The path to check.
 
332
 * @return bool
 
333
 * @access public
 
334
 */
 
335
        function inCakePath($path = '') {
 
336
                $dir = substr(Folder::slashTerm(ROOT), 0, -1);
 
337
                $newdir = $dir . $path;
 
338
 
 
339
                return $this->inPath($newdir);
 
340
        }
 
341
 
 
342
/**
 
343
 * Returns true if the File is in given path.
 
344
 *
 
345
 * @param string $path The path to check that the current pwd() resides with in.
 
346
 * @param boolean $reverse
 
347
 * @return bool
 
348
 * @access public
 
349
 */
 
350
        function inPath($path = '', $reverse = false) {
 
351
                $dir = Folder::slashTerm($path);
 
352
                $current = Folder::slashTerm($this->pwd());
 
353
 
 
354
                if (!$reverse) {
 
355
                        $return = preg_match('/^(.*)' . preg_quote($dir, '/') . '(.*)/', $current);
 
356
                } else {
 
357
                        $return = preg_match('/^(.*)' . preg_quote($current, '/') . '(.*)/', $dir);
 
358
                }
 
359
                return (bool)$return;
 
360
        }
 
361
 
 
362
/**
 
363
 * Change the mode on a directory structure recursively. This includes changing the mode on files as well.
 
364
 *
 
365
 * @param string $path The path to chmod
 
366
 * @param integer $mode octal value 0755
 
367
 * @param boolean $recursive chmod recursively, set to false to only change the current directory.
 
368
 * @param array $exceptions array of files, directories to skip
 
369
 * @return boolean Returns TRUE on success, FALSE on failure
 
370
 * @access public
 
371
 */
 
372
        function chmod($path, $mode = false, $recursive = true, $exceptions = array()) {
 
373
                if (!$mode) {
 
374
                        $mode = $this->mode;
 
375
                }
 
376
 
 
377
                if ($recursive === false && is_dir($path)) {
 
378
                        if (@chmod($path, intval($mode, 8))) {
 
379
                                $this->__messages[] = sprintf(__('%s changed to %s', true), $path, $mode);
 
380
                                return true;
 
381
                        }
 
382
 
 
383
                        $this->__errors[] = sprintf(__('%s NOT changed to %s', true), $path, $mode);
 
384
                        return false;
 
385
                }
 
386
 
 
387
                if (is_dir($path)) {
 
388
                        $paths = $this->tree($path);
 
389
 
 
390
                        foreach ($paths as $type) {
 
391
                                foreach ($type as $key => $fullpath) {
 
392
                                        $check = explode(DS, $fullpath);
 
393
                                        $count = count($check);
 
394
 
 
395
                                        if (in_array($check[$count - 1], $exceptions)) {
 
396
                                                continue;
 
397
                                        }
 
398
 
 
399
                                        if (@chmod($fullpath, intval($mode, 8))) {
 
400
                                                $this->__messages[] = sprintf(__('%s changed to %s', true), $fullpath, $mode);
 
401
                                        } else {
 
402
                                                $this->__errors[] = sprintf(__('%s NOT changed to %s', true), $fullpath, $mode);
 
403
                                        }
 
404
                                }
 
405
                        }
 
406
 
 
407
                        if (empty($this->__errors)) {
 
408
                                return true;
 
409
                        }
 
410
                }
 
411
                return false;
 
412
        }
 
413
 
 
414
/**
 
415
 * Returns an array of nested directories and files in each directory
 
416
 *
 
417
 * @param string $path the directory path to build the tree from
 
418
 * @param mixed $exceptions Array of files to exclude, defaults to excluding hidden files.
 
419
 * @param string $type either file or dir. null returns both files and directories
 
420
 * @return mixed array of nested directories and files in each directory
 
421
 * @access public
 
422
 */
 
423
        function tree($path, $exceptions = true, $type = null) {
 
424
                $original = $this->path;
 
425
                $path = rtrim($path, DS);
 
426
                if (!$this->cd($path)) {
 
427
                        if ($type === null) {
 
428
                                return array(array(), array());
 
429
                        }
 
430
                        return array();
 
431
                }
 
432
                $this->__files = array();
 
433
                $this->__directories = array($this->realpath($path));
 
434
                $directories = array();
 
435
 
 
436
                if ($exceptions === false) {
 
437
                        $exceptions = true;
 
438
                }
 
439
                while (!empty($this->__directories)) {
 
440
                        $dir = array_pop($this->__directories);
 
441
                        $this->__tree($dir, $exceptions);
 
442
                        $directories[] = $dir;
 
443
                }
 
444
 
 
445
                if ($type === null) {
 
446
                        return array($directories, $this->__files);
 
447
                }
 
448
                if ($type === 'dir') {
 
449
                        return $directories;
 
450
                }
 
451
                $this->cd($original);
 
452
 
 
453
                return $this->__files;
 
454
        }
 
455
 
 
456
/**
 
457
 * Private method to list directories and files in each directory
 
458
 *
 
459
 * @param string $path The Path to read.
 
460
 * @param mixed $exceptions Array of files to exclude from the read that will be performed.
 
461
 * @access private
 
462
 */
 
463
        function __tree($path, $exceptions) {
 
464
                $this->path = $path;
 
465
                list($dirs, $files) = $this->read(false, $exceptions, true);
 
466
                $this->__directories = array_merge($this->__directories, $dirs);
 
467
                $this->__files = array_merge($this->__files, $files);
 
468
        }
 
469
 
 
470
/**
 
471
 * Create a directory structure recursively. Can be used to create
 
472
 * deep path structures like `/foo/bar/baz/shoe/horn`
 
473
 *
 
474
 * @param string $pathname The directory structure to create
 
475
 * @param integer $mode octal value 0755
 
476
 * @return boolean Returns TRUE on success, FALSE on failure
 
477
 * @access public
 
478
 */
 
479
        function create($pathname, $mode = false) {
 
480
                if (is_dir($pathname) || empty($pathname)) {
 
481
                        return true;
 
482
                }
 
483
 
 
484
                if (!$mode) {
 
485
                        $mode = $this->mode;
 
486
                }
 
487
 
 
488
                if (is_file($pathname)) {
 
489
                        $this->__errors[] = sprintf(__('%s is a file', true), $pathname);
 
490
                        return false;
 
491
                }
 
492
                $pathname = rtrim($pathname, DS);
 
493
                $nextPathname = substr($pathname, 0, strrpos($pathname, DS));
 
494
 
 
495
                if ($this->create($nextPathname, $mode)) {
 
496
                        if (!file_exists($pathname)) {
 
497
                                $old = umask(0);
 
498
                                if (mkdir($pathname, $mode)) {
 
499
                                        umask($old);
 
500
                                        $this->__messages[] = sprintf(__('%s created', true), $pathname);
 
501
                                        return true;
 
502
                                } else {
 
503
                                        umask($old);
 
504
                                        $this->__errors[] = sprintf(__('%s NOT created', true), $pathname);
 
505
                                        return false;
 
506
                                }
 
507
                        }
 
508
                }
 
509
                return false;
 
510
        }
 
511
 
 
512
/**
 
513
 * Returns the size in bytes of this Folder and its contents.
 
514
 *
 
515
 * @param string $directory Path to directory
 
516
 * @return int size in bytes of current folder
 
517
 * @access public
 
518
 */
 
519
        function dirsize() {
 
520
                $size = 0;
 
521
                $directory = Folder::slashTerm($this->path);
 
522
                $stack = array($directory);
 
523
                $count = count($stack);
 
524
                for ($i = 0, $j = $count; $i < $j; ++$i) {
 
525
                        if (is_file($stack[$i])) {
 
526
                                $size += filesize($stack[$i]);
 
527
                        } elseif (is_dir($stack[$i])) {
 
528
                                $dir = dir($stack[$i]);
 
529
                                if ($dir) {
 
530
                                        while (false !== ($entry = $dir->read())) {
 
531
                                                if ($entry === '.' || $entry === '..') {
 
532
                                                        continue;
 
533
                                                }
 
534
                                                $add = $stack[$i] . $entry;
 
535
 
 
536
                                                if (is_dir($stack[$i] . $entry)) {
 
537
                                                        $add = Folder::slashTerm($add);
 
538
                                                }
 
539
                                                $stack[] = $add;
 
540
                                        }
 
541
                                        $dir->close();
 
542
                                }
 
543
                        }
 
544
                        $j = count($stack);
 
545
                }
 
546
                return $size;
 
547
        }
 
548
 
 
549
/**
 
550
 * Recursively Remove directories if the system allows.
 
551
 *
 
552
 * @param string $path Path of directory to delete
 
553
 * @return boolean Success
 
554
 * @access public
 
555
 */
 
556
        function delete($path = null) {
 
557
                if (!$path) {
 
558
                        $path = $this->pwd();
 
559
                }
 
560
                if (!$path) {
 
561
                        return null;
 
562
                }
 
563
                $path = Folder::slashTerm($path);
 
564
                if (is_dir($path) === true) {
 
565
                        $normalFiles = glob($path . '*');
 
566
                        $hiddenFiles = glob($path . '\.?*');
 
567
 
 
568
                        $normalFiles = $normalFiles ? $normalFiles : array();
 
569
                        $hiddenFiles = $hiddenFiles ? $hiddenFiles : array();
 
570
 
 
571
                        $files = array_merge($normalFiles, $hiddenFiles);
 
572
                        if (is_array($files)) {
 
573
                                foreach ($files as $file) {
 
574
                                        if (preg_match('/(\.|\.\.)$/', $file)) {
 
575
                                                continue;
 
576
                                        }
 
577
                                        if (is_file($file) === true) {
 
578
                                                if (@unlink($file)) {
 
579
                                                        $this->__messages[] = sprintf(__('%s removed', true), $file);
 
580
                                                } else {
 
581
                                                        $this->__errors[] = sprintf(__('%s NOT removed', true), $file);
 
582
                                                }
 
583
                                        } elseif (is_dir($file) === true && $this->delete($file) === false) {
 
584
                                                return false;
 
585
                                        }
 
586
                                }
 
587
                        }
 
588
                        $path = substr($path, 0, strlen($path) - 1);
 
589
                        if (rmdir($path) === false) {
 
590
                                $this->__errors[] = sprintf(__('%s NOT removed', true), $path);
 
591
                                return false;
 
592
                        } else {
 
593
                                $this->__messages[] = sprintf(__('%s removed', true), $path);
 
594
                        }
 
595
                }
 
596
                return true;
 
597
        }
 
598
 
 
599
/**
 
600
 * Recursive directory copy.
 
601
 *
 
602
 * ### Options
 
603
 *
 
604
 * - `to` The directory to copy to.
 
605
 * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
 
606
 * - `chmod` The mode to copy the files/directories with.
 
607
 * - `skip` Files/directories to skip.
 
608
 *
 
609
 * @param mixed $options Either an array of options (see above) or a string of the destination directory.
 
610
 * @return bool Success
 
611
 * @access public
 
612
 */
 
613
        function copy($options = array()) {
 
614
                if (!$this->pwd()) {
 
615
                        return false;
 
616
                }
 
617
                $to = null;
 
618
                if (is_string($options)) {
 
619
                        $to = $options;
 
620
                        $options = array();
 
621
                }
 
622
                $options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options);
 
623
 
 
624
                $fromDir = $options['from'];
 
625
                $toDir = $options['to'];
 
626
                $mode = $options['mode'];
 
627
 
 
628
                if (!$this->cd($fromDir)) {
 
629
                        $this->__errors[] = sprintf(__('%s not found', true), $fromDir);
 
630
                        return false;
 
631
                }
 
632
 
 
633
                if (!is_dir($toDir)) {
 
634
                        $this->create($toDir, $mode);
 
635
                }
 
636
 
 
637
                if (!is_writable($toDir)) {
 
638
                        $this->__errors[] = sprintf(__('%s not writable', true), $toDir);
 
639
                        return false;
 
640
                }
 
641
 
 
642
                $exceptions = array_merge(array('.', '..', '.svn'), $options['skip']);
 
643
                if ($handle = @opendir($fromDir)) {
 
644
                        while (false !== ($item = readdir($handle))) {
 
645
                                if (!in_array($item, $exceptions)) {
 
646
                                        $from = Folder::addPathElement($fromDir, $item);
 
647
                                        $to = Folder::addPathElement($toDir, $item);
 
648
                                        if (is_file($from)) {
 
649
                                                if (copy($from, $to)) {
 
650
                                                        chmod($to, intval($mode, 8));
 
651
                                                        touch($to, filemtime($from));
 
652
                                                        $this->__messages[] = sprintf(__('%s copied to %s', true), $from, $to);
 
653
                                                } else {
 
654
                                                        $this->__errors[] = sprintf(__('%s NOT copied to %s', true), $from, $to);
 
655
                                                }
 
656
                                        }
 
657
 
 
658
                                        if (is_dir($from) && !file_exists($to)) {
 
659
                                                $old = umask(0);
 
660
                                                if (mkdir($to, $mode)) {
 
661
                                                        umask($old);
 
662
                                                        $old = umask(0);
 
663
                                                        chmod($to, $mode);
 
664
                                                        umask($old);
 
665
                                                        $this->__messages[] = sprintf(__('%s created', true), $to);
 
666
                                                        $options = array_merge($options, array('to'=> $to, 'from'=> $from));
 
667
                                                        $this->copy($options);
 
668
                                                } else {
 
669
                                                        $this->__errors[] = sprintf(__('%s not created', true), $to);
 
670
                                                }
 
671
                                        }
 
672
                                }
 
673
                        }
 
674
                        closedir($handle);
 
675
                } else {
 
676
                        return false;
 
677
                }
 
678
 
 
679
                if (!empty($this->__errors)) {
 
680
                        return false;
 
681
                }
 
682
                return true;
 
683
        }
 
684
 
 
685
/**
 
686
 * Recursive directory move.
 
687
 *
 
688
 * ### Options
 
689
 *
 
690
 * - `to` The directory to copy to.
 
691
 * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
 
692
 * - `chmod` The mode to copy the files/directories with.
 
693
 * - `skip` Files/directories to skip.
 
694
 *
 
695
 * @param array $options (to, from, chmod, skip)
 
696
 * @return boolean Success
 
697
 * @access public
 
698
 */
 
699
        function move($options) {
 
700
                $to = null;
 
701
                if (is_string($options)) {
 
702
                        $to = $options;
 
703
                        $options = (array)$options;
 
704
                }
 
705
                $options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options);
 
706
 
 
707
                if ($this->copy($options)) {
 
708
                        if ($this->delete($options['from'])) {
 
709
                                return $this->cd($options['to']);
 
710
                        }
 
711
                }
 
712
                return false;
 
713
        }
 
714
 
 
715
/**
 
716
 * get messages from latest method
 
717
 *
 
718
 * @return array
 
719
 * @access public
 
720
 */
 
721
        function messages() {
 
722
                return $this->__messages;
 
723
        }
 
724
 
 
725
/**
 
726
 * get error from latest method
 
727
 *
 
728
 * @return array
 
729
 * @access public
 
730
 */
 
731
        function errors() {
 
732
                return $this->__errors;
 
733
        }
 
734
 
 
735
/**
 
736
 * Get the real path (taking ".." and such into account)
 
737
 *
 
738
 * @param string $path Path to resolve
 
739
 * @return string The resolved path
 
740
 */
 
741
        function realpath($path) {
 
742
                $path = str_replace('/', DS, trim($path));
 
743
                if (strpos($path, '..') === false) {
 
744
                        if (!Folder::isAbsolute($path)) {
 
745
                                $path = Folder::addPathElement($this->path, $path);
 
746
                        }
 
747
                        return $path;
 
748
                }
 
749
                $parts = explode(DS, $path);
 
750
                $newparts = array();
 
751
                $newpath = '';
 
752
                if ($path[0] === DS) {
 
753
                        $newpath = DS;
 
754
                }
 
755
 
 
756
                while (($part = array_shift($parts)) !== NULL) {
 
757
                        if ($part === '.' || $part === '') {
 
758
                                continue;
 
759
                        }
 
760
                        if ($part === '..') {
 
761
                                if (!empty($newparts)) {
 
762
                                        array_pop($newparts);
 
763
                                        continue;
 
764
                                } else {
 
765
                                        return false;
 
766
                                }
 
767
                        }
 
768
                        $newparts[] = $part;
 
769
                }
 
770
                $newpath .= implode(DS, $newparts);
 
771
 
 
772
                return Folder::slashTerm($newpath);
 
773
        }
 
774
 
 
775
/**
 
776
 * Returns true if given $path ends in a slash (i.e. is slash-terminated).
 
777
 *
 
778
 * @param string $path Path to check
 
779
 * @return boolean true if path ends with slash, false otherwise
 
780
 * @access public
 
781
 * @static
 
782
 */
 
783
        function isSlashTerm($path) {
 
784
                $lastChar = $path[strlen($path) - 1];
 
785
                return $lastChar === '/' || $lastChar === '\\';
 
786
        }
 
787
}