在 PHP 5.1 上创建和下载 ZipArchive 失败,在 PHP 5.4 上有效

Creating and downloading ZipArchive fails on PHP 5.1, works on PHP 5.4

以下 class 失败并出现 ZipArchive 错误 23 - "Entry has been deleted" 尝试添加嵌套在另一个添加的空目录中的新空目录时。例如:

dir1:
    file1
    file2
    ...

工作正常,但类似于:

dir1:
    dir2:
        file1
        ...
    file1
    file1
    ...

尝试添加 dir1/dir2 时会失败。

下载器Class

class Downloader {

    var $path, $tmp, $zip, $txt, $selected;

    function __construct($selected) {
        global $webroot;

        $this->path = $webroot.'downloads/';
        $this->tmp = tempnam('../tmp', 'dln');
        $this->zip = new ZipArchive();
        $this->zip->open($this->tmp, ZipArchive::OVERWRITE);
        $this->txt = '';
        $this->selected = $selected;
    }

    public function incl_file($name) {
        $this->zip->addFile($this->path.$name, $name);
    }

    public function incl_dir($name) {
        $this->zip->addEmptyDir($name);
        $files = new DirectoryIterator($this->path.$name.'/');
        foreach ($files as $file) {
            if (!$file->isDot()) {
                if ($file->isDir()) {
                    $this->incl_dir($name.'/'.$file->getFilename());
                } else {
                    $this->incl_file($name.'/'.$file->getFilename());
                }
            }
        }
    }

    public function download($downloadObj) {
        $selected = preg_split('/,/', $this->selected);
        foreach ($selected as $name) {
            $this->txt .= file_get_contents($this->path.$name.'.snip');

            foreach ($downloadObj->files as $file) {
                if ($name == $file->name) {
                    // check to see if there are files to include
                    if (strlen($file->incl_files) > 0) {
                        // if so, get include directories
                        $incl_dirs = preg_split('/,/', $file->incl_dir);
                        // iterate include directories
                        foreach ($incl_dirs as $dir) {
                            // get include file groups
                            $incl_file_groups = preg_split('/,/', $file->incl_files);
                            // iterate include file groups
                            foreach ($incl_file_groups as $group) {
                                // get individual include files
                                $incl_files = preg_split('/\|/', $group);
                                // iterate individual include files
                                foreach ($incl_files as $f) {
                                    // check to see if all files in include dir should be inserted
                                    if ($f == '*') {
                                        $this->incl_dir($dir);
                                    } else {
                                        $path = '';
                                        if ($dir == "/") {
                                            $path = $f;
                                        } else {
                                            $path .= $dir.'/'.$f;
                                        }
                                        $this->incl_file($path);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        $this->txt = file_get_contents($this->path.'header.inc').$this->txt.file_get_contents($this->path.'footer.inc');
        $this->zip->addFromString('DownloadTemplate.xml', $this->txt);
        $this->zip->close();
        $filename = 'MyDownload.zip';
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
        header('Last-Modified: ' . gmdate('D,d M YH:i:s') . ' GMT');
        header('Cache-Control: no-cache, must-revalidate');
        header('Pragma: no-cache');
        header('Content-type: application/zip');
        header('Content-Disposition: attachment; filename='.$filename);
        header('Content-Transfer-Encoding: binary');
        readfile($this->tmp);
        unlink($this->tmp);
    }
}

Pre-PHP 5.2 zip 是通过 different means 安装的。因此,当您更新到 5.4 时,您可能使用 PHP 编译或安装了 zip 扩展,而在 5.1

上没有它

经过大量调试和测试不同的选项后,问题出在对 addEmptyDir() 的调用中。出于某种原因,我仍然没有找到答案,调用未能在 Zip 中添加目录。然而,我随后发现这个调用完全没有必要,因为 addFile() 会在给定相对路径名时创建必要的目录,例如 'dir1/file1'。知道这一点后,我刚刚删除了对 addEmptyDir() 的调用,并且能够正确生成具有适当目录的 zip 文件。