php - 在 PHP 中压缩文件夹的内容

标签 php file compression zip

在将此帖子标记为重复之前,请注意我已经在 SO 上搜索了答案,到目前为止我找到的答案(如下所列)并不是我一直在寻找的答案。

这些只是我看过的一部分。

我的问题是:我不能使用 addFromString,我必须使用 addFile,这是任务的要求。

我已经尝试了几种方法,这是我当前的迭代:

public function getZippedFiles($path)
{
    $real_path = WEBROOT_PATH.$path;

    $files = new RecursiveIteratorIterator (new RecursiveDirectoryIterator($real_path), RecursiveIteratorIterator::LEAVES_ONLY);

    //# create a temp file & open it
    $tmp_file = tempnam($real_path,'');
    $zip_file = preg_replace('"\.tmp$"', '.zip', $tmp_file);

    $zip = new ZipArchive();
    $zip->open($zip_file, ZipArchive::CREATE);

    foreach ($files as $name=>$file)
    {
        error_log(print_r($name, true));
        error_log(print_r($file, true));
        if ( ($file == ".") || ($file == "..") )
        {
            continue;
        }

        $file_path = $file->getRealPath();
        $zip->addFile($file_path);
    }

    $zip->close();
}

当我尝试打开生成的文件时,我被告知“Windows 无法打开该文件夹。压缩(zipped)文件夹''无效。”

我已经成功地使用 addFromString 完成了任务,如下所示:

$file_path = WEBROOT_PATH.$path;
    $files = array();
    if (is_dir($file_path) == true)
    {
        if ($handle = opendir($file_path))
        {
            while (($file = readdir($handle)) !== false)
            {
                if (is_dir($file_path.$file) == false)
                {
                    $files[] = $file_path."\\".$file;
                }
            }

            //# create new zip opbject
            $zip = new ZipArchive();

            //# create a temp file & open it
            $tmp_file = tempnam($file_path,'');
            $zip_file = preg_replace('"\.tmp$"', '.zip', $tmp_file);

            $zip->open($zip_file, ZipArchive::CREATE);

            //# loop through each file
            foreach($files as $file){

                //# download file
                $download_file = file_get_contents($file);

                //#add it to the zip
                $zip->addFromString(basename($file),$download_file);

            }

            //# close zip
            $zip->close();
        }
    }
}

上面大部分内容都是直接从我在某处看到的一些示例代码中复制过来的。如果有人能给我指出一个好的方向,我将不胜感激!

***** 更新 ***** 我像这样在结尾处添加了一个 if:

if (!$zip->close()) {
    echo "failed writing zip to archive";
}

消息得到回显,很明显问题就在那里。我还检查以确保 $zip->open() 正常工作,并且我确认它可以正常打开它。

最佳答案

终于设法使用 addFile 实现了一些功能。

我创建了一个包含 3 个函数的辅助类:一个用于列出目录中的所有文件,一个用于压缩所有这些文件,还有一个用于下载压缩文件:

<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/config.php");

class FileHelper extends ZipArchive
{
    /**
     * Lists files in dir
     * 
     * This function expects an absolute path to a folder intended as the target.
     * The function will attempt to create an array containing the full paths to 
     * all files in the target directory, except for . and ..
     * 
     * @param dir [string]    : absolute path to the target directory
     * 
     * @return result [array] : array of absolute paths pointing to files in the target directory
     */
    public static function listDirectory($dir)
    {
        $result = array();
        $root = scandir($dir);
        foreach($root as $value) {
            if($value === '.' || $value === '..') {
                continue;
            }
            if(is_file("$dir$value")) {
                $result[] = "$dir$value";
                continue;
            }
            if(is_dir("$dir$value")) {
                $result[] = "$dir$value/";
            }
            foreach(self::listDirectory("$dir$value/") as $value)
            {
                $result[] = $value;
            }
        }
        return $result;
    }

    /**
     * Zips and downloads files
     * 
     * This function expects a directory location as target for a temp file, and a list(array)
     * of absolute file names that will be compressed and added to a zip file. After compression,
     * the temporary zipped file will be downloaded and deleted.
     * 
     * @param location [string] : absolute path to the directory that will contain the temp file
     * @param file_list [array] : array of absolute paths pointing to files that need to be compressed
     * 
     * @return void
     */
    public function downloadZip($file)
    {
        $modules = apache_get_modules();
        if (in_array('mod_xsendfile', $modules)) // Note, it is not possible to detect if X-SendFile is turned on or not, we can only check if the module is installed. If X-SendFile is installed but turned off, file downloads will not work
        {
            header("Content-Type: application/octet-stream");
            header('Content-Disposition: attachment; filename="'.basename($file).'"');
            header("X-Sendfile: ".realpath(dirname(__FILE__)).$file);

            // Apache will take care of the rest, so terminate the script
            exit;
        }

        header("Content-Type: application/octet-stream");
        header("Content-Length: " .(string)(filesize($file)) );
        header('Content-Disposition: attachment; filename="'.basename($file).'"');
        header("Content-Transfer-Encoding: binary");
        header("Expires: 0");
        header("Cache-Control: no-cache, must-revalidate");
        header("Cache-Control: private");
        header("Pragma: public");

        ob_end_clean(); // Without this, the file will be read into the output buffer which destroys memory on large files
        readfile($file);
    }

    /**
     * Zips files
     * 
     * This function expects a directory location as target for a temp file, and a list(array)
     * of absolute file names that will be compressed and added to a zip file. 
     * 
     * @param location [string]  : absolute path to the directory that will contain the temp file
     * @param file_list [array]  : array of absolute paths pointing to files that need to be compressed
     * 
     * @return zip_file [string] : absolute file path of the freshly zipped file
     */
    public function zipFile($location, $file_list)
    {
        $tmp_file = tempnam($location,'');
        $zip_file = preg_replace('"\.tmp$"', '.zip', $tmp_file);

        $zip = new ZipArchive();
        if ($zip->open($zip_file, ZIPARCHIVE::CREATE) === true)
        {
            foreach ($file_list as $file)
            {
                if ($file !== $zip_file)
                {
                    $zip->addFile($file, substr($file, strlen($location)));
                }
            }
            $zip->close();
        }

        // delete the temporary files
        unlink($tmp_file);

        return $zip_file;
    }
}
?>

下面是我如何调用这个类的函数:

$location = "d:/some/path/to/file/";
$file_list = $file_helper::listDirectory($location);
$zip_file = $file_helper->zipFile($location, $file_list);
$file_helper->downloadZip($zip_file);

关于php - 在 PHP 中压缩文件夹的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29102612/

相关文章:

c++ - 使用 qCompress 使用 GZip 压缩字符串?

c - LZO 解压缓冲区大小

PHP/用对应的非拉丁字符替换

javascript - laravel 获取数据以传递给 laravel blade 但采用 json 格式

java - 如何解析位于 HDFS 中的 XML 文件并追加子节点

c - 从文件中读取未知数量的整数

php - 获取最后一小时插入的最后一项

php - 嵌套动态 PHP 类

c - 尝试使用 strlen 但出现错误 : Conflicting types for 'strlen'

Java - 读取 BZ2 文件并即时解压缩/解析