Класс RecursiveDirectoryIterator

(PHP 5, PHP 7)

Введение

Класс RecursiveDirectoryIterator предоставляет интерфейс для рекурсивного перебора каталогов файловой системы.

Обзор классов

RecursiveDirectoryIterator extends FilesystemIterator implements SeekableIterator , RecursiveIterator {
/* Методы */
public __construct ( string $path [, int $flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO ] )
public mixed getChildren ( void )
public string getSubPath ( void )
public string getSubPathname ( void )
public bool hasChildren ([ bool $allow_links = false ] )
public string key ( void )
public void next ( void )
public void rewind ( void )
/* Inherits */
public FilesystemIterator::__construct ( string $path [, int $flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS ] )
public mixed FilesystemIterator::current ( void )
public int FilesystemIterator::getFlags ( void )
public string FilesystemIterator::key ( void )
public void FilesystemIterator::next ( void )
public void FilesystemIterator::rewind ( void )
public void FilesystemIterator::setFlags ([ int $flags ] )
}

Список изменений

Версия Описание
5.3.0 Класс FilesystemIterator был введен в качестве родительского класса. Ранее родителем был DirectoryIterator.
5.3.0 Осуществляет SeekableIterator.
5.2.11, 5.3.1 Добавлено RecursiveDirectoryIterator::FOLLOW_SYMLINKS

Содержание

Коментарии

Usage example:

<?php

$path 
realpath('/etc');

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach(
$objects as $name => $object){
    echo 
"$name\n";
}

?>

This prints a list of all files and directories under $path (including $path ifself). If you want to omit directories, remove the RecursiveIteratorIterator::SELF_FIRST part.
2008-09-18 11:15:45
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
Usage example:
To see all the files, and count the space usage:

<?php
$ite
=new RecursiveDirectoryIterator("/path/");

$bytestotal=0;
$nbfiles=0;
foreach (new 
RecursiveIteratorIterator($ite) as $filename=>$cur) {
   
$filesize=$cur->getSize();
   
$bytestotal+=$filesize;
   
$nbfiles++;
    echo 
"$filename => $filesize\n";
}

$bytestotal=number_format($bytestotal);
echo 
"Total: $nbfiles files, $bytestotal bytes\n";
?>
2009-07-15 04:57:07
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
If you would like to get, say, all the *.php files in your project folder, recursively, you could use the following:

<?php

$Directory 
= new RecursiveDirectoryIterator('path/to/project/');
$Iterator = new RecursiveIteratorIterator($Directory);
$Regex = new RegexIterator($Iterator'/^.+\.php$/i'RecursiveRegexIterator::GET_MATCH);

?>

$Regex will contain a single index array for each PHP file.
2010-04-09 03:05:52
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
If you use RecursiveDirectoryIterator with RecursiveIteratorIterator and run into UnexpectedValueException you may use this little hack to ignore those directories, such as lost+found on linux.

<?php
class IgnorantRecursiveDirectoryIterator extends RecursiveDirectoryIterator {
    function 
getChildren() {
        try {
            return new 
IgnorantRecursiveDirectoryIterator($this->getPathname());
        } catch(
UnexpectedValueException $e) {
            return new 
RecursiveArrayIterator(array());
        }
    }
}
?>

Use just like the normal RecursiveDirectoryIterator.
2011-01-02 11:40:22
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
The returned object is an iterator of SplFileInfo objects.
2012-02-14 05:51:40
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
If you need to convert a nested directory tree into a multidimensional array, use this code:

<?php
$ritit 
= new RecursiveIteratorIterator(new RecursiveDirectoryIterator($startpath), RecursiveIteratorIterator::CHILD_FIRST);
$r = array();
foreach (
$ritit as $splFileInfo) {
   
$path $splFileInfo->isDir()
         ? array(
$splFileInfo->getFilename() => array())
         : array(
$splFileInfo->getFilename());

   for (
$depth $ritit->getDepth() - 1$depth >= 0$depth--) {
       
$path = array($ritit->getSubIterator($depth)->current()->getFilename() => $path);
   }
   
$r array_merge_recursive($r$path);
}

print_r($r);
?>
2013-01-19 02:44:51
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
If you want to copy all files recursively from a source directory to some destination  :

    $directory = new RecursiveDirectoryIterator("./source_path/");

    foreach (new RecursiveIteratorIterator($directory) as $filename=>$current) {
           
            $src = $current->getPathName();
            $dest = "./destination_path/" . $current->getFileName();
           
            echo "copy " .  $src . " => " . $dest  . "\n";
           
            copy($src, $dest);
     }

I hope it can help someone because when I looked for this solution I had to transform another example to get it.
2013-11-13 11:07:15
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
(related to the post about exceptions in getChildren().

instead of subclassing you can simply use the CATCH_GET_CHILD flag for RecursiveIteratorIterator

new RecursiveIteratorIterator($diriter, RecursiveIteratorIterator::CATCH_GET_CHILD);
2013-12-18 18:11:07
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
When looping through the RecursiveDirectoryIterator , the results use  SplFileInfo.
2014-01-19 18:01:47
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
Since I continue to run into implementations across the net that are unintentionally running into this trap — beware:

RecursiveDirectoryIterator recurses without limitations into the full filesystem tree.

Do NOT do the following, unless you intentionally want to infinitely recurse without limitations:

<?php
$directory 
= new \RecursiveDirectoryIterator($path);
$iterator = new \RecursiveIteratorIterator($directory);
$files = array();
foreach (
$iterator as $info) {
  if (...
custom conditions...) {
   
$files[] = $info->getPathname();
  }
}
?>

1. RecursiveDirectoryIterator is just a RecursiveIterator that recurses into its children, until no more children are found.

2. The instantiation of RecursiveIteratorIterator causes RecursiveDirectoryIterator to *immediately* recurse infinitely into the entire filesystem tree (starting from the given base path).

3. Unnecessary filesystem recursion is slow.  In 90% of all cases, this is not what you want.

Remember this simple rule of thumb:

→ A RecursiveDirectoryIterator must be FILTERED or you have a solid reason for why it shouldn't.

On PHP <5.4, implement the following - your custom conditions move into a proper filter:

<?php
$directory 
= new \RecursiveDirectoryIterator($path\FilesystemIterator::FOLLOW_SYMLINKS);
$filter = new MyRecursiveFilterIterator($directory);
$iterator = new \RecursiveIteratorIterator($filter);
$files = array();
foreach (
$iterator as $info) {
 
$files[] = $info->getPathname();
}

class 
MyRecursiveFilterIterator extends \RecursiveFilterIterator {

  public function 
accept() {
   
$filename $this->current()->getFilename();
   
// Skip hidden files and directories.
   
if ($name[0] === '.') {
      return 
FALSE;
    }
    if (
$this->isDir()) {
     
// Only recurse into intended subdirectories.
     
return $name === 'wanted_dirname';
    }
    else {
     
// Only consume files of interest.
     
return strpos($name'wanted_filename') === 0;
    }
  }

}
?>

On PHP 5.4+, PHP core addressed the slightly cumbersome issue of having to create an entirely new class and you can leverage the new RecursiveCallbackFilterIterator instead:

<?php
$directory 
= new \RecursiveDirectoryIterator($path\FilesystemIterator::FOLLOW_SYMLINKS);
$filter = new \RecursiveCallbackFilterIterator($directory, function ($current$key$iterator) {
 
// Skip hidden files and directories.
 
if ($current->getFilename()[0] === '.') {
    return 
FALSE;
  }
  if (
$current->isDir()) {
   
// Only recurse into intended subdirectories.
   
return $current->getFilename() === 'wanted_dirname';
  }
  else {
   
// Only consume files of interest.
   
return strpos($current->getFilename(), 'wanted_filename') === 0;
  }
});
$iterator = new \RecursiveIteratorIterator($filter);
$files = array();
foreach (
$iterator as $info) {
 
$files[] = $info->getPathname();
}
?>

Have fun!
2014-02-28 22:39:01
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
In this doc page i see things for to hide hidden files  (also for opendir() or readdir() .... this should be mentiond all there 
<?php
// not hidden but on most OS systems Win, *nix, OSX..
if ($file == '.' || $file == '..') { 
     
// "." current dir info, 
     // ".." dir above info,
         
continue; 
?>
or
<?php
if $name[0] === '.' // NOT OK FOLKS
?>
Think: 
"... and then came Polly.avi" is the title of the Movi. What do you do then?

Windows does it different with hidden files than unix based systems.

For unix based systems  something like this should work:
<?php
if (preg_match('/^(\.\w+|\.$|\.\.$)/i'$location)) {
/* is hidden:
    .
    ..
    .dir
    .file
*/
}
// must be ok: "..some thing", "... some thing"
?>

I know you do it (if $name[0] === '.' ) because it is much faster. But it is NOT correct and some day you miss things like me today :-)
2015-03-29 05:58:32
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
I tried to use RecursiveDirectoryIterator to dump all files (and theirs properties, such as size/is_link/is_dir/mtime/perms/owner/group) from a large directory (~400.000 files), filtering some specific wanted files/folders.

Using RecursiveDirectoryIterator and SplFileInfo, dump was taking about 50 seconds to perform, but it was working.

However, to improve performance, I decided to make another version of the same script, using only direct file functions, such as "readdir", "filesize", "filemtime", etc.., and adding recursivity myself (if(is_dir($path)) doRecursivity($path);

After running it, script went from ~50s to only ~20s to complete (On Linux CentOS 7, SSD 300IPs).

Strangely, on Windows 7, Sata3 (with exactly same files [mirrored]) the time went from ~63s to ~57s.

I believe that this payload is due to the OO approach of SPL, which runs lots of unnecessary extra code to perform the same tasks with more reliability, while direct file funcions are more like alias to C corresponding functions, and thereover, must faster.

So, if you're dealing with a large amount of files, using RecursiveDirectoryIterator is probably not the way to go.
2016-01-20 16:50:02
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
There are differences between Windows and Linux about the order of the files.

<?php
$it 
= new RecursiveIteratorIterator(
    new 
RecursiveDirectoryIterator'path/to/dir' )
   
//, does not matter the flag
   
);
...
?>

On Windows, you will get the files ordered by name. On Linux they are not ordered.
2017-04-12 05:25:31
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
if you want to show the all files from all directories you have to follow it- 

$dir = new RecursiveDirectoryIterator(getcwd());
$files = new RecursiveIteratorIterator($dir);

foreach($files as $file){
   echo $file->getFileName();
   echo PHP_EOL; // for new line
}

Now, if you want to show the full path, then follow this- 

$dir = new RecursiveDirectoryIterator(getcwd());
$files = new RecursiveIteratorIterator($dir);

foreach($files as $file){
   echo $file->getPath().$file->getFileName();
   echo PHP_EOL;
}

If you want to skip the dots, you need to change the first line with this-
$dir = new RecursiveDirectoryIterator(getcwd(), RecursiveDirectoryIterator::SKIP_DOTS);
2019-04-15 06:50:03
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
Do not waste your time with this. I have included a function below that accomplishes the same thing more simply. If you want to do regex while iterating you can pass the regex into the recursive function as a parameter.

<?php

function recursive_read($directory$entries_array = array()) {
    if(
is_dir($directory)) {
       
$handle opendir($directory);
        while(
FALSE !== ($entry readdir($handle))) {
            if(
$entry == '.' || $entry == '..') {
                continue;
            }
           
$Entry $directory DS $entry;
            if(
is_dir($Entry)) {
               
$entries_array recursive_read($Entry$entries_array);
            } else {
               
$entries_array[] = $Entry;
            }
        }
       
closedir($handle);
    }
    return 
$entries_array;
}

?>
2019-08-16 02:30:15
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
Автор:
When using the option FilesystemIterator::FOLLOW_SYMLINKS if there is a symlink to an upper directory there is a loop so we end up with repeated directories.
For example (having a -> ../ ):

/c
/c/..
/c/a
/c/a/c
/c/a/c/..
/c/a/c/a
/c/a/c/a/c
... (up to 40 x /c/a )
/c/a/c/a/..
/c/a/c/a/.
/c/a/c/.
/c/a/..
/c/a/.
/c/.
/..
/.

Apparently there is a limit to avoid having an infinite loop. I don't know documentation for this.

It would be interesting to have an option to allow following symlinks without loops.
2019-09-09 23:54:58
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html
if you just want a plain array, recursively, of all files (not directories), try

<?php

/** 
 * returns a plain string array of path to all files in a directory, and subdirectories,
 * but does not return directories themselves. (meaning if a directory is empty, it will not be included at all)
 * 
 * @param string $dir
 * @param bool $realpath
 * @throws UnexpectedValueException if $dir is not readable/does not exists
 * @return string[] files
 */
function get_file_list_recursively(string $dirbool $realpath false): array
{
   
$files = array();
   
$files = [];
    foreach ((new 
RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirRecursiveDirectoryIterator::SKIP_DOTS))) as $file) {
       
/** @var SplFileInfo $file */
       
if ($realpath) {
           
$files[] = $file->getRealPath();
        } else {
           
$files[] = $file->getPathname();
        }
    }
    return 
$files;
}
?>

sample return:
<?php
array (
 
=> '/home/hans/scraping/1650518081RESULTS.txt',
 
=> '/home/hans/scraping/1650518121RESULTS.txt',
 
=> '/home/hans/scraping/1650518679RESULTS.txt',
 
=> '/home/hans/scraping/1650518780RESULTS.txt',
 
=> '/home/hans/scraping/1650522198RESULTS.txt',
 
=> '/home/hans/scraping/1650522927RESULTS.txt',
 
=> '/home/hans/scraping/1650525391RESULTS.txt',
 
=> '/home/hans/scraping/check_cache.php',
 
=> '/home/hans/scraping/foo/bar.txt',
 
=> '/home/hans/scraping/foobar.txt',
 
10 => '/home/hans/scraping/GoodProxyDaemon.php',
);
?>

(note to editor, if you can find a better sample return, feel absolutely free to overwrite the one above)
2022-04-23 23:29:30
http://php5.kiev.ua/manual/ru/class.recursivedirectoryiterator.html

    Поддержать сайт на родительском проекте КГБ