如何使用 PHP 压缩整个文件夹
Posted
技术标签:
【中文标题】如何使用 PHP 压缩整个文件夹【英文标题】:How to zip a whole folder using PHP 【发布时间】:2011-06-22 08:00:33 【问题描述】:我在 stackoveflow 找到了一些关于如何压缩特定文件的代码,但是特定文件夹呢?
Folder/
index.html
picture.jpg
important.txt
在My Folder
里面,有文件。压缩My Folder
后,我还想删除除important.txt
之外的文件夹的全部内容。
在stack 找到这个
我需要你的帮助。 谢谢。
【问题讨论】:
据我所知,您提供的 *** 链接实际上会压缩多个文件。哪部分有问题? @lasseespeholt 我给你的链接只压缩一个特定的文件,而不是文件夹和文件夹的内容.. 他获取一组文件(本质上是一个文件夹)并将所有文件添加到 zip 文件中(循环)。我可以看到现在已经发布了一个很好的答案 +1 :) 这是相同的代码,数组现在只是一个目录中的文件列表。 compress/archive folder using php script的可能重复 这可以帮助你codingbin.com/compressing-a-directory-of-files-with-php 【参考方案1】:如果您有子文件夹,并且想要保留文件夹的结构,请执行以下操作:
$zip = new \ZipArchive();
$fileName = "my-package.zip";
if ($zip->open(public_path($fileName), \ZipArchive::CREATE) === true)
$files = \Illuminate\Support\Facades\File::allFiles(
public_path('/MY_FOLDER_PATH/')
);
foreach ($files as $file)
$zip->addFile($file->getPathname(), $file->getRelativePathname());
$zip->close();
return response()
->download(public_path($fileName))
->deleteFileAfterSend(true);
deleteFileAfterSend(true)
从服务器中删除文件my-package.zip
。
不要忘记将/MY_FOLDER_PATH/
更改为您要下载的文件夹的路径。
【讨论】:
【参考方案2】:包括所有子文件夹:
new GoodZipArchive('path/to/input/folder', 'path/to/output_zip_file.zip') ;
这里是source-code(可能有更新,但下面我放了那个代码的副本):
class GoodZipArchive extends ZipArchive
public function __construct($a=false, $b=false) $this->create_func($a, $b);
public function create_func($input_folder=false, $output_zip_file=false)
if($input_folder !== false && $output_zip_file !== false)
$res = $this->open($output_zip_file, ZipArchive::CREATE);
if($res === TRUE) $this->addDir($input_folder, basename($input_folder)); $this->close();
else echo 'Could not create a zip archive. Contact Admin.';
// Add a Dir with Files and Subdirs to the archive
public function addDir($location, $name)
$this->addEmptyDir($name);
$this->addDirDo($location, $name);
// Add Files & Dirs to archive
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: GoodZipArchive::addDir(), else ::File();
$do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
$this->$do($location . $file, $name . $file);
【讨论】:
【参考方案3】:ZipArchive 类中有一个有用的未记录方法:addGlob();
$zipFile = "./testZip.zip";
$zipArchive = new ZipArchive();
if ($zipArchive->open($zipFile, (ZipArchive::CREATE | ZipArchive::OVERWRITE)) !== true)
die("Failed to create archive\n");
$zipArchive->addGlob("./*.txt");
if ($zipArchive->status != ZIPARCHIVE::ER_OK)
echo "Failed to write files to zip\n";
$zipArchive->close();
现在记录在:www.php.net/manual/en/ziparchive.addglob.php
【讨论】:
@netcoder - 编写用于测试它的 phpt 的好处......基本上,通读 ZipArchive 类的源代码,并在那里找到它......还有一个未记录的 addPattern()采用正则表达式样式模式的方法,但我从未设法让它工作(可能是类中的错误) @kread - 你可以将它与任何可以使用 glob() 提取的文件列表一起使用,所以我发现它非常有用,因为我发现了它。addGlob
是递归的吗?
ZipArchive::open() 在失败时返回一个非零整数,因此检查 if (!$zipArchive->open($zipFile, ZIPARCHIVE::OVERWRITE))
是无效的,只是浪费了我一个小时的时间来尝试调试!已相应地编辑了答案。
此外,如果指定文件不存在,仅使用 ZipArchive::OVERWRITE
将失败,因此请改用 (ZipArchive::CREATE | ZipArchive::OVERWRITE)
(假设您要创建或覆盖适用)。【参考方案4】:
在 PHP 中创建一个 zip 文件夹。
Zip 创建方法
public function zip_creation($source, $destination)
$dir = opendir($source);
$result = ($dir === false ? false : true);
if ($result !== false)
$rootPath = realpath($source);
// Initialize archive object
$zip = new ZipArchive();
$zipfilename = $destination.".zip";
$zip->open($zipfilename, ZipArchive::CREATE | ZipArchive::OVERWRITE );
// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $name => $file)
// Skip directories (they would be added automatically)
if (!$file->isDir())
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
// Zip archive will be created only after closing object
$zip->close();
return TRUE;
else
return FALSE;
调用zip方法
$source = $source_directory;
$destination = $destination_directory;
$zipcreation = $this->zip_creation($source, $destination);
【讨论】:
【参考方案5】:使用它工作正常。
$dir = '/Folder/';
$zip = new ZipArchive();
$res = $zip->open(trim($dir, "/") . '.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
if ($res === TRUE)
foreach (glob($dir . '*') as $file)
$zip->addFile($file, basename($file));
$zip->close();
else
echo 'Failed to create to zip. Error: ' . $res;
【讨论】:
【参考方案6】:使用此功能:
function zip($source, $destination)
if (!extension_loaded('zip') || !file_exists($source))
return false;
$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE))
return false;
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true)
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file)
$file = str_replace('\\', '/', $file);
// Ignore "." and ".." folders
if (in_array(substr($file, strrpos($file, '/')+1), array('.', '..')))
continue;
$file = realpath($file);
if (is_dir($file) === true)
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
elseif (is_file($file) === true)
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
elseif (is_file($source) === true)
$zip->addFromString(basename($source), file_get_contents($source));
return $zip->close();
使用示例:
zip('/folder/to/compress/', './compressed.zip');
【讨论】:
【参考方案7】:代码更新于 2015 年 4 月 22 日。
压缩整个文件夹:
// Get real path for our folder
$rootPath = realpath('folder-to-zip');
// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
// Skip directories (they would be added automatically)
if (!$file->isDir())
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
// Zip archive will be created only after closing object
$zip->close();
压缩整个文件夹 + 删除除“important.txt”以外的所有文件:
// Get real path for our folder
$rootPath = realpath('folder-to-zip');
// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Initialize empty "delete list"
$filesToDelete = array();
// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
// Skip directories (they would be added automatically)
if (!$file->isDir())
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
// Add current file to "delete list"
// delete it later cause ZipArchive create archive only after calling close function and ZipArchive lock files until archive created)
if ($file->getFilename() != 'important.txt')
$filesToDelete[] = $filePath;
// Zip archive will be created only after closing object
$zip->close();
// Delete all files from "delete list"
foreach ($filesToDelete as $file)
unlink($file);
【讨论】:
您必须将 dir(此脚本所在的位置)上的 chmod(可写)设置为 777。例如:如果脚本位于 /var/www/localhost/script.php,那么您需要设置 chmod 0777在目录 /var/www/localhost/. 在调用$zip->close()
之前删除文件将不起作用。检查我的答案here
@alnas-s-re 这是问题的要求:“我还想删除文件夹的全部内容,除了important.txt”。另外我建议您在执行代码之前始终阅读代码。
@alnas-s-re 哈哈哈 ...对不起 :) ...哈哈哈
@nick-newman,是的,要计算百分比,您可以在循环内使用 php.net/manual/ru/function.iterator-count.php + counter。关于压缩级别 - 目前无法使用 ZipArchive:***.com/questions/1833168/…【参考方案8】:
对于阅读这篇文章并寻找为什么使用 addFile 而不是 addFromString 压缩文件的任何人,它不会使用它们的绝对路径压缩文件(只是压缩文件而不是其他任何东西),请参阅我的问题和回答 @987654321 @
【讨论】:
【参考方案9】:我在 google 中发现这篇文章是第二个最佳结果,首先是使用 exec :(
无论如何,虽然这并不完全符合我的需求。我决定用我的快速但扩展的版本为其他人发布答案。
脚本功能
备份文件按天命名,PREFIX-YYYY-MM-DD-POSTFIX.EXTENSION 文件报告/丢失 以前的备份列表 不压缩/包括以前的备份;) 适用于 windows/linux无论如何,在脚本上。虽然它可能看起来很多..记住这里有多余的..所以随意删除报告部分根据需要...
它也可能看起来很乱,并且某些东西可以很容易地清理......所以不要评论它,它只是一个包含基本 cmets 的快速脚本.. 不适合现场使用.. 但易于清理现场使用!
在本例中,它是从位于根 www / public_html 文件夹内的目录运行的。因此只需向上移动一个文件夹即可到达根目录。
<?php
// DIRECTORY WE WANT TO BACKUP
$pathBase = '../'; // Relate Path
// ZIP FILE NAMING ... This currently is equal to = sitename_www_YYYY_MM_DD_backup.zip
$zipPREFIX = "sitename_www";
$zipDATING = '_' . date('Y_m_d') . '_';
$zipPOSTFIX = "backup";
$zipEXTENSION = ".zip";
// SHOW PHP ERRORS... REMOVE/CHANGE FOR LIVE USE
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);
// ############################################################################################################################
// NO CHANGES NEEDED FROM THIS POINT
// ############################################################################################################################
// SOME BASE VARIABLES WE MIGHT NEED
$iBaseLen = strlen($pathBase);
$iPreLen = strlen($zipPREFIX);
$iPostLen = strlen($zipPOSTFIX);
$sFileZip = $pathBase . $zipPREFIX . $zipDATING . $zipPOSTFIX . $zipEXTENSION;
$oFiles = array();
$oFiles_Error = array();
$oFiles_Previous = array();
// SIMPLE HEADER ;)
echo '<center><h2>PHP Example: ZipArchive - Mayhem</h2></center>';
// CHECK IF BACKUP ALREADY DONE
if (file_exists($sFileZip))
// IF BACKUP EXISTS... SHOW MESSAGE AND THATS IT
echo "<h3 style='margin-bottom:0px;'>Backup Already Exists</h3><div style='width:800px; border:1px solid #000;'>";
echo '<b>File Name: </b>',$sFileZip,'<br />';
echo '<b>File Size: </b>',$sFileZip,'<br />';
echo "</div>";
exit; // No point loading our function below ;)
else
// NO BACKUP FOR TODAY.. SO START IT AND SHOW SCRIPT SETTINGS
echo "<h3 style='margin-bottom:0px;'>Script Settings</h3><div style='width:800px; border:1px solid #000;'>";
echo '<b>Backup Directory: </b>',$pathBase,'<br /> ';
echo '<b>Backup Save File: </b>',$sFileZip,'<br />';
echo "</div>";
// CREATE ZIPPER AND LOOP DIRECTORY FOR SUB STUFF
$oZip = new ZipArchive;
$oZip->open($sFileZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$oFilesWrk = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathBase),RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($oFilesWrk as $oKey => $eFileWrk)
// VARIOUS NAMING FORMATS OF THE CURRENT FILE / DIRECTORY.. RELATE & ABSOLUTE
$sFilePath = substr($eFileWrk->getPathname(),$iBaseLen, strlen($eFileWrk->getPathname())- $iBaseLen);
$sFileReal = $eFileWrk->getRealPath();
$sFile = $eFileWrk->getBasename();
// WINDOWS CORRECT SLASHES
$sMyFP = str_replace('\\', '/', $sFileReal);
if (file_exists($sMyFP)) // CHECK IF THE FILE WE ARE LOOPING EXISTS
if ($sFile!="." && $sFile!="..") // MAKE SURE NOT DIRECTORY / . || ..
// CHECK IF FILE HAS BACKUP NAME PREFIX/POSTFIX... If So, Dont Add It,, List It
if (substr($sFile,0, $iPreLen)!=$zipPREFIX && substr($sFile,-1, $iPostLen + 4)!= $zipPOSTFIX.$zipEXTENSION)
$oFiles[] = $sMyFP; // LIST FILE AS DONE
$oZip->addFile($sMyFP, $sFilePath); // APPEND TO THE ZIP FILE
else
$oFiles_Previous[] = $sMyFP; // LIST PREVIOUS BACKUP
else
$oFiles_Error[] = $sMyFP; // LIST FILE THAT DOES NOT EXIST
$sZipStatus = $oZip->getStatusString(); // GET ZIP STATUS
$oZip->close(); // WARNING: Close Required to append files, dont delete any files before this.
// SHOW BACKUP STATUS / FILE INFO
echo "<h3 style='margin-bottom:0px;'>Backup Stats</h3><div style='width:800px; height:120px; border:1px solid #000;'>";
echo "<b>Zipper Status: </b>" . $sZipStatus . "<br />";
echo "<b>Finished Zip Script: </b>",$sFileZip,"<br />";
echo "<b>Zip Size: </b>",human_filesize($sFileZip),"<br />";
echo "</div>";
// SHOW ANY PREVIOUS BACKUP FILES
echo "<h3 style='margin-bottom:0px;'>Previous Backups Count(" . count($oFiles_Previous) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
foreach ($oFiles_Previous as $eFile)
echo basename($eFile) . ", Size: " . human_filesize($eFile) . "<br />";
echo "</div>";
// SHOW ANY FILES THAT DID NOT EXIST??
if (count($oFiles_Error)>0)
echo "<h3 style='margin-bottom:0px;'>Error Files, Count(" . count($oFiles_Error) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
foreach ($oFiles_Error as $eFile)
echo $eFile . "<br />";
echo "</div>";
// SHOW ANY FILES THAT HAVE BEEN ADDED TO THE ZIP
echo "<h3 style='margin-bottom:0px;'>Added Files, Count(" . count($oFiles) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
foreach ($oFiles as $eFile)
echo $eFile . "<br />";
echo "</div>";
// CONVERT FILENAME INTO A FILESIZE AS Bytes/Kilobytes/Megabytes,Giga,Tera,Peta
function human_filesize($sFile, $decimals = 2)
$bytes = filesize($sFile);
$sz = 'BKMGTP';
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.$decimalsf", $bytes / pow(1024, $factor)) . @$sz[$factor];
?>
它有什么作用??
它会简单地压缩变量 $pathBase 的完整内容并将压缩文件存储在同一个文件夹中。它对以前的备份进行简单检测并跳过它们。
CRON 备份
我刚刚在 linux 上测试过这个脚本,并且在使用绝对 url 作为 pathBase 的 cron 作业中运行良好。
【讨论】:
我也排除了删除脚本,你可以看到这个接受的答案 必须喜欢那些随机的反对票,而无需评论解释原因。【参考方案10】:这将解决您的问题。请尝试一下。
$zip = new ZipArchive;
$zip->open('testPDFZip.zip', ZipArchive::CREATE);
foreach (glob(APPLICATION_PATH."pages/recruitment/uploads/test_pdf_folder/*") as $file)
$new_filename = end(explode("/",$file));
$zip->addFile($file,"emp/".$new_filename);
$zip->close();
【讨论】:
【参考方案11】:我尝试使用下面的代码,它正在工作。该代码是不言自明的,如果您有任何问题,请告诉我。
<?php
class FlxZipArchive extends ZipArchive
public function addDir($location, $name)
$this->addEmptyDir($name);
$this->addDirDo($location, $name);
private function addDirDo($location, $name)
$name .= '/';
$location .= '/';
$dir = opendir ($location);
while ($file = readdir($dir))
if ($file == '.' || $file == '..') continue;
$do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
$this->$do($location . $file, $name . $file);
?>
<?php
$the_folder = '/path/to/folder/to/be/zipped';
$zip_file_name = '/path/to/zip/archive.zip';
$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';
?>
【讨论】:
优秀的解决方案。它也适用于 laravel 5.5。真的很喜欢。 (y) 很棒的代码!干净,简单,完美的工作! ;) 这对我来说似乎是最好的答复。如果它可以帮助某人:我只是在执行脚本之前添加了ini_set('memory_limit', '512M');
,最后添加了ini_restore('memory_limit');
。有必要避免在文件夹很重的情况下内存不足(这是一个大于 500MB 的文件夹)。
在我的环境(PHP 7.3,Debian)中创建了一个没有目录列表的 ZIP 存档(大的空文件)。我不得不更改以下行: $name .= '/';进入 $name = ($name == '.' ? '' : $name .'/');
这对我有用。感谢分享。干杯!【参考方案12】:
我对脚本做了一些小的改进。
<?php
$directory = "./";
//create zip object
$zip = new ZipArchive();
$zip_name = time().".zip";
$zip->open($zip_name, ZipArchive::CREATE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($directory),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file)
$path = $file->getRealPath();
//check file permission
if(fileperms($path)!="16895")
$zip->addFromString(basename($path), file_get_contents($path)) ;
echo "<span style='color:green;'>$path is added to zip file.<br /></span> " ;
else
echo"<span style='color:red;'>$path location could not be added to zip<br /></span>";
$zip->close();
?>
【讨论】:
这会压缩文件但目录列表消失了它不再有目录【参考方案13】:这是一个将整个文件夹及其内容压缩到一个 zip 文件中的功能,您可以像这样简单地使用它:
addzip ("path/folder/" , "/path2/folder.zip" );
功能:
// compress all files in the source directory to destination directory
function create_zip($files = array(), $dest = '', $overwrite = false)
if (file_exists($dest) && !$overwrite)
return false;
if (($files))
$zip = new ZipArchive();
if ($zip->open($dest, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true)
return false;
foreach ($files as $file)
$zip->addFile($file, $file);
$zip->close();
return file_exists($dest);
else
return false;
function addzip($source, $destination)
$files_to_zip = glob($source . '/*');
create_zip($files_to_zip, $destination);
echo "done";
【讨论】:
如何使用此脚本自动在备份中包含子文件夹? @Alireza【参考方案14】:这是一个用 PHP 制作 ZIP 的工作示例:
$zip = new ZipArchive();
$zip_name = time().".zip"; // Zip name
$zip->open($zip_name, ZipArchive::CREATE);
foreach ($files as $file)
echo $path = "uploadpdf/".$file;
if(file_exists($path))
$zip->addFromString(basename($path), file_get_contents($path));---This is main function
else
echo"file does not exist";
$zip->close();
【讨论】:
【参考方案15】:为什么不试试 EFS PhP-ZiP MultiVolume Script...我压缩并传输了数百个演出和数百万个文件...需要 ssh 才能有效地创建档案。
但我相信生成的文件可以直接从 php 与 exec 一起使用:
exec('zip -r backup-2013-03-30_0 . -i@backup-2013-03-30_0.txt');
我不知道它是否有效。我没试过……
“秘诀”是归档的执行时间不能超过PHP代码的执行时间。
【讨论】:
【参考方案16】:我假设这是在 zip 应用程序位于搜索路径中的服务器上运行的。应该适用于所有基于 unix 的服务器,我猜大多数基于 Windows 的服务器。
exec('zip -r archive.zip "My folder"');
unlink('My\ folder/index.html');
unlink('My\ folder/picture.jpg');
之后存档将驻留在 archive.zip 中。请记住,文件或文件夹名称中的空白是导致错误的常见原因,应尽可能避免。
【讨论】:
【参考方案17】:试试这个:
$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("target_folder/*") as $file)
$zip->addFile($file);
if ($file != 'target_folder/important.txt') unlink($file);
$zip->close();
这个不会递归压缩。
【讨论】:
它确实删除了My folder
中的一些文件,但我在My folder
文件夹中还有一个文件夹,这给了我一个错误:通过取消与My folder
中的文件夹的链接而拒绝权限
@Stupefy:改用if (!is_dir($file) && $file != 'target_folder...')
。或者如果您想递归压缩,请查看@kread answer,这是最有效的方式。
My folder
中的文件夹仍然没有被删除,但无论如何也没有更多错误。
我也忘了提到我没有创建 .zip 文件。
在调用$zip->close()
之前删除文件将不起作用。检查我的答案here以上是关于如何使用 PHP 压缩整个文件夹的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 php 压缩的情况下下载文件夹及其所有文件夹和文件