php 如何压缩文件夹并使用php下载?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5484347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 21:35:41  来源:igfitidea点击:

How to zip a folder and download it using php?

phpzipfile

提问by Sangam254

I have folder named "data". This "data" folder contains a file "filecontent.txt" and another folder named "Files". The "Files" folder contains a "info.txt" file. So it is a folder inside folder structure.

我有一个名为“data”的文件夹。这个“data”文件夹包含一个文件“filecontent.txt”和另一个名为“Files”的文件夹。“文件”文件夹包含一个“info.txt”文件。所以它是文件夹结构中的文件夹。

I have to zip this folder "data"(using php) along with the file and folder inside it, and download the zipped file.

我必须压缩这个文件夹“数据”(使用 php)以及其中的文件和文件夹,然后下载压缩文件。

I have tried the examples available at http://www.php.net/manual/en/zip.examples.phpThese examples did not work. My PHP version is 5.2.10

我已经尝试了http://www.php.net/manual/en/zip.examples.php提供的示例 这些示例不起作用。我的 PHP 版本是 5.2.10

Please help.

请帮忙。

I have written this code.

我写了这段代码。

<?php
$zip = new ZipArchive;
if ($zip->open('check/test2.zip',ZIPARCHIVE::CREATE) === TRUE) {
    if($zip->addEmptyDir('newDirectory')) {
        echo 'Created a new directory';
    } else {
        echo 'Could not create directory';
    }
    $zipfilename="test2.zip";
    $zipname="check/test2.zip";

    header('Content-Type: application/zip');
    header('Content-disposition: attachment; filename=check/test1.zip');    //header('Content-Length: ' . filesize( $zipfilename));
    readfile($zipname);  //$zip->close(); } else { echo failed';
}
?>

file downloaded but could not unzip

文件已下载但无法解压

回答by chriso

You need to recursively add files in the directory. Something like this (untested):

您需要在目录中递归添加文件。像这样的东西(未经测试):

function createZipFromDir($dir, $zip_file) {
    $zip = new ZipArchive;
    if (true !== $zip->open($zip_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) {
        return false;
    }
    zipDir($dir, $zip);
    return $zip;
}

function zipDir($dir, $zip, $relative_path = DIRECTORY_SEPARATOR) {
    $dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
    if ($handle = opendir($dir)) {
        while (false !== ($file = readdir($handle))) {
            if (file === '.' || $file === '..') {
                continue;
            }
            if (is_file($dir . $file)) {
                $zip->addFile($dir . $file, $file);
            } elseif (is_dir($dir . $file)) {
                zipDir($dir . $file, $zip, $relative_path . $file);
            }
        }
    }
    closedir($handle);
}

Then call $zip = createZipFromDir('/tmp/dir', 'files.zip');

然后打电话 $zip = createZipFromDir('/tmp/dir', 'files.zip');

For even more win I'd recommend reading up on the SPL DirectoryIteratorhere

为了获得更多胜利,我建议在这里阅读 SPLDirectoryIterator

回答by T.Todua

========= The only solution for me ! ! !==========

========== 对我来说唯一的解决方案!!!==========

Puts all subfolders and sub-files with their structure:

放置所有子文件夹和子文件及其结构:

<?php
$the_folder = 'path/foldername';
$zip_file_name = 'archived_name.zip';


$download_file= true;
//$delete_file_after_download= true; doesnt work!!


class FlxZipArchive extends ZipArchive {
    /** Add a Dir with Files and Subdirs to the archive;;;;; @param string $location Real Location;;;;  @param string $name Name in Archive;;; @author Nicolas Heimann;;;; @access private  **/

    public function addDir($location, $name) {
        $this->addEmptyDir($name);

        $this->addDirDo($location, $name);
     } // EO addDir;

    /**  Add Files & Dirs to archive;;;; @param string $location Real Location;  @param string $name Name in Archive;;;;;; @author Nicolas Heimann
     * @access private   **/
    private function addDirDo($location, $name) {
        $name .= '/';
        $location .= '/';

        // Read all Files in Dir
        $dir = opendir ($location);
        while ($file = readdir($dir))
        {
            if ($file == '.' || $file == '..') continue;
            // Rekursiv, If dir: FlxZipArchive::addDir(), else ::File();
            $do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
            $this->$do($location . $file, $name . $file);
        }
    } // EO addDirDo();
}

$za = new FlxZipArchive;
$res = $za->open($zip_file_name, ZipArchive::CREATE);
if($res === TRUE) 
{
    $za->addDir($the_folder, basename($the_folder));
    $za->close();
}
else  { echo 'Could not create a zip archive';}

if ($download_file)
{
    ob_get_clean();
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private", false);
    header("Content-Type: application/zip");
    header("Content-Disposition: attachment; filename=" . basename($zip_file_name) . ";" );
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: " . filesize($zip_file_name));
    readfile($zip_file_name);

    //deletes file when its done...
    //if ($delete_file_after_download) 
    //{ unlink($zip_file_name); }
}
?>

回答by Deratrius

I had to do the same thing a few days ago and here is what I did.

几天前我不得不做同样的事情,这就是我所做的。

1) Retrieve File/Folder structure and fill an array of items. Each item is either a file or a folder, if it's a folder, retrieve its content as items the same way.

1)检索文件/文件夹结构并填充项目数组。每个项目要么是一个文件要么是一个文件夹,如果它是一个文件夹,则以相同的方式将其内容作为项目检索。

2) Parse that array and generate the zip file.

2) 解析该数组并生成 zip 文件。

Put my code below, you will of course have to adapt it depending on how your application was made.

将我的代码放在下面,您当然必须根据您的应用程序的制作方式对其进行调整。

// Get files
$items['items'] = $this->getFilesStructureinFolder($folderId);

$archiveName = $baseDir . 'temp_' . time(). '.zip';

if (!extension_loaded('zip')) {
    dl('zip.so');
}

//all files added now
$zip = new ZipArchive();
$zip->open($archiveName, ZipArchive::OVERWRITE);

$this->fillZipRecursive($zip, $items);

$zip->close();

//outputs file
if (!file_exists($archiveName)) {
    error_log('File doesn\'t exist.');
    echo 'Folder is empty';
    return;
}


header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . basename($archiveName) . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($archiveName));
readfile($archiveName);

//deletes file when its done...
unlink($archiveName);

Methods used to fill & parse:

用于填充和解析的方法:

/**
 * 
 * Gets all the files recursively within a folder and keeps the structure.
 * 
 * @param   int     $folderId   The id of the folder from which we start the search
 * @return  array   $tree       The data files/folders data structure within the given folder id
 */
public function getFilesStructureinFolder($folderId) {
    $result = array();

    $query = $this->db->query('SELECT * FROM xx WHERE deleted = 0 AND status = 1 AND parent_folder_id = ? ORDER BY name ASC', $folderId);

    $folders = $query->result();

    foreach($folders as $folder) {
        $folderItem = array();
        $folderItem['type']     = 'folder';
        $folderItem['obj']      = $folder;  
        $folderItem['items']    = $this->getFilesStructureinFolder($folder->id);
        $result[]               = $folderItem;
    }

    $query = $this->db->query('SELECT * FROM xx WHERE deleted = 0 AND xx = ? AND status = 1 ORDER BY name ASC', $folderId);

    $files = $query->result();

    foreach ($files as $file) {
        $fileItem = array();
        $fileItem['type']   = 'file';
        $fileItem['obj']    = $file;    
        $result[]           = $fileItem;
    }

    return $result;
}

/**
 * Fills zip file recursively
 * 
 * @param ZipArchive    $zip        The zip archive we are filling
 * @param Array         $items      The array representing the file/folder structure
 * @param String        $zipPath    Local path within the zip
 * 
 */
public function fillZipRecursive($zip, $items, $zipPath = '') {
    $baseDir = $this->CI->config->item('xxx');

    foreach ($items['items'] as $item) {

        //Item is a file
        if ($item['type'] == 'file') {
            $file = $item['obj'];
            $fileName = $baseDir . '/' . $file->fs_folder_id . '/' . $file->file_name;

            if (trim($file->file_name) == '' || !file_exists($fileName))
                continue;

            $zip->addFile($fileName, $zipPath.''.$file->file_name);
        }

        //Item is a folder
        else if ($item['type'] == 'folder') {
            $folder     = $item['obj'];

            $zip->addEmptyDir($zipPath.''.$folder->name);

            //Folder probably has items in it!
            if (!empty($item['items']))
                $this->fillZipRecursive($zip, $item, $zipPath.'/'.$folder->name.'/');
        }
    }
} 

回答by Skrol29

Use the TbsZipclass to create a new zip Archive. TbsZip is simple, it uses no temporary files, no zip EXE, it has no dependency, and has a Download feature that flushes the archive as a download file.

使用TbsZip类创建新的 zip 存档。TbsZip 很简单,它不使用临时文件,不使用 zip EXE,它没有依赖性,并且具有将存档刷新为下载文件的下载功能。

You just have to loop under the folder tree and add all files in the archive, and then flush it.

您只需在文件夹树下循环并添加存档中的所有文件,然后刷新它。

Code example:

代码示例:

$zip = new clsTbsZip(); // instantiate the class
$zip->CreateNew(); // create a virtual new zip archive
foreach (...) { // your loop to scann the folder tree
  ...
  // add the file in the archive
  $zip->FileAdd($FileInnerName, $LocalFilePath, TBSZIP_FILE);
}
// flush the result as an HTTP download
$zip->Flush(TBSZIP_DOWNLOAD, 'my_archive.zip');

Files added in the archive will be compressed sequentially during the Flush() method. So your archive can contain numerous sub-files, this won't increase the PHP memory.

添加到存档中的文件将在 Flush() 方法期间按顺序压缩。因此您的存档可以包含大量子文件,这不会增加 PHP 内存。

回答by mario

See the linked duplicates. Another often overlooked and particular lazy option would be:

查看链接的重复项。另一个经常被忽视和特别懒惰的选择是:

exec("zip -r data.zip data/");
header("Content-Type: application/zip");
readfile("data.zip");    // must be a writeable location though