压缩 PHP 中文件夹的内容
Zipping the contents of a folders in PHP
在将此 post 标记为重复之前,请注意我已经在 SO 上搜索了答案,并且到目前为止我发现的答案(如下所列)并不完全符合我的要求一直在找
- How to [recursively] Zip a directory in PHP?
- using zipArchive addFile() will not add image to zip
- ZipArchive - addFile won't work
这些只是我看过的一部分。
我的问题是:我不能使用 addFromString,我必须 使用 addFile,这是任务的要求。
我已经尝试了几种方法,这是我当前的迭代:
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();
}
当我尝试打开生成的文件时,我被告知 "Windows cannot open the folder. The Compressed(zipped) Folder '' is invalid."
我已经成功地使用 addFromString 完成了任务,如下所示:
$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();
}
}
}
以上内容主要是直接从我在某处看到的一些示例代码中复制而来。如果有人能给我指出一个好的方向,我将不胜感激!
***** 更新 *****
我在结尾处添加了一个 if,如下所示:
if (!$zip->close()) {
echo "failed writing zip to archive";
}
消息被回显,很明显问题就在那里。我还检查以确保 $zip->open()
正常工作,并且我确认它可以正常打开它。
看看这个解决方案,更清楚:
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 . '/'));
}
else if (is_file($file) === true)
{
$zip->addFile($file, str_replace($source . '/', '', $file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFile($file, str_replace($source . '/', '', $file));
}
return $zip->close();
}
并像这样使用它:
Zip('/folder/to/compress/', './compressed.zip');
用 addFromString
检查 original post
终于设法使用 addFile
实现了某些功能。
我创建了一个包含 3 个功能的助手 class:一个用于列出目录中的所有文件,一个用于压缩所有这些文件,还有一个用于下载压缩文件:
<?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;
}
}
?>
我是这样称呼这个 class 的函数的:
$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);
在将此 post 标记为重复之前,请注意我已经在 SO 上搜索了答案,并且到目前为止我发现的答案(如下所列)并不完全符合我的要求一直在找
- How to [recursively] Zip a directory in PHP?
- using zipArchive addFile() will not add image to zip
- ZipArchive - addFile won't work
这些只是我看过的一部分。
我的问题是:我不能使用 addFromString,我必须 使用 addFile,这是任务的要求。
我已经尝试了几种方法,这是我当前的迭代:
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();
}
当我尝试打开生成的文件时,我被告知 "Windows cannot open the folder. The Compressed(zipped) Folder '' is invalid."
我已经成功地使用 addFromString 完成了任务,如下所示:
$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();
}
}
}
以上内容主要是直接从我在某处看到的一些示例代码中复制而来。如果有人能给我指出一个好的方向,我将不胜感激!
***** 更新 ***** 我在结尾处添加了一个 if,如下所示:
if (!$zip->close()) {
echo "failed writing zip to archive";
}
消息被回显,很明显问题就在那里。我还检查以确保 $zip->open()
正常工作,并且我确认它可以正常打开它。
看看这个解决方案,更清楚:
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 . '/'));
}
else if (is_file($file) === true)
{
$zip->addFile($file, str_replace($source . '/', '', $file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFile($file, str_replace($source . '/', '', $file));
}
return $zip->close();
}
并像这样使用它:
Zip('/folder/to/compress/', './compressed.zip');
用 addFromString
检查 original post终于设法使用 addFile
实现了某些功能。
我创建了一个包含 3 个功能的助手 class:一个用于列出目录中的所有文件,一个用于压缩所有这些文件,还有一个用于下载压缩文件:
<?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;
}
}
?>
我是这样称呼这个 class 的函数的:
$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);