duanchen7036 2015-03-17 15:05
浏览 60
已采纳

在PHP中压缩文件夹的内容

Before marking this post as a duplicate, please note that I have already searched for answer on SO and the once I've found so far (listed below) haven't been exactly what I've been looking for.

Those are just some of the ones I've looked at.

My problem is this: I can't use addFromString, I have to use addFile, it's a requirement of the task.

I've already tried a couple of ways, here's my current iteration:

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

When I try to open the resulting file, I get told that "Windows cannot open the folder. The Compressed(zipped) Folder '' is invalid."

I've managed to succesfully complete the task using addFromString, like so:

$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();
        }
    }
}

The above is mostly just copied straight from some example code I saw somewhere. If anyone can point me in a good direction I'd be very grateful!

***** UPDATE ***** I added an if around the close like this:

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

The message gets echoed out, so obviously the problem is there. I've also checked to make sure the $zip->open() works, and I've confirmed that it is opening it without a problem.

  • 写回答

2条回答 默认 最新

  • doulandai0641 2015-03-18 09:56
    关注

    Finally managed to get something working using addFile.

    I created a helper class that contains 3 functions: one to list all the files in a directory, 1 to zip all those files, and 1 to download the zipped files:

    <?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;
        }
    }
    ?>
    

    Here's how I called this class's functions:

    $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);
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式