Can I make RecursiveDirectoryIterator skip unreadable directories?
Asked Answered
D

2

17
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.

Divot answered 28/12, 2010 at 16:22 Comment(4)
wrap it into try catch blocks. and it seems to be a bad ideea to create new objects right inside foreach parenthesesExcurrent
To Elaborate on s3v3n's comment. It seems to be a bad idea, because what exactly is going on is very hard to determine. Good code isn't always the smallest or fastest code.Phlyctena
It's not hard to determine what happens if you know what is RecursiveIteratorIterator and RecursiveDirectoryIterator and what is their common use case. It's simple code.Divot
@Excurrent You gave me an idea of transforming foreach into while and explicitely calling iterator next() inside try {} catch. Unfortunately it doesn't work.Divot
F
26

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

Flavia answered 28/12, 2010 at 22:30 Comment(2)
I have a similar problem asked here #14411399 do you have any ideas on how I can rework you solution to solve my problem?Ron
Specifically, the flag is: CATCH_GET_CHILDBreakaway
Y
8

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";
}
Yann answered 28/12, 2010 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.