虽然目录存在,但rmdir没有这样的文件目录错误

时间:2014-06-10 14:49:24

标签: php rmdir

如果使用此功能删除目录+内部的所有文件。

function delete_files($target)
{
    if(is_dir($target))
    {
        $files = glob($target . '*', GLOB_MARK);
        foreach($files as $file)
        {
            delete_files($file);
        }
        rmdir($target);
    }
    elseif(is_file($target))
    {
        unlink($target);
    }
}
delete_files($directory);

但每当我这样做时,都会收到以下错误消息:

  

警告:rmdir(目录/ 12)[function.rmdir]:没有这样的文件或目录   在delete_files.php中

“directory / 12”是我想删除的目录的正确名称。我不明白为什么它说它不存在因为它确实存在!奇怪的是,即使我收到错误消息,目录DID也会被删除。

所以我在for循环之前添加了一行代码print_n($files);,它为我提供了两个数组 - 一个包含目录(“directory / 12”),另一个包含目录的所有文件( “directory / 12 / 01.gif”,“directory / 12 / 02.gif”等)。所以我认为该目录必须在for-loop中被删除并删除了行rmdir($target)并再次尝试。这次,目录中的所有文件都被删除了,但目录本身仍然存在。

显然,rmdir确实正确删除了目录。但是,为什么它事先给我错误信息它不存在?

2 个答案:

答案 0 :(得分:3)

如果在目录名称附加斜杠,它将起作用。

说明:当您最初将该函数调用为delete_files("directory/12")时,传递给glob()调用的参数将如下所示:

$files = glob("directory/12*", GLOB_MARK);

假设directory/中没有名称以12开头的其他文件,则只会返回"directory/12/"(由于GLOB_MARK而附加斜杠)。然后,该函数将使用该参数递归调用自身,从而导致顶级目录被处理两次。

当然,如果确实碰巧有一些名为directory/123的其他文件或目录,那么会被删除,这是大概不是你想要的。


要正确修复此问题,您应该确保您的函数可以正确处理目录,即使它们在没有尾部斜杠的情况下传入也是如此。最简单的方法是在对它们进行全局处理之前始终将斜杠附加到目录名,如下所示:

$files = glob($target . '/*');

但是,请注意,如果您的目录恰好包含*未匹配的某些文件,例如dotfiles,则可能会失败(尽管破坏性较小),因为它们不会被删除,从而导致后续rmdir()失败,因为该目录不会为空。

更强大的解决方案是使用scandir()代替glob(),如下所示:

$files = array_diff( scandir($target), array('.', '..') );
foreach ($files as $file) {
    delete_files("$target/$file");
}

(需要array_diff()来消除特殊的...目录条目,这会导致代码在没有被排除的情况下永远递归。)

剩下的一种潜在的失败模式是,这段代码很乐意遵循符号链接到目录,并尝试删除它们指向的目录中的所有内容(然后无法删除链接本身,因为rmdir()无法解决问题删除符号链接)。要解决此问题,您可能希望将is_dir($target)测试替换为!is_link($target) && is_dir($target)


全部放在一起,生成的代码如下所示:

function delete_files($target)
{
    if(!is_link($target) && is_dir($target))
    {
        // it's a directory; recursively delete everything in it
        $files = array_diff( scandir($target), array('.', '..') );
        foreach($files as $file) {
            delete_files("$target/$file");
        }
        rmdir($target);
    }
    else
    {
        // probably a normal file or a symlink; either way, just unlink() it
        unlink($target);
    }
}
delete_files($directory);

聚苯乙烯。另请参阅How do I recursively delete a directory and its entire contents (files + sub dirs) in PHP?

答案 1 :(得分:0)

因为第二次它在第二次出错时会调用它两次。

我无法证明这一点,但使用递归代码就是问题。