Revision 148 | Blame | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed
<?php/** This file is part of the Symfony package.** (c) Fabien Potencier <fabien@symfony.com>** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*/namespace Symfony\Component\Finder\Iterator;use Symfony\Component\Finder\Exception\AccessDeniedException;use Symfony\Component\Finder\SplFileInfo;/*** Extends the \RecursiveDirectoryIterator to support relative paths.** @author Victor Berchet <victor@suumit.com>** @extends \RecursiveDirectoryIterator<string, SplFileInfo>*/class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator{private bool $ignoreUnreadableDirs;private ?bool $rewindable = null;// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterationsprivate string $rootPath;private string $subPath;private string $directorySeparator = '/';/*** @throws \RuntimeException*/public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false){if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {throw new \RuntimeException('This iterator only support returning current as fileinfo.');}parent::__construct($path, $flags);$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;$this->rootPath = $path;if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {$this->directorySeparator = \DIRECTORY_SEPARATOR;}}/*** Return an instance of SplFileInfo with support for relative paths.*/public function current(): SplFileInfo{// the logic here avoids redoing the same work in all iterationsif (!isset($this->subPath)) {$this->subPath = $this->getSubPath();}$subPathname = $this->subPath;if ('' !== $subPathname) {$subPathname .= $this->directorySeparator;}$subPathname .= $this->getFilename();if ('/' !== $basePath = $this->rootPath) {$basePath .= $this->directorySeparator;}return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);}public function hasChildren(bool $allowLinks = false): bool{$hasChildren = parent::hasChildren($allowLinks);if (!$hasChildren || !$this->ignoreUnreadableDirs) {return $hasChildren;}try {parent::getChildren();return true;} catch (\UnexpectedValueException) {// If directory is unreadable and finder is set to ignore it, skip childrenreturn false;}}/*** @throws AccessDeniedException*/public function getChildren(): \RecursiveDirectoryIterator{try {$children = parent::getChildren();if ($children instanceof self) {// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;// performance optimization to avoid redoing the same work in all children$children->rewindable = &$this->rewindable;$children->rootPath = $this->rootPath;}return $children;} catch (\UnexpectedValueException $e) {throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);}}/*** Do nothing for non rewindable stream.*/public function rewind(): void{if (false === $this->isRewindable()) {return;}parent::rewind();}/*** Checks if the stream is rewindable.*/public function isRewindable(): bool{if (null !== $this->rewindable) {return $this->rewindable;}if (false !== $stream = @opendir($this->getPath())) {$infos = stream_get_meta_data($stream);closedir($stream);if ($infos['seekable']) {return $this->rewindable = true;}}return $this->rewindable = false;}}