PHP:安全删除目录的方法?

4

考虑以下代码:

public static function removeDir($src)
{
    if (is_dir($src)) {
        $dir = @opendir($src);
        if ($dir === false)
            return;
        while(($file = readdir($dir)) !== false) {
            if ($file != '.' && $file != '..') {
                $path = $src . DIRECTORY_SEPARATOR . $file;
                if (is_dir($path)) {
                    self::removeDir($path);
                } else {
                    @unlink($path);
                }
            }
        }
        closedir($dir);
        @rmdir($src);
    }
}

这将删除一个目录。但如果unlink在任何子目录上失败或opendir失败,则该目录将保留一些内容。
我希望要么全部删除,要么什么也不删除。我考虑在删除前复制目录,如果出现任何问题,就恢复副本。但也许有更好的方法,比如锁定文件或类似的东西?

你可以使用flock()来锁定文件,但是没有办法检查文件/目录是否可以被删除,除非实际删除它。不过,你可以事先检查chmod权限,或者使用is_writable()或类似的方法来检查是否可写。 - Ben Fortune
1
这也可以使用 fileperms() 来完成... - Boldewyn
1
即使权限没问题,如果文件在另一个进程中仍然打开,我不确定它是否会被删除。 - Ben Fortune
复制它,删除它,如果被删除则复制回来,否则抛出删除消息失败... - We0
你可以使用exec吗?或者shell_exec()?你希望脚本跨浏览器运行吗?还是只针对特定的操作系统? - jnhghy - Alexandru Jantea
显示剩余3条评论
2个回答

1

一般来说,我会确认以下评论:

"复制它,删除它,如果已删除则复制回来,否则抛出删除消息失败..." - We0

但是让我们考虑一些附加条件:

尝试实现事务保存文件删除意味着您想要在同一组文件上允许竞争文件锁定。事务处理通常是确保一致性的最“昂贵”的方式。即使PHP具有任何类型的testdelete可用,这也是正确的,因为您需要在第一次运行中测试删除所有内容,然后进行第二个循环,这需要时间(并且您在危险之中,在此期间文件系统上的某些内容发生了更改)。还有其他选择:

  1. 尝试将真正需要事务保存的内容隔离出来,并在数据库中处理这些数据访问。例如,MySQL/InnoDB支持所有琐碎的事务处理细节。
  2. 定义和实现专用的“写/锁定所有权”。因此,您有文件夹A和B以及子项目,您的php可以锁定A中的文件,其他进程可以锁定B中的文件。您的php和其他进程都可以读取A和B。这在文件上变得棘手,因为文件读取也会导致锁定,其持续时间越长,文件越大。因此,在文件基础上,您可能需要丰富它,包括文件大小限制、容错期等。
  3. 定义和实现专用的访问时间范围。例如,所有文件可以在一周内使用,但您在星期日晚上有一个维护时间段,该时间段也可以运行删除操作,因此需要无锁环境。

好吧,假设我的推理还不足以令人恐惧:) - 并且您仍然要实现事务保存文件删除 - 您的例程可以这样实现:

  1. 备份所有文件
  2. 如果备份失败,可以尝试第二次、第三次、第四次(这是一项实现决策)
  3. 如果没有成功的备份,停止
  4. 运行您的删除过程,有两种实现选项(无论如何,您需要记录已成功删除的文件):
    • 始终完全运行,并记录所有错误(这可以作为后续任务列表返回给用户,但可能运行时间很长)
    • 运行并在第一个错误处停止
  5. 如果删除成功,则一切正常/停止;如果不成功,则继续回滚
  6. 仅从存档中复制以前成功删除的文件(仅限它们!)
  7. 清除您的备份

因此,这只是文件级别上的事务保存。它不处理在步骤5和6之间有人更改文件夹权限的情况。


0

或者您可以尝试将目录重命名/移动到类似于/tmp/的位置,它会成功或失败 - 但文件不会消失。即使另一个进程有一个打开的句柄,移动也应该是可以的。当tmp文件夹被清空时,文件将在稍后消失。


如果文件夹中有任何一个文件被打开,我认为该文件夹无法移动。 - Dalius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接