CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.7 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.7
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • File
  • Folder
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   5:  *
   6:  * Licensed under The MIT License
   7:  * For full copyright and license information, please see the LICENSE.txt
   8:  * Redistributions of files must retain the above copyright notice.
   9:  *
  10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11:  * @link          https://cakephp.org CakePHP(tm) Project
  12:  * @since         0.2.9
  13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  14:  */
  15: namespace Cake\Filesystem;
  16: 
  17: use DirectoryIterator;
  18: use Exception;
  19: use InvalidArgumentException;
  20: use RecursiveDirectoryIterator;
  21: use RecursiveIteratorIterator;
  22: 
  23: /**
  24:  * Folder structure browser, lists folders and files.
  25:  * Provides an Object interface for Common directory related tasks.
  26:  *
  27:  * @link https://book.cakephp.org/3.0/en/core-libraries/file-folder.html#folder-api
  28:  */
  29: class Folder
  30: {
  31: 
  32:     /**
  33:      * Default scheme for Folder::copy
  34:      * Recursively merges subfolders with the same name
  35:      *
  36:      * @var string
  37:      */
  38:     const MERGE = 'merge';
  39: 
  40:     /**
  41:      * Overwrite scheme for Folder::copy
  42:      * subfolders with the same name will be replaced
  43:      *
  44:      * @var string
  45:      */
  46:     const OVERWRITE = 'overwrite';
  47: 
  48:     /**
  49:      * Skip scheme for Folder::copy
  50:      * if a subfolder with the same name exists it will be skipped
  51:      *
  52:      * @var string
  53:      */
  54:     const SKIP = 'skip';
  55: 
  56:     /**
  57:      * Sort mode by name
  58:      *
  59:      * @var string
  60:      */
  61:     const SORT_NAME = 'name';
  62: 
  63:     /**
  64:      * Sort mode by time
  65:      *
  66:      * @var string
  67:      */
  68:     const SORT_TIME = 'time';
  69: 
  70:     /**
  71:      * Path to Folder.
  72:      *
  73:      * @var string
  74:      */
  75:     public $path;
  76: 
  77:     /**
  78:      * Sortedness. Whether or not list results
  79:      * should be sorted by name.
  80:      *
  81:      * @var bool
  82:      */
  83:     public $sort = false;
  84: 
  85:     /**
  86:      * Mode to be used on create. Does nothing on windows platforms.
  87:      *
  88:      * @var int
  89:      * https://book.cakephp.org/3.0/en/core-libraries/file-folder.html#Cake\Filesystem\Folder::$mode
  90:      */
  91:     public $mode = 0755;
  92: 
  93:     /**
  94:      * Functions array to be called depending on the sort type chosen.
  95:      */
  96:     protected $_fsorts = [
  97:         self::SORT_NAME => 'getPathname',
  98:         self::SORT_TIME => 'getCTime'
  99:     ];
 100: 
 101:     /**
 102:      * Holds messages from last method.
 103:      *
 104:      * @var array
 105:      */
 106:     protected $_messages = [];
 107: 
 108:     /**
 109:      * Holds errors from last method.
 110:      *
 111:      * @var array
 112:      */
 113:     protected $_errors = [];
 114: 
 115:     /**
 116:      * Holds array of complete directory paths.
 117:      *
 118:      * @var array
 119:      */
 120:     protected $_directories;
 121: 
 122:     /**
 123:      * Holds array of complete file paths.
 124:      *
 125:      * @var array
 126:      */
 127:     protected $_files;
 128: 
 129:     /**
 130:      * Constructor.
 131:      *
 132:      * @param string|null $path Path to folder
 133:      * @param bool $create Create folder if not found
 134:      * @param int|false $mode Mode (CHMOD) to apply to created folder, false to ignore
 135:      */
 136:     public function __construct($path = null, $create = false, $mode = false)
 137:     {
 138:         if (empty($path)) {
 139:             $path = TMP;
 140:         }
 141:         if ($mode) {
 142:             $this->mode = $mode;
 143:         }
 144: 
 145:         if (!file_exists($path) && $create === true) {
 146:             $this->create($path, $this->mode);
 147:         }
 148:         if (!Folder::isAbsolute($path)) {
 149:             $path = realpath($path);
 150:         }
 151:         if (!empty($path)) {
 152:             $this->cd($path);
 153:         }
 154:     }
 155: 
 156:     /**
 157:      * Return current path.
 158:      *
 159:      * @return string Current path
 160:      */
 161:     public function pwd()
 162:     {
 163:         return $this->path;
 164:     }
 165: 
 166:     /**
 167:      * Change directory to $path.
 168:      *
 169:      * @param string $path Path to the directory to change to
 170:      * @return string|bool The new path. Returns false on failure
 171:      */
 172:     public function cd($path)
 173:     {
 174:         $path = $this->realpath($path);
 175:         if ($path !== false && is_dir($path)) {
 176:             return $this->path = $path;
 177:         }
 178: 
 179:         return false;
 180:     }
 181: 
 182:     /**
 183:      * Returns an array of the contents of the current directory.
 184:      * The returned array holds two arrays: One of directories and one of files.
 185:      *
 186:      * @param string|bool $sort Whether you want the results sorted, set this and the sort property
 187:      *   to false to get unsorted results.
 188:      * @param array|bool $exceptions Either an array or boolean true will not grab dot files
 189:      * @param bool $fullPath True returns the full path
 190:      * @return array Contents of current directory as an array, an empty array on failure
 191:      */
 192:     public function read($sort = self::SORT_NAME, $exceptions = false, $fullPath = false)
 193:     {
 194:         $dirs = $files = [];
 195: 
 196:         if (!$this->pwd()) {
 197:             return [$dirs, $files];
 198:         }
 199:         if (is_array($exceptions)) {
 200:             $exceptions = array_flip($exceptions);
 201:         }
 202:         $skipHidden = isset($exceptions['.']) || $exceptions === true;
 203: 
 204:         try {
 205:             $iterator = new DirectoryIterator($this->path);
 206:         } catch (Exception $e) {
 207:             return [$dirs, $files];
 208:         }
 209: 
 210:         if (!is_bool($sort) && isset($this->_fsorts[$sort])) {
 211:             $methodName = $this->_fsorts[$sort];
 212:         } else {
 213:             $methodName = $this->_fsorts[self::SORT_NAME];
 214:         }
 215: 
 216:         foreach ($iterator as $item) {
 217:             if ($item->isDot()) {
 218:                 continue;
 219:             }
 220:             $name = $item->getFilename();
 221:             if ($skipHidden && $name[0] === '.' || isset($exceptions[$name])) {
 222:                 continue;
 223:             }
 224:             if ($fullPath) {
 225:                 $name = $item->getPathname();
 226:             }
 227: 
 228:             if ($item->isDir()) {
 229:                 $dirs[$item->{$methodName}()][] = $name;
 230:             } else {
 231:                 $files[$item->{$methodName}()][] = $name;
 232:             }
 233:         }
 234: 
 235:         if ($sort || $this->sort) {
 236:             ksort($dirs);
 237:             ksort($files);
 238:         }
 239: 
 240:         if ($dirs) {
 241:             $dirs = array_merge(...array_values($dirs));
 242:         }
 243: 
 244:         if ($files) {
 245:             $files = array_merge(...array_values($files));
 246:         }
 247: 
 248:         return [$dirs, $files];
 249:     }
 250: 
 251:     /**
 252:      * Returns an array of all matching files in current directory.
 253:      *
 254:      * @param string $regexpPattern Preg_match pattern (Defaults to: .*)
 255:      * @param bool $sort Whether results should be sorted.
 256:      * @return array Files that match given pattern
 257:      */
 258:     public function find($regexpPattern = '.*', $sort = false)
 259:     {
 260:         list(, $files) = $this->read($sort);
 261: 
 262:         return array_values(preg_grep('/^' . $regexpPattern . '$/i', $files));
 263:     }
 264: 
 265:     /**
 266:      * Returns an array of all matching files in and below current directory.
 267:      *
 268:      * @param string $pattern Preg_match pattern (Defaults to: .*)
 269:      * @param bool $sort Whether results should be sorted.
 270:      * @return array Files matching $pattern
 271:      */
 272:     public function findRecursive($pattern = '.*', $sort = false)
 273:     {
 274:         if (!$this->pwd()) {
 275:             return [];
 276:         }
 277:         $startsOn = $this->path;
 278:         $out = $this->_findRecursive($pattern, $sort);
 279:         $this->cd($startsOn);
 280: 
 281:         return $out;
 282:     }
 283: 
 284:     /**
 285:      * Private helper function for findRecursive.
 286:      *
 287:      * @param string $pattern Pattern to match against
 288:      * @param bool $sort Whether results should be sorted.
 289:      * @return array Files matching pattern
 290:      */
 291:     protected function _findRecursive($pattern, $sort = false)
 292:     {
 293:         list($dirs, $files) = $this->read($sort);
 294:         $found = [];
 295: 
 296:         foreach ($files as $file) {
 297:             if (preg_match('/^' . $pattern . '$/i', $file)) {
 298:                 $found[] = Folder::addPathElement($this->path, $file);
 299:             }
 300:         }
 301:         $start = $this->path;
 302: 
 303:         foreach ($dirs as $dir) {
 304:             $this->cd(Folder::addPathElement($start, $dir));
 305:             $found = array_merge($found, $this->findRecursive($pattern, $sort));
 306:         }
 307: 
 308:         return $found;
 309:     }
 310: 
 311:     /**
 312:      * Returns true if given $path is a Windows path.
 313:      *
 314:      * @param string $path Path to check
 315:      * @return bool true if windows path, false otherwise
 316:      */
 317:     public static function isWindowsPath($path)
 318:     {
 319:         return (preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) === '\\\\');
 320:     }
 321: 
 322:     /**
 323:      * Returns true if given $path is an absolute path.
 324:      *
 325:      * @param string $path Path to check
 326:      * @return bool true if path is absolute.
 327:      */
 328:     public static function isAbsolute($path)
 329:     {
 330:         if (empty($path)) {
 331:             return false;
 332:         }
 333: 
 334:         return $path[0] === '/' ||
 335:             preg_match('/^[A-Z]:\\\\/i', $path) ||
 336:             substr($path, 0, 2) === '\\\\' ||
 337:             self::isRegisteredStreamWrapper($path);
 338:     }
 339: 
 340:     /**
 341:      * Returns true if given $path is a registered stream wrapper.
 342:      *
 343:      * @param string $path Path to check
 344:      * @return bool True if path is registered stream wrapper.
 345:      */
 346:     public static function isRegisteredStreamWrapper($path)
 347:     {
 348:         return preg_match('/^[^:\/\/]+?(?=:\/\/)/', $path, $matches) &&
 349:             in_array($matches[0], stream_get_wrappers());
 350:     }
 351: 
 352:     /**
 353:      * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
 354:      *
 355:      * @param string $path Path to check
 356:      * @return string Set of slashes ("\\" or "/")
 357:      *
 358:      * @deprecated 3.7.0 This method will be removed in 4.0.0. Use correctSlashFor() instead.
 359:      */
 360:     public static function normalizePath($path)
 361:     {
 362:         deprecationWarning('Folder::normalizePath() is deprecated. Use Folder::correctSlashFor() instead.');
 363: 
 364:         return Folder::correctSlashFor($path);
 365:     }
 366: 
 367:     /**
 368:      * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
 369:      *
 370:      * @param string $path Path to transform
 371:      * @return string Path with the correct set of slashes ("\\" or "/")
 372:      */
 373:     public static function normalizeFullPath($path)
 374:     {
 375:         $to = Folder::correctSlashFor($path);
 376:         $from = ($to == '/' ? '\\' : '/');
 377: 
 378:         return str_replace($from, $to, $path);
 379:     }
 380: 
 381:     /**
 382:      * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
 383:      *
 384:      * @param string $path Path to check
 385:      * @return string Set of slashes ("\\" or "/")
 386:      */
 387:     public static function correctSlashFor($path)
 388:     {
 389:         return Folder::isWindowsPath($path) ? '\\' : '/';
 390:     }
 391: 
 392:     /**
 393:      * Returns $path with added terminating slash (corrected for Windows or other OS).
 394:      *
 395:      * @param string $path Path to check
 396:      * @return string Path with ending slash
 397:      */
 398:     public static function slashTerm($path)
 399:     {
 400:         if (Folder::isSlashTerm($path)) {
 401:             return $path;
 402:         }
 403: 
 404:         return $path . Folder::correctSlashFor($path);
 405:     }
 406: 
 407:     /**
 408:      * Returns $path with $element added, with correct slash in-between.
 409:      *
 410:      * @param string $path Path
 411:      * @param string|array $element Element to add at end of path
 412:      * @return string Combined path
 413:      */
 414:     public static function addPathElement($path, $element)
 415:     {
 416:         $element = (array)$element;
 417:         array_unshift($element, rtrim($path, DIRECTORY_SEPARATOR));
 418: 
 419:         return implode(DIRECTORY_SEPARATOR, $element);
 420:     }
 421: 
 422:     /**
 423:      * Returns true if the Folder is in the given Cake path.
 424:      *
 425:      * @param string $path The path to check.
 426:      * @return bool
 427:      * @deprecated 3.2.12 This method will be removed in 4.0.0. Use inPath() instead.
 428:      */
 429:     public function inCakePath($path = '')
 430:     {
 431:         deprecationWarning('Folder::inCakePath() is deprecated. Use Folder::inPath() instead.');
 432:         $dir = substr(Folder::slashTerm(ROOT), 0, -1);
 433:         $newdir = $dir . $path;
 434: 
 435:         return $this->inPath($newdir);
 436:     }
 437: 
 438:     /**
 439:      * Returns true if the Folder is in the given path.
 440:      *
 441:      * @param string $path The absolute path to check that the current `pwd()` resides within.
 442:      * @param bool $reverse Reverse the search, check if the given `$path` resides within the current `pwd()`.
 443:      * @return bool
 444:      * @throws \InvalidArgumentException When the given `$path` argument is not an absolute path.
 445:      */
 446:     public function inPath($path, $reverse = false)
 447:     {
 448:         if (!Folder::isAbsolute($path)) {
 449:             throw new InvalidArgumentException('The $path argument is expected to be an absolute path.');
 450:         }
 451: 
 452:         $dir = Folder::slashTerm($path);
 453:         $current = Folder::slashTerm($this->pwd());
 454: 
 455:         if (!$reverse) {
 456:             $return = preg_match('/^' . preg_quote($dir, '/') . '(.*)/', $current);
 457:         } else {
 458:             $return = preg_match('/^' . preg_quote($current, '/') . '(.*)/', $dir);
 459:         }
 460: 
 461:         return (bool)$return;
 462:     }
 463: 
 464:     /**
 465:      * Change the mode on a directory structure recursively. This includes changing the mode on files as well.
 466:      *
 467:      * @param string $path The path to chmod.
 468:      * @param int|bool $mode Octal value, e.g. 0755.
 469:      * @param bool $recursive Chmod recursively, set to false to only change the current directory.
 470:      * @param array $exceptions Array of files, directories to skip.
 471:      * @return bool Success.
 472:      */
 473:     public function chmod($path, $mode = false, $recursive = true, array $exceptions = [])
 474:     {
 475:         if (!$mode) {
 476:             $mode = $this->mode;
 477:         }
 478: 
 479:         if ($recursive === false && is_dir($path)) {
 480:             //@codingStandardsIgnoreStart
 481:             if (@chmod($path, intval($mode, 8))) {
 482:                 //@codingStandardsIgnoreEnd
 483:                 $this->_messages[] = sprintf('%s changed to %s', $path, $mode);
 484: 
 485:                 return true;
 486:             }
 487: 
 488:             $this->_errors[] = sprintf('%s NOT changed to %s', $path, $mode);
 489: 
 490:             return false;
 491:         }
 492: 
 493:         if (is_dir($path)) {
 494:             $paths = $this->tree($path);
 495: 
 496:             foreach ($paths as $type) {
 497:                 foreach ($type as $fullpath) {
 498:                     $check = explode(DIRECTORY_SEPARATOR, $fullpath);
 499:                     $count = count($check);
 500: 
 501:                     if (in_array($check[$count - 1], $exceptions)) {
 502:                         continue;
 503:                     }
 504: 
 505:                     //@codingStandardsIgnoreStart
 506:                     if (@chmod($fullpath, intval($mode, 8))) {
 507:                         //@codingStandardsIgnoreEnd
 508:                         $this->_messages[] = sprintf('%s changed to %s', $fullpath, $mode);
 509:                     } else {
 510:                         $this->_errors[] = sprintf('%s NOT changed to %s', $fullpath, $mode);
 511:                     }
 512:                 }
 513:             }
 514: 
 515:             if (empty($this->_errors)) {
 516:                 return true;
 517:             }
 518:         }
 519: 
 520:         return false;
 521:     }
 522: 
 523:     /**
 524:      * Returns an array of subdirectories for the provided or current path.
 525:      *
 526:      * @param string|null $path The directory path to get subdirectories for.
 527:      * @param bool $fullPath Whether to return the full path or only the directory name.
 528:      * @return array Array of subdirectories for the provided or current path.
 529:      */
 530:     public function subdirectories($path = null, $fullPath = true)
 531:     {
 532:         if (!$path) {
 533:             $path = $this->path;
 534:         }
 535:         $subdirectories = [];
 536: 
 537:         try {
 538:             $iterator = new DirectoryIterator($path);
 539:         } catch (Exception $e) {
 540:             return [];
 541:         }
 542: 
 543:         foreach ($iterator as $item) {
 544:             if (!$item->isDir() || $item->isDot()) {
 545:                 continue;
 546:             }
 547:             $subdirectories[] = $fullPath ? $item->getRealPath() : $item->getFilename();
 548:         }
 549: 
 550:         return $subdirectories;
 551:     }
 552: 
 553:     /**
 554:      * Returns an array of nested directories and files in each directory
 555:      *
 556:      * @param string|null $path the directory path to build the tree from
 557:      * @param array|bool $exceptions Either an array of files/folder to exclude
 558:      *   or boolean true to not grab dot files/folders
 559:      * @param string|null $type either 'file' or 'dir'. Null returns both files and directories
 560:      * @return array Array of nested directories and files in each directory
 561:      */
 562:     public function tree($path = null, $exceptions = false, $type = null)
 563:     {
 564:         if (!$path) {
 565:             $path = $this->path;
 566:         }
 567:         $files = [];
 568:         $directories = [$path];
 569: 
 570:         if (is_array($exceptions)) {
 571:             $exceptions = array_flip($exceptions);
 572:         }
 573:         $skipHidden = false;
 574:         if ($exceptions === true) {
 575:             $skipHidden = true;
 576:         } elseif (isset($exceptions['.'])) {
 577:             $skipHidden = true;
 578:             unset($exceptions['.']);
 579:         }
 580: 
 581:         try {
 582:             $directory = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME | RecursiveDirectoryIterator::CURRENT_AS_SELF);
 583:             $iterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);
 584:         } catch (Exception $e) {
 585:             if ($type === null) {
 586:                 return [[], []];
 587:             }
 588: 
 589:             return [];
 590:         }
 591: 
 592:         /**
 593:          * @var string $itemPath
 594:          * @var \RecursiveDirectoryIterator $fsIterator
 595:          */
 596:         foreach ($iterator as $itemPath => $fsIterator) {
 597:             if ($skipHidden) {
 598:                 $subPathName = $fsIterator->getSubPathname();
 599:                 if ($subPathName{0} === '.' || strpos($subPathName, DIRECTORY_SEPARATOR . '.') !== false) {
 600:                     continue;
 601:                 }
 602:             }
 603:             /** @var \FilesystemIterator $item */
 604:             $item = $fsIterator->current();
 605:             if (!empty($exceptions) && isset($exceptions[$item->getFilename()])) {
 606:                 continue;
 607:             }
 608: 
 609:             if ($item->isFile()) {
 610:                 $files[] = $itemPath;
 611:             } elseif ($item->isDir() && !$item->isDot()) {
 612:                 $directories[] = $itemPath;
 613:             }
 614:         }
 615:         if ($type === null) {
 616:             return [$directories, $files];
 617:         }
 618:         if ($type === 'dir') {
 619:             return $directories;
 620:         }
 621: 
 622:         return $files;
 623:     }
 624: 
 625:     /**
 626:      * Create a directory structure recursively.
 627:      *
 628:      * Can be used to create deep path structures like `/foo/bar/baz/shoe/horn`
 629:      *
 630:      * @param string $pathname The directory structure to create. Either an absolute or relative
 631:      *   path. If the path is relative and exists in the process' cwd it will not be created.
 632:      *   Otherwise relative paths will be prefixed with the current pwd().
 633:      * @param int|bool $mode octal value 0755
 634:      * @return bool Returns TRUE on success, FALSE on failure
 635:      */
 636:     public function create($pathname, $mode = false)
 637:     {
 638:         if (is_dir($pathname) || empty($pathname)) {
 639:             return true;
 640:         }
 641: 
 642:         if (!self::isAbsolute($pathname)) {
 643:             $pathname = self::addPathElement($this->pwd(), $pathname);
 644:         }
 645: 
 646:         if (!$mode) {
 647:             $mode = $this->mode;
 648:         }
 649: 
 650:         if (is_file($pathname)) {
 651:             $this->_errors[] = sprintf('%s is a file', $pathname);
 652: 
 653:             return false;
 654:         }
 655:         $pathname = rtrim($pathname, DIRECTORY_SEPARATOR);
 656:         $nextPathname = substr($pathname, 0, strrpos($pathname, DIRECTORY_SEPARATOR));
 657: 
 658:         if ($this->create($nextPathname, $mode)) {
 659:             if (!file_exists($pathname)) {
 660:                 $old = umask(0);
 661:                 if (mkdir($pathname, $mode, true)) {
 662:                     umask($old);
 663:                     $this->_messages[] = sprintf('%s created', $pathname);
 664: 
 665:                     return true;
 666:                 }
 667:                 umask($old);
 668:                 $this->_errors[] = sprintf('%s NOT created', $pathname);
 669: 
 670:                 return false;
 671:             }
 672:         }
 673: 
 674:         return false;
 675:     }
 676: 
 677:     /**
 678:      * Returns the size in bytes of this Folder and its contents.
 679:      *
 680:      * @return int size in bytes of current folder
 681:      */
 682:     public function dirsize()
 683:     {
 684:         $size = 0;
 685:         $directory = Folder::slashTerm($this->path);
 686:         $stack = [$directory];
 687:         $count = count($stack);
 688:         for ($i = 0, $j = $count; $i < $j; $i++) {
 689:             if (is_file($stack[$i])) {
 690:                 $size += filesize($stack[$i]);
 691:             } elseif (is_dir($stack[$i])) {
 692:                 $dir = dir($stack[$i]);
 693:                 if ($dir) {
 694:                     while (($entry = $dir->read()) !== false) {
 695:                         if ($entry === '.' || $entry === '..') {
 696:                             continue;
 697:                         }
 698:                         $add = $stack[$i] . $entry;
 699: 
 700:                         if (is_dir($stack[$i] . $entry)) {
 701:                             $add = Folder::slashTerm($add);
 702:                         }
 703:                         $stack[] = $add;
 704:                     }
 705:                     $dir->close();
 706:                 }
 707:             }
 708:             $j = count($stack);
 709:         }
 710: 
 711:         return $size;
 712:     }
 713: 
 714:     /**
 715:      * Recursively Remove directories if the system allows.
 716:      *
 717:      * @param string|null $path Path of directory to delete
 718:      * @return bool Success
 719:      */
 720:     public function delete($path = null)
 721:     {
 722:         if (!$path) {
 723:             $path = $this->pwd();
 724:         }
 725:         if (!$path) {
 726:             return false;
 727:         }
 728:         $path = Folder::slashTerm($path);
 729:         if (is_dir($path)) {
 730:             try {
 731:                 $directory = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::CURRENT_AS_SELF);
 732:                 $iterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::CHILD_FIRST);
 733:             } catch (Exception $e) {
 734:                 return false;
 735:             }
 736: 
 737:             foreach ($iterator as $item) {
 738:                 $filePath = $item->getPathname();
 739:                 if ($item->isFile() || $item->isLink()) {
 740:                     //@codingStandardsIgnoreStart
 741:                     if (@unlink($filePath)) {
 742:                         //@codingStandardsIgnoreEnd
 743:                         $this->_messages[] = sprintf('%s removed', $filePath);
 744:                     } else {
 745:                         $this->_errors[] = sprintf('%s NOT removed', $filePath);
 746:                     }
 747:                 } elseif ($item->isDir() && !$item->isDot()) {
 748:                     //@codingStandardsIgnoreStart
 749:                     if (@rmdir($filePath)) {
 750:                         //@codingStandardsIgnoreEnd
 751:                         $this->_messages[] = sprintf('%s removed', $filePath);
 752:                     } else {
 753:                         $this->_errors[] = sprintf('%s NOT removed', $filePath);
 754: 
 755:                         return false;
 756:                     }
 757:                 }
 758:             }
 759: 
 760:             $path = rtrim($path, DIRECTORY_SEPARATOR);
 761:             //@codingStandardsIgnoreStart
 762:             if (@rmdir($path)) {
 763:                 //@codingStandardsIgnoreEnd
 764:                 $this->_messages[] = sprintf('%s removed', $path);
 765:             } else {
 766:                 $this->_errors[] = sprintf('%s NOT removed', $path);
 767: 
 768:                 return false;
 769:             }
 770:         }
 771: 
 772:         return true;
 773:     }
 774: 
 775:     /**
 776:      * Recursive directory copy.
 777:      *
 778:      * ### Options
 779:      *
 780:      * - `to` The directory to copy to.
 781:      * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
 782:      * - `mode` The mode to copy the files/directories with as integer, e.g. 0775.
 783:      * - `skip` Files/directories to skip.
 784:      * - `scheme` Folder::MERGE, Folder::OVERWRITE, Folder::SKIP
 785:      * - `recursive` Whether to copy recursively or not (default: true - recursive)
 786:      *
 787:      * @param array|string $options Either an array of options (see above) or a string of the destination directory.
 788:      * @return bool Success.
 789:      */
 790:     public function copy($options)
 791:     {
 792:         if (!$this->pwd()) {
 793:             return false;
 794:         }
 795:         $to = null;
 796:         if (is_string($options)) {
 797:             $to = $options;
 798:             $options = [];
 799:         }
 800:         $options += [
 801:             'to' => $to,
 802:             'from' => $this->path,
 803:             'mode' => $this->mode,
 804:             'skip' => [],
 805:             'scheme' => Folder::MERGE,
 806:             'recursive' => true
 807:         ];
 808: 
 809:         $fromDir = $options['from'];
 810:         $toDir = $options['to'];
 811:         $mode = $options['mode'];
 812: 
 813:         if (!$this->cd($fromDir)) {
 814:             $this->_errors[] = sprintf('%s not found', $fromDir);
 815: 
 816:             return false;
 817:         }
 818: 
 819:         if (!is_dir($toDir)) {
 820:             $this->create($toDir, $mode);
 821:         }
 822: 
 823:         if (!is_writable($toDir)) {
 824:             $this->_errors[] = sprintf('%s not writable', $toDir);
 825: 
 826:             return false;
 827:         }
 828: 
 829:         $exceptions = array_merge(['.', '..', '.svn'], $options['skip']);
 830:         //@codingStandardsIgnoreStart
 831:         if ($handle = @opendir($fromDir)) {
 832:             //@codingStandardsIgnoreEnd
 833:             while (($item = readdir($handle)) !== false) {
 834:                 $to = Folder::addPathElement($toDir, $item);
 835:                 if (($options['scheme'] != Folder::SKIP || !is_dir($to)) && !in_array($item, $exceptions)) {
 836:                     $from = Folder::addPathElement($fromDir, $item);
 837:                     if (is_file($from) && (!is_file($to) || $options['scheme'] != Folder::SKIP)) {
 838:                         if (copy($from, $to)) {
 839:                             chmod($to, intval($mode, 8));
 840:                             touch($to, filemtime($from));
 841:                             $this->_messages[] = sprintf('%s copied to %s', $from, $to);
 842:                         } else {
 843:                             $this->_errors[] = sprintf('%s NOT copied to %s', $from, $to);
 844:                         }
 845:                     }
 846: 
 847:                     if (is_dir($from) && file_exists($to) && $options['scheme'] === Folder::OVERWRITE) {
 848:                         $this->delete($to);
 849:                     }
 850: 
 851:                     if (is_dir($from) && $options['recursive'] === false) {
 852:                         continue;
 853:                     }
 854: 
 855:                     if (is_dir($from) && !file_exists($to)) {
 856:                         $old = umask(0);
 857:                         if (mkdir($to, $mode, true)) {
 858:                             umask($old);
 859:                             $old = umask(0);
 860:                             chmod($to, $mode);
 861:                             umask($old);
 862:                             $this->_messages[] = sprintf('%s created', $to);
 863:                             $options = ['to' => $to, 'from' => $from] + $options;
 864:                             $this->copy($options);
 865:                         } else {
 866:                             $this->_errors[] = sprintf('%s not created', $to);
 867:                         }
 868:                     } elseif (is_dir($from) && $options['scheme'] === Folder::MERGE) {
 869:                         $options = ['to' => $to, 'from' => $from] + $options;
 870:                         $this->copy($options);
 871:                     }
 872:                 }
 873:             }
 874:             closedir($handle);
 875:         } else {
 876:             return false;
 877:         }
 878: 
 879:         return empty($this->_errors);
 880:     }
 881: 
 882:     /**
 883:      * Recursive directory move.
 884:      *
 885:      * ### Options
 886:      *
 887:      * - `to` The directory to copy to.
 888:      * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
 889:      * - `chmod` The mode to copy the files/directories with.
 890:      * - `skip` Files/directories to skip.
 891:      * - `scheme` Folder::MERGE, Folder::OVERWRITE, Folder::SKIP
 892:      * - `recursive` Whether to copy recursively or not (default: true - recursive)
 893:      *
 894:      * @param array|string $options (to, from, chmod, skip, scheme)
 895:      * @return bool Success
 896:      */
 897:     public function move($options)
 898:     {
 899:         $to = null;
 900:         if (is_string($options)) {
 901:             $to = $options;
 902:             $options = (array)$options;
 903:         }
 904:         $options += ['to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => [], 'recursive' => true];
 905: 
 906:         if ($this->copy($options) && $this->delete($options['from'])) {
 907:             return (bool)$this->cd($options['to']);
 908:         }
 909: 
 910:         return false;
 911:     }
 912: 
 913:     /**
 914:      * get messages from latest method
 915:      *
 916:      * @param bool $reset Reset message stack after reading
 917:      * @return array
 918:      */
 919:     public function messages($reset = true)
 920:     {
 921:         $messages = $this->_messages;
 922:         if ($reset) {
 923:             $this->_messages = [];
 924:         }
 925: 
 926:         return $messages;
 927:     }
 928: 
 929:     /**
 930:      * get error from latest method
 931:      *
 932:      * @param bool $reset Reset error stack after reading
 933:      * @return array
 934:      */
 935:     public function errors($reset = true)
 936:     {
 937:         $errors = $this->_errors;
 938:         if ($reset) {
 939:             $this->_errors = [];
 940:         }
 941: 
 942:         return $errors;
 943:     }
 944: 
 945:     /**
 946:      * Get the real path (taking ".." and such into account)
 947:      *
 948:      * @param string $path Path to resolve
 949:      * @return string|false The resolved path
 950:      */
 951:     public function realpath($path)
 952:     {
 953:         if (strpos($path, '..') === false) {
 954:             if (!Folder::isAbsolute($path)) {
 955:                 $path = Folder::addPathElement($this->path, $path);
 956:             }
 957: 
 958:             return $path;
 959:         }
 960:         $path = str_replace('/', DIRECTORY_SEPARATOR, trim($path));
 961:         $parts = explode(DIRECTORY_SEPARATOR, $path);
 962:         $newparts = [];
 963:         $newpath = '';
 964:         if ($path[0] === DIRECTORY_SEPARATOR) {
 965:             $newpath = DIRECTORY_SEPARATOR;
 966:         }
 967: 
 968:         while (($part = array_shift($parts)) !== null) {
 969:             if ($part === '.' || $part === '') {
 970:                 continue;
 971:             }
 972:             if ($part === '..') {
 973:                 if (!empty($newparts)) {
 974:                     array_pop($newparts);
 975:                     continue;
 976:                 }
 977: 
 978:                 return false;
 979:             }
 980:             $newparts[] = $part;
 981:         }
 982:         $newpath .= implode(DIRECTORY_SEPARATOR, $newparts);
 983: 
 984:         return Folder::slashTerm($newpath);
 985:     }
 986: 
 987:     /**
 988:      * Returns true if given $path ends in a slash (i.e. is slash-terminated).
 989:      *
 990:      * @param string $path Path to check
 991:      * @return bool true if path ends with slash, false otherwise
 992:      */
 993:     public static function isSlashTerm($path)
 994:     {
 995:         $lastChar = $path[strlen($path) - 1];
 996: 
 997:         return $lastChar === '/' || $lastChar === '\\';
 998:     }
 999: }
1000: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs