note 114504 added to class.recursivedirectoryiterator
| From: | sun | Date: | Fri, 28 Feb 2014 20:39:03 +0000 |
| Subject: | note 114504 added to class.recursivedirectoryiterator | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-198749@lists.php.net to get a copy of this message | ||
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!
----
Server IP: 72.52.91.14
Probable Submitter: 72.52.91.14
----
Manual Page -- http://php.net/manual/en/class.recursivedirectoryiterator.php
Edit -- https://master.php.net/note/edit/114504
Del: integrated -- https://master.php.net/note/delete/114504/integrated
Del: useless -- https://master.php.net/note/delete/114504/useless
Del: bad code -- https://master.php.net/note/delete/114504/bad+code
Del: spam -- https://master.php.net/note/delete/114504/spam
Del: non-english -- https://master.php.net/note/delete/114504/non-english
Del: in docs -- https://master.php.net/note/delete/114504/in+docs
Del: other reasons-- https://master.php.net/note/delete/114504
Reject -- https://master.php.net/note/reject/114504
Search -- https://master.php.net/manage/user-notes.php