Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Symfony\Component\Finder\Iterator;
13
 
14
use Symfony\Component\Finder\Exception\AccessDeniedException;
15
use Symfony\Component\Finder\SplFileInfo;
16
 
17
/**
18
 * Extends the \RecursiveDirectoryIterator to support relative paths.
19
 *
20
 * @author Victor Berchet <victor@suumit.com>
21
 * @extends \RecursiveDirectoryIterator<string, SplFileInfo>
22
 */
23
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
24
{
25
    private bool $ignoreUnreadableDirs;
26
    private ?bool $rewindable = null;
27
 
28
    // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
29
    private string $rootPath;
30
    private string $subPath;
31
    private string $directorySeparator = '/';
32
 
33
    /**
34
     * @throws \RuntimeException
35
     */
36
    public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
37
    {
38
        if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
39
            throw new \RuntimeException('This iterator only support returning current as fileinfo.');
40
        }
41
 
42
        parent::__construct($path, $flags);
43
        $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
44
        $this->rootPath = $path;
45
        if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
46
            $this->directorySeparator = \DIRECTORY_SEPARATOR;
47
        }
48
    }
49
 
50
    /**
51
     * Return an instance of SplFileInfo with support for relative paths.
52
     */
53
    public function current(): SplFileInfo
54
    {
55
        // the logic here avoids redoing the same work in all iterations
56
 
57
        if (!isset($this->subPath)) {
58
            $this->subPath = $this->getSubPath();
59
        }
60
        $subPathname = $this->subPath;
61
        if ('' !== $subPathname) {
62
            $subPathname .= $this->directorySeparator;
63
        }
64
        $subPathname .= $this->getFilename();
65
 
66
        if ('/' !== $basePath = $this->rootPath) {
67
            $basePath .= $this->directorySeparator;
68
        }
69
 
70
        return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
71
    }
72
 
73
    public function hasChildren(bool $allowLinks = false): bool
74
    {
75
        $hasChildren = parent::hasChildren($allowLinks);
76
 
77
        if (!$hasChildren || !$this->ignoreUnreadableDirs) {
78
            return $hasChildren;
79
        }
80
 
81
        try {
82
            parent::getChildren();
83
 
84
            return true;
85
        } catch (\UnexpectedValueException) {
86
            // If directory is unreadable and finder is set to ignore it, skip children
87
            return false;
88
        }
89
    }
90
 
91
    /**
92
     * @throws AccessDeniedException
93
     */
94
    public function getChildren(): \RecursiveDirectoryIterator
95
    {
96
        try {
97
            $children = parent::getChildren();
98
 
99
            if ($children instanceof self) {
100
                // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
101
                $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
102
 
103
                // performance optimization to avoid redoing the same work in all children
104
                $children->rewindable = &$this->rewindable;
105
                $children->rootPath = $this->rootPath;
106
            }
107
 
108
            return $children;
109
        } catch (\UnexpectedValueException $e) {
110
            throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
111
        }
112
    }
113
 
114
    /**
115
     * Do nothing for non rewindable stream.
116
     */
117
    public function rewind(): void
118
    {
119
        if (false === $this->isRewindable()) {
120
            return;
121
        }
122
 
123
        parent::rewind();
124
    }
125
 
126
    /**
127
     * Checks if the stream is rewindable.
128
     */
129
    public function isRewindable(): bool
130
    {
131
        if (null !== $this->rewindable) {
132
            return $this->rewindable;
133
        }
134
 
135
        if (false !== $stream = @opendir($this->getPath())) {
136
            $infos = stream_get_meta_data($stream);
137
            closedir($stream);
138
 
139
            if ($infos['seekable']) {
140
                return $this->rewindable = true;
141
            }
142
        }
143
 
144
        return $this->rewindable = false;
145
    }
146
}