php 清理文件夹 WSTMALL 处理的错误思想解析

522 阅读1分钟

在php7.1 下使用WSTMALL出现一下问题,关于php的文件操作 WSTMALL的处理方式如下

function WSTDelDir($dirpath)
{
    $dh = opendir($dirpath);
    while (($file = readdir($dh))!==false) { //=====>C
        if ($file != "." && $file != "..") {
            $fullpath = $dirpath . "/" . $file;
            if (!is_dir($fullpath)) {
                unlink($fullpath);
            } else {
                WSTDelDir($fullpath); //=======>A
                rmdir($fullpath);
            }
        }
    }
    closedir($dh);//=========>B
    $isEmpty = 1;
    $dh      = opendir($dirpath);
    while (($file = readdir($dh)) != false) {
        if ($file != "." && $file != "..") {
            $isEmpty = 0;
            break;
        }
    }
    return $isEmpty;
}
我调试了一下发现文件夹正常删除,但是 最后总会遇到一个TEMP文件夹内有文件。 所以个人感觉WSTMALL的删除有问题。 通过个人跟踪发现 标记为A处的命令并没有执行第二次,只执行到第一处就结束了。也就是说。这个方法没有深度递归。 于是我用了另一个opensns的实现

function WSTDelDir($dirname)
{
    if (!file_exists($dirname)) {
        return 0;
    }
    if (is_file($dirname) || is_link($dirname)) {
        return unlink($dirname);
    }
    $dir = dir($dirname);
    if($dir){
        while (false !== $entry = $dir->read()) {
            if ($entry == '.' || $entry == '..') {
                continue;
            }
            WSTDelDir($dirname . DIRECTORY_SEPARATOR . $entry);
        }
    }
    $dir->close();
    return rmdir($dirname);
}
对比之后发现原来是原先的实现有问题。 关键就在于B标记之后.

1. WSTMALL的写法有读取了一遍文件夹。这个是有问题的。原因在于当前进程虽然在之前成功删除了文件夹,但是并没有保证其他进程不会生成缓存文件。所以WSTMALL的失败就在此处。

2. 另一点就是OPENSNS的处理方式,成功的删除了所有缓存文件,而 WSTMALL无法成功处理也在于B标记之后的数据,他提前返回了。并没有循环完毕所有的目录。

3. 最后说一下

关于在PHP7.1正式版下为什么WSTMALL的清理方法不执行了。
原因是PHP7.1 修正一处bug 。[x] Fixed bug #72667 (opendir() with ftp:// attempts to open data stream for non-existent directories).
这导致opendir()打开一个不存在目录返回的是null而不是false