Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ignore directories using RecursiveIteratorIterator?

Tags:

iterator

php

I have tried several methods to ignore certain directories using RecursiveIteratorIterator on a file system.

For the sake of an example say I want to ignore the following directory: /cache.

My Iterator looks like this:

//$dirname is root
$directory = new RecursiveDirectoryIterator($dirname);
$mega = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);

foreach ($mega as $fileinfo) {
 echo $fileinfo;
}

I have been able to ignore certain file extensions using pathinfo for example this works:

$filetypes = array("jpg", "png");
$filetype = pathinfo($fileinfo, PATHINFO_EXTENSION);

foreach ($mega as $fileinfo) {
    if (!in_array(strtolower($filetype), $filetypes)) {
    echo $fileinfo;
    }
}

When I try it using PATHINFO_DIRNAME (with the appropriate directory paths in the array) it does not work, there are no errors, it just does not ignore the directories.

I have also experimented with using FilterIterator to no avail, and now I'm thinking maybe I should use RegexIterator.

What would be the simplest and most efficient way to ignore directories using RecursiveIteratorIterator ?


Experiments that didn't work. Using PATHINFO_DIRNAME

$dirignore = array("cache", "cache2");
$directory = new RecursiveDirectoryIterator($dirname);
$mega = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);
$dirtype = pathinfo($fileinfo, PATHINFO_DIRNAME); 

if (!in_array($dirtype), $dirignore)) {
echo $fileinfo;  //no worky still echo directories
}

Using FilterIterator (not sure how this works)

class DirFilter extends FilterIterator
{
    public function accept()
    {
        //return parent::current() != "..\cache\";

       $file = $this->getInnerIterator()->current();
       if ($file != "..\cache")
       return $file->getFilename();

      //also tried with same error as below
      //return !preg_match('/\cache', $file->getFilename());
    }
}

$directory= new RecursiveDirectoryIterator($dirname);
$directory = new DirFilter($directory); 
$mega = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);
// loop

Tis results in Error: An instance of RecursiveIterator or IteratorAggregate creating it is required

like image 372
Wyck Avatar asked Mar 12 '13 18:03

Wyck


1 Answers

Your DirFilter wants to extend RecursiveFilterIterator, since it is being used with a recursive iterator. Not doing that, is the cause of your error.

class DirFilter extends RecursiveFilterIterator
{
    // …
}

The next step is figuring out how to use accept() properly. It is supposed to return a true or false value, which dictates whether the current item should be included (true) or excluded (false) from the iteration. Returning a file name from accept() is not what you want to be doing.

class DirFilter extends RecursiveFilterIterator
{
    public function accept()
    {
        $excludes = array("cache", "cache2");
        return !($this->isDir() && in_array($this->getFilename(), $excludes));
    }
}

It might be nice to be able to pass in the array of excluded directories. This requires a little more code but is much more reusable.

class DirFilter extends RecursiveFilterIterator
{
    protected $exclude;
    public function __construct($iterator, array $exclude)
    {
        parent::__construct($iterator);
        $this->exclude = $exclude;
    }
    public function accept()
    {
        return !($this->isDir() && in_array($this->getFilename(), $this->exclude));
    }
    public function getChildren()
    {
        return new DirFilter($this->getInnerIterator()->getChildren(), $this->exclude);
    }
}

This code could then be used like:

$directory = new RecursiveDirectoryIterator($dirname);
$filtered = new DirFilter($directory, $dirignore); 
$mega = new RecursiveIteratorIterator($filtered, …);
like image 67
salathe Avatar answered Nov 15 '22 02:11

salathe