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

时间:2011-03-30 09:14:04

标签: php zipfile

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

我必须将此文件夹“data”(使用php)以及其中的文件和文件夹压缩,然后下载压缩文件。

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

请帮忙。

我已经写了这段代码。

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

文件已下载但无法解压缩

5 个答案:

答案 0 :(得分:5)

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

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

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

为了获得更多胜利,我建议您阅读SPL DirectoryIterator here

答案 1 :(得分:4)

=========我唯一的解决方案! ! !==========

将所有子文件夹和子文件放在其结构中:

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

答案 2 :(得分:2)

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

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

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

将我的代码放在下面,您当然必须根据应用程序的设置进行调整。

// 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);

用于填补&amp;解析:

/**
 * 
 * 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.'/');
        }
    }
} 

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

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

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

代码示例:

$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');

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