-->

Can I make RecursiveDirectoryIterator skip unreada

2019-03-24 16:24发布

问题:

foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(".")) as $file) {
  echo "$file\n";
}

Is there any way for this code to not throw UnexpectedValueException "failed to open dir: Permission denied" whenever there is a unreadable subdirectory inside directory I attempt to list?

UPDATE

Converting foreach() to while() and explicitly calling Iterator::next() wrapped in try() catch {} doesn't help. This code:

$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."));
while($iter->valid()) {
    $file = $iter->current();
    echo "$file\n";
    try {
        $iter->next();
    } catch(UnexpectedValueException $e) {
    }
};

is an infinite loop if there is unreadable subdirectory.

回答1:

Apparently you can pass $flags parameter to constructor. There's only one flag in the docs, but it does exactly what you want: catches exceptions during getChildren() calls and simply jumps to the next element.

Change your class creation code to

new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator("."), 
    RecursiveIteratorIterator::LEAVES_ONLY,
    RecursiveIteratorIterator::CATCH_GET_CHILD);

and it should work



回答2:

You could do something like this :

class ReadableFilter extends RecursiveFilterIterator{
    public function accept(){
            return $this->current()->isReadable();
    }
}

$filteredIterator = new RecursiveIteratorIterator(new ReadableFilter(new RecursiveDirectoryIterator(".")));

foreach ($filteredIterator as $file){
    echo "$file\n";
}


回答3:

It's possible that the iterator position will still be valid even if a directory is not readable.

You could check the state of the directory entry. Sloppy untested sample code:

$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."));
foreach ($iter as $dir) {
    if($dir->isReadable()){
        //do something
    }
}