无法使用RecursiveDirectoryIterator跳过不可读的目录

时间:2013-01-19 03:46:54

标签: php directory directory-walk

我想得到所有子目录的列表,我的下面的代码工作,除非我对某些文件夹具有只读权限。

在下面的问题中,它显示了如何使用RecursiveDirectoryIterator跳过目录 Can I make RecursiveDirectoryIterator skip unreadable directories?但是我的代码在这里略有不同,我无法解决问题。

$path = 'www/';
foreach (new RecursiveIteratorIterator(
       new RecursiveDirectoryIterator($path,RecursiveDirectoryIterator::KEY_AS_PATHNAME),
            RecursiveIteratorIterator::CHILD_FIRST) as $file => $info) 
            {
                if ($info->isDir())
                {
                       echo $file . '<br>';                     
                }
            }   

我收到错误

Uncaught exception 'UnexpectedValueException' with message 'RecursiveDirectoryIterator::__construct(../../www/special): failed to open dir: Permission denied'

我已尝试将其替换为另一个问题中接受的答案。

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

但是这段代码不会给我一个像我想要的www里面所有目录的列表,我在哪里错了?

8 个答案:

答案 0 :(得分:6)

简介

您的代码的主要问题是使用CHILD_FIRST

FROM PHP DOC

  

可选模式。可能的值是

     
      
  • RecursiveIteratorIterator :: LEAVES_ONLY - 默认值。列表仅在迭代中离开。
  •   
  • RecursiveIteratorIterator :: SELF_FIRST - 在父母第一次的迭代中列出叶子和父母。
  •   
  • RecursiveIteratorIterator :: CHILD_FIRST - 在迭代中列出叶子和父项,首先是叶子。
  •   

您应该使用的是SELF_FIRST,以便包含当前目录。您还忘记添加可选参数RecursiveIteratorIterator::CATCH_GET_CHILD

FROM PHP DOC

  

可选标志。可能的值是RecursiveIteratorIterator :: CATCH_GET_CHILD,它将忽略对RecursiveIteratorIterator :: getChildren()的调用中抛出的异常。

重新访问您的CODE

foreach (new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path,RecursiveDirectoryIterator::KEY_AS_PATHNAME),
        RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD) as $file => $info)
{
    if ($info->isDir())
    {
        echo $file . '<br>';
    }
}

你真的想要CHILD_FIRST

如果你真的想维持CHILD_FIRST结构,那么我建议你使用ReadableDirectoryIterator

示例

foreach ( new RecursiveIteratorIterator(
        new ReadableDirectoryIterator($path),RecursiveIteratorIterator::CHILD_FIRST) as $file ) {
    echo $file . '<br>';
}

使用的课程

class ReadableDirectoryIterator extends RecursiveFilterIterator {
    function __construct($path) {
        if (!$path instanceof RecursiveDirectoryIterator) {
            if (! is_readable($path) || ! is_dir($path))
                throw new InvalidArgumentException("$path is not a valid directory or not readable");
            $path = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
        }
        parent::__construct($path);
    }

    public function accept() {
        return $this->current()->isReadable() && $this->current()->isDir();
    }
}

答案 1 :(得分:2)

function dirScan($dir, $fullpath = false){

    $ignore = array(".","..");
    if (isset($dir) && is_readable($dir)){
        $dlist = array();
        $dir = realpath($dir);
        $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir,RecursiveDirectoryIterator::KEY_AS_PATHNAME),RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);

        foreach($objects as $entry){    
                    if(!in_array(basename($entry), $ignore)){
                        if (!$fullpath){
                            $entry = str_replace($dir, '', $entry);
                        }           
                            $dlist[] = $entry;
                    }                        
        }       
        return $dlist;
    }

}

此代码100%正常工作......

您只需使用此功能即可扫描所需目录或驱动器中的文件和文件夹。您只需将所需目录的路径传递给函数即可。该函数的第二个参数是显示扫描文件和文件夹的完整路径。第二个参数的假值意味着不显示完整路径。

数组$ ignore用于从列表中排除任何所需的文件名或foldername。

该函数返回包含文件和文件夹列表的数组。

此功能会跳过递归时无法读取的文件和文件夹。

答案 2 :(得分:1)

我已经设置了以下目录结构:

/
    test.php <-- the test script
    www/
        test1/ <-- permissions = 000
            file1
        test2/
            file2
        file3

我运行了以下代码(我添加了SKIP_DOTS标记以跳过... btw):

$i = new RecursiveIteratorIterator(
  new RecursiveDirectoryIterator("www", FilesystemIterator::SKIP_DOTS),
  RecursiveIteratorIterator::LEAVES_ONLY,
  RecursiveIteratorIterator::CATCH_GET_CHILD
);

print_r(iterator_to_array($i));

输出以下内容:

Array
(
    [www/test2/file2] => SplFileInfo Object
        (
            [pathName:SplFileInfo:private] => www/test2/file2
            [fileName:SplFileInfo:private] => file2
        )

    [www/file3] => SplFileInfo Object
        (
            [pathName:SplFileInfo:private] => www/file3
            [fileName:SplFileInfo:private] => file3
        )

)

这可以按预期工作。

<强>更新

添加了原始示例中的标记(尽管我认为这些标记是默认的):

foreach (new RecursiveIteratorIterator(
  new RecursiveDirectoryIterator("www", FilesystemIterator::SKIP_DOTS | FilesystemIterator::KEY_AS_PATHNAME),
  RecursiveIteratorIterator::LEAVES_ONLY,
  RecursiveIteratorIterator::CATCH_GET_CHILD | RecursiveIteratorIterator::CHILD_FIRST
) as $file => $info) {
        echo $file, "\n";
        print_r($info);
        if ($info->isDir()) {
            echo $file . '<br>';
        }
}

输出:

www/test2/file2
SplFileInfo Object
(
    [pathName:SplFileInfo:private] => www/test2/file2
    [fileName:SplFileInfo:private] => file2
)
www/file3
SplFileInfo Object
(
    [pathName:SplFileInfo:private] => www/file3
    [fileName:SplFileInfo:private] => file3
)

答案 3 :(得分:1)

<?php
    $path = "D:/Movies";

    $directory_iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME);

    $files = new RecursiveIteratorIterator($directory_iterator,
            RecursiveIteratorIterator::SELF_FIRST,
            RecursiveIteratorIterator::CATCH_GET_CHILD);

    try {
        foreach( $files as $fullFileName => $file) {
            $path_parts = pathinfo($fullFileName);

            if(is_file($fullFileName)){
                $path_parts = pathinfo($fullFileName);
                $fileName[] =  $path_parts['filename'];
                $extensionName[] =  $path_parts['extension'];
                $dirName[] =  $path_parts['dirname'];
                $baseName[] =  $path_parts['basename'];
                $fullpath[] = $fullFileName;
            }
        }


        foreach ($fullpath as $filles){
                echo $filles;
                echo "</br>";
        }

    }
    catch (UnexpectedValueException $e) {
        printf("Directory [%s] contained a directory we can not recurse into", $directory);
    }
?>

答案 4 :(得分:0)

glob函数会自动跳过读取错误,并且还应该简化您的代码。

答案 5 :(得分:0)

如果您遇到未处理的异常,为什么不将该代码放在try块中,并使用异常catch块来捕获无法读取目录的错误?通过查看您的代码和您的问题,只是一个简单的建议。在PHP中可能有一种更简洁的方法。

答案 6 :(得分:0)

如果要返回不可读的目录名,则需要使用SELF_FIRST常量。 当您执行CHILD_FIRST时,它会尝试进入目录,失败,并且不包含当前目录名称。

$path = 'testing';

$directory_iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME);

$iterator = new RecursiveIteratorIterator($directory_iterator,
    RecursiveIteratorIterator::SELF_FIRST,
    RecursiveIteratorIterator::CATCH_GET_CHILD);

foreach ($iterator as $file => $info) {
    if ($info->isDir()) {
        echo $file . "\n";
    }
}

答案 7 :(得分:0)

尝试捕获UnexpectedValueException怎么样?也许甚至有一个唯一的异常代码可以检查该错误。否则你可以通过恶意解析异常消息“拒绝许可”。

我建议检查http://php.net/manual/de/class.unexpectedvalueexception.php