3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
19 * @ingroup FileBackend
23 * Wrapper around RecursiveDirectoryIterator/DirectoryIterator that
24 * catches exception or does any custom behavoir that we may want.
25 * Do not use this class from places outside FSFileBackend.
27 * @ingroup FileBackend
29 abstract class FSFileBackendList
implements Iterator
{
34 protected $suffixStart;
40 protected $params = [];
43 * @param string $dir File system directory
44 * @param array $params
46 public function __construct( $dir, array $params ) {
47 $path = realpath( $dir ); // normalize
48 if ( $path === false ) {
51 $this->suffixStart
= strlen( $path ) +
1; // size of "path/to/dir/"
52 $this->params
= $params;
55 $this->iter
= $this->initIterator( $path );
56 } catch ( UnexpectedValueException
$e ) {
57 $this->iter
= null; // bad permissions? deleted?
62 * Return an appropriate iterator object to wrap
64 * @param string $dir File system directory
67 protected function initIterator( $dir ) {
68 if ( !empty( $this->params
['topOnly'] ) ) { // non-recursive
69 # Get an iterator that will get direct sub-nodes
70 return new DirectoryIterator( $dir );
72 # Get an iterator that will return leaf nodes (non-directories)
73 # RecursiveDirectoryIterator extends FilesystemIterator.
74 # FilesystemIterator::SKIP_DOTS default is inconsistent in PHP 5.3.x.
75 $flags = FilesystemIterator
::CURRENT_AS_SELF | FilesystemIterator
::SKIP_DOTS
;
77 return new RecursiveIteratorIterator(
78 new RecursiveDirectoryIterator( $dir, $flags ),
79 RecursiveIteratorIterator
::CHILD_FIRST
// include dirs
85 * @see Iterator::key()
88 public function key() {
93 * @see Iterator::current()
94 * @return string|bool String or false
96 public function current() {
97 return $this->getRelPath( $this->iter
->current()->getPathname() );
101 * @see Iterator::next()
102 * @throws FileBackendError
104 public function next() {
107 $this->filterViaNext();
108 } catch ( UnexpectedValueException
$e ) { // bad permissions? deleted?
109 throw new FileBackendError( "File iterator gave UnexpectedValueException." );
115 * @see Iterator::rewind()
116 * @throws FileBackendError
118 public function rewind() {
121 $this->iter
->rewind();
122 $this->filterViaNext();
123 } catch ( UnexpectedValueException
$e ) { // bad permissions? deleted?
124 throw new FileBackendError( "File iterator gave UnexpectedValueException." );
129 * @see Iterator::valid()
132 public function valid() {
133 return $this->iter
&& $this->iter
->valid();
137 * Filter out items by advancing to the next ones
139 protected function filterViaNext() {
143 * Return only the relative path and normalize slashes to FileBackend-style.
144 * Uses the "real path" since the suffix is based upon that.
149 protected function getRelPath( $dir ) {
150 $path = realpath( $dir );
151 if ( $path === false ) {
155 return strtr( substr( $path, $this->suffixStart
), '\\', '/' );