我想得到所有子目录的列表,我的下面的代码工作,除非我对某些文件夹具有只读权限。
在下面的问题中,它显示了如何使用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里面所有目录的列表,我在哪里错了?
答案 0 :(得分:6)
简介
您的代码的主要问题是使用CHILD_FIRST
可选模式。可能的值是
- RecursiveIteratorIterator :: LEAVES_ONLY - 默认值。列表仅在迭代中离开。
- RecursiveIteratorIterator :: SELF_FIRST - 在父母第一次的迭代中列出叶子和父母。
- RecursiveIteratorIterator :: CHILD_FIRST - 在迭代中列出叶子和父项,首先是叶子。
您应该使用的是SELF_FIRST
,以便包含当前目录。您还忘记添加可选参数RecursiveIteratorIterator::CATCH_GET_CHILD
可选标志。可能的值是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