如何压缩文件夹并使用php下载?
Posted
技术标签:
【中文标题】如何压缩文件夹并使用php下载?【英文标题】:How to zip a folder and download it using php? 【发布时间】:2011-03-30 09:14:03 【问题描述】:我有一个名为“data”的文件夹。此“数据”文件夹包含一个文件“filecontent.txt”和另一个名为“文件”的文件夹。 “文件”文件夹包含一个“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';
?>
文件已下载但无法解压
【问题讨论】:
你说的没有用是什么意思? How to zip a whole folder using PHP的可能重复 我的意思是,当我在 url 处运行脚本时,不会发生错误,但不会发生压缩或下载。我不知道出了什么问题.. 【参考方案1】:您需要在目录中递归添加文件。像这样的东西(未经测试):
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
【讨论】:
感谢您的代码。我尝试过这个。但是当我在 url 处运行脚本时,不会发生错误,但不会发生压缩或下载。我不知道出了什么问题.. 代码压缩文件但不发送。您需要设置适当的标题(请参阅其他答案)然后调用fpassthru($zip_file)
你在第 14 行犯了一个小错误,应该是 $file
而不是 file
。【参考方案2】:
========= 对我来说唯一的解决方案! ! !==========
将所有子文件夹和子文件及其结构:
<?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);
?>
【讨论】:
【参考方案3】:几天前我不得不做同样的事情,这就是我所做的。
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);
用于填充和解析的方法:
/**
*
* 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.'/');
【讨论】:
我已经写了这段代码。 $zip = 新的 ZipArchive; if ($zip->open('check/test2.zip',ZIPARCHIVE::CREATE) === TRUE) if($zip->addEmptyDir('newDirectory')) echo '创建了一个新目录'; else echo '无法创建目录'; $zipfilename="test2.zip"; $zipname="check/test2.zip"; header('Content-Type: application/zip'); header('内容配置:附件;文件名=check/test1.zip'); //header('Content-Length:' .filesize($zipfilename));读取文件($zipname); //$zip->close(); 其他 回声失败'; 文件已下载但无法解压缩 在使用header之前不要使用echo,如果需要调试信息可以使用error_log()。【参考方案4】:查看链接的重复项。另一个经常被忽视且特别懒惰的选择是:
exec("zip -r data.zip data/");
header("Content-Type: application/zip");
readfile("data.zip"); // must be a writeable location though
【讨论】:
懒惰?加入一些平台检测并称之为简短而甜蜜:D 由于安全原因,在大多数托管服务器上,PHP 中禁用了 exec。 @FractalizeR:我不会称它们为“最”,而是“低端”。而且它也不是很好的安全方法的指示性。 (我还没有看到你无法通过将自己的 PHP 解释器放入 cgi-bin 来规避它。) 我试过这段代码。当我打开下载的文件时,它会下载但文件中没有数据。我用的是mac系统。这会是个问题吗? @Sangam254:是的。它需要安装zip
命令行工具。它也有多种变体。如果您有 Mac 版本,它可能需要不同的参数。 (另外:注意输出文件在任何情况下都必须位于可写位置。)【参考方案5】:
使用 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 内存。
【讨论】:
爱它!使用起来非常简单,并且适用于 GoDaddy 或 OVH 等共享(廉价)托管服务以上是关于如何压缩文件夹并使用php下载?的主要内容,如果未能解决你的问题,请参考以下文章
php导出excel表后,打包成压缩包,然后下载到本地如何实现?
如何使用 Javascript 下载、压缩和保存多个文件并取得进展?