scratch – Blame information for rev
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
120 | office | 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 | */ |
||
22 | class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator |
||
23 | { |
||
24 | /** |
||
25 | * @var bool |
||
26 | */ |
||
27 | private $ignoreUnreadableDirs; |
||
28 | |||
29 | /** |
||
30 | * @var bool |
||
31 | */ |
||
32 | private $rewindable; |
||
33 | |||
34 | // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations |
||
35 | private $rootPath; |
||
36 | private $subPath; |
||
37 | private $directorySeparator = '/'; |
||
38 | |||
39 | /** |
||
40 | * Constructor. |
||
41 | * |
||
42 | * @param string $path |
||
43 | * @param int $flags |
||
44 | * @param bool $ignoreUnreadableDirs |
||
45 | * |
||
46 | * @throws \RuntimeException |
||
47 | */ |
||
48 | public function __construct($path, $flags, $ignoreUnreadableDirs = false) |
||
49 | { |
||
50 | if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) { |
||
51 | throw new \RuntimeException('This iterator only support returning current as fileinfo.'); |
||
52 | } |
||
53 | |||
54 | parent::__construct($path, $flags); |
||
55 | $this->ignoreUnreadableDirs = $ignoreUnreadableDirs; |
||
56 | $this->rootPath = $path; |
||
57 | if ('/' !== DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) { |
||
58 | $this->directorySeparator = DIRECTORY_SEPARATOR; |
||
59 | } |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * Return an instance of SplFileInfo with support for relative paths. |
||
64 | * |
||
65 | * @return SplFileInfo File information |
||
66 | */ |
||
67 | public function current() |
||
68 | { |
||
69 | // the logic here avoids redoing the same work in all iterations |
||
70 | |||
71 | if (null === $subPathname = $this->subPath) { |
||
72 | $subPathname = $this->subPath = (string) $this->getSubPath(); |
||
73 | } |
||
74 | if ('' !== $subPathname) { |
||
75 | $subPathname .= $this->directorySeparator; |
||
76 | } |
||
77 | $subPathname .= $this->getFilename(); |
||
78 | |||
79 | return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @return \RecursiveIterator |
||
84 | * |
||
85 | * @throws AccessDeniedException |
||
86 | */ |
||
87 | public function getChildren() |
||
88 | { |
||
89 | try { |
||
90 | $children = parent::getChildren(); |
||
91 | |||
92 | if ($children instanceof self) { |
||
93 | // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore |
||
94 | $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs; |
||
95 | |||
96 | // performance optimization to avoid redoing the same work in all children |
||
97 | $children->rewindable = &$this->rewindable; |
||
98 | $children->rootPath = $this->rootPath; |
||
99 | } |
||
100 | |||
101 | return $children; |
||
102 | } catch (\UnexpectedValueException $e) { |
||
103 | if ($this->ignoreUnreadableDirs) { |
||
104 | // If directory is unreadable and finder is set to ignore it, a fake empty content is returned. |
||
105 | return new \RecursiveArrayIterator(array()); |
||
106 | } else { |
||
107 | throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e); |
||
108 | } |
||
109 | } |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Do nothing for non rewindable stream. |
||
114 | */ |
||
115 | public function rewind() |
||
116 | { |
||
117 | if (false === $this->isRewindable()) { |
||
118 | return; |
||
119 | } |
||
120 | |||
121 | // @see https://bugs.php.net/68557 |
||
122 | if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) { |
||
123 | parent::next(); |
||
124 | } |
||
125 | |||
126 | parent::rewind(); |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Checks if the stream is rewindable. |
||
131 | * |
||
132 | * @return bool true when the stream is rewindable, false otherwise |
||
133 | */ |
||
134 | public function isRewindable() |
||
135 | { |
||
136 | if (null !== $this->rewindable) { |
||
137 | return $this->rewindable; |
||
138 | } |
||
139 | |||
140 | // workaround for an HHVM bug, should be removed when https://github.com/facebook/hhvm/issues/7281 is fixed |
||
141 | if ('' === $this->getPath()) { |
||
142 | return $this->rewindable = false; |
||
143 | } |
||
144 | |||
145 | if (false !== $stream = @opendir($this->getPath())) { |
||
146 | $infos = stream_get_meta_data($stream); |
||
147 | closedir($stream); |
||
148 | |||
149 | if ($infos['seekable']) { |
||
150 | return $this->rewindable = true; |
||
151 | } |
||
152 | } |
||
153 | |||
154 | return $this->rewindable = false; |
||
155 | } |
||
156 | } |