1

If use this function to remove a directory + all files inside.

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

But whenever I do this, I get this error message:

Warning: rmdir(directory/12) [function.rmdir]: No such file or directory in delete_files.php

"directory/12" is the correct name of the directory I wanted to delete. I don't understand why it says that it does not exist because it does! Weirdly though, even though I got the error message, the directory DID get deleted.

So I added a line of code print_n($files); before the for-loop and it game me two arrays -- one containing the directory ("directory/12") and the other containing all the files of the directory ("directory/12/01.gif", "directory/12/02.gif" etc). So I figured the directory must have gotten deleted in the for-loop and removed the line rmdir($target) and tried it again. This time, all the files within the directory got deleted but the directory itself remained.

So apparently, rmdir DOES indeed remove the directory correctly. But then, why does it give me the error message beforehand that it doesn't exist?

4

2 回答 2

3

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

说明:当您最初调用函数 asdelete_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);

附言。另请参阅如何在 PHP 中递归删除目录及其全部内容(文件 + 子目录)?

于 2014-06-10T15:01:10.990 回答
-1

因为你在第一次工作时调用它两次,第二次它给出错误。

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

于 2014-06-10T14:53:07.790 回答