note 114504 added to class.recursivedirectoryiterator

From: 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

« previous php.notes (#198749) next »