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



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

在下面的问题中,它显示了如何使用RecursiveDirectoryTerator跳过目录我可以让RecursiveDirectoryTerator跳过不可读的目录吗?然而,我的代码在这里略有不同,我无法解决这个问题。

$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内所有目录的列表,我在哪里出错了?

简介

代码的主要问题是使用CHILD_FIRST

来自PHP-DOC-

可选模式。可能的值为

  • RecursiveIteratorIterator::LEAVES_ONLY-默认值。仅列出迭代中的叶子
  • RecursiveIteratorIterator::SELF_FIRST-列出迭代中的叶子和父代,父代位于第一位
  • RecursiveIteratorIterator::CHILD_FIRST-列出迭代中的叶子和父代,叶子在前

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

来自PHP-DOC-

可选标志。可能的值是RecursiveIteratorIterator::CATCH_GET_CHILD,然后它将忽略在对RecursiveITeratorIterar::getChildren((的调用中引发的异常。

您的代码被修改

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();
    }
}

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

/
    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
)
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%有效。。。

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

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

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

此函数跳过递归时无法读取的文件和文件夹。

<?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);
    }
?>

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

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

如果要返回不可读的目录名,则需要使用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";
    }
}

尝试捕获UnexpectedValueException怎么样。也许您甚至可以检查该错误的唯一异常代码。否则,您可以解析异常消息中的"权限被拒绝"。

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

相关内容

  • 没有找到相关文章

最新更新