123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- <?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>
- */
- class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
- {
- /**
- * @var bool
- */
- private $ignoreUnreadableDirs;
- /**
- * @var bool
- */
- private $ignoreFirstRewind = true;
- // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
- private $rootPath;
- private $subPath;
- private $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.
- *
- * @return SplFileInfo
- */
- #[\ReturnTypeWillChange]
- public function current()
- {
- // the logic here avoids redoing the same work in all iterations
- if (null === $subPathname = $this->subPath) {
- $subPathname = $this->subPath = $this->getSubPath();
- }
- if ('' !== $subPathname) {
- $subPathname .= $this->directorySeparator;
- }
- $subPathname .= $this->getFilename();
- if ('/' !== $basePath = $this->rootPath) {
- $basePath .= $this->directorySeparator;
- }
- return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
- }
- /**
- * @param bool $allowLinks
- *
- * @return bool
- */
- #[\ReturnTypeWillChange]
- public function hasChildren($allowLinks = false)
- {
- $hasChildren = parent::hasChildren($allowLinks);
- if (!$hasChildren || !$this->ignoreUnreadableDirs) {
- return $hasChildren;
- }
- try {
- parent::getChildren();
- return true;
- } catch (\UnexpectedValueException $e) {
- // If directory is unreadable and finder is set to ignore it, skip children
- return false;
- }
- }
- /**
- * @return \RecursiveDirectoryIterator
- *
- * @throws AccessDeniedException
- */
- #[\ReturnTypeWillChange]
- public function getChildren()
- {
- 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->rootPath = $this->rootPath;
- }
- return $children;
- } catch (\UnexpectedValueException $e) {
- throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
- }
- }
- /**
- * @return void
- */
- #[\ReturnTypeWillChange]
- public function next()
- {
- $this->ignoreFirstRewind = false;
- parent::next();
- }
- /**
- * @return void
- */
- #[\ReturnTypeWillChange]
- public function rewind()
- {
- // some streams like FTP are not rewindable, ignore the first rewind after creation,
- // as newly created DirectoryIterator does not need to be rewound
- if ($this->ignoreFirstRewind) {
- $this->ignoreFirstRewind = false;
- return;
- }
- parent::rewind();
- }
- }
|