此類的原寫法:https://www.php.cn/php-weizijiaocheng-405771.html,但是有問題的
使用之前要注意的點:
1、PHP7.2不需要另外添加zip擴展,如果其它版本,要注意有沒有集成,沒有集成就要下載
2、實例化zip類的時候$zip->open打開文件的時候,要使用ZipArchive::CREATE。我使用了ZIPARCHIVE::OVERWRITE 模式,而官方解釋是“總是以一個新的壓縮包開始,此模式下如果已經存在則會被覆蓋。”。文檔只說了存在的時候會覆蓋,並沒說不存在會創建(到底會不會創建,用了才知道),那我的使用場景是默認一定不存在這樣一個文件的,那我把常亮改成CREATE試下,結果成功生成了zip文件。
3、路徑問題,要使用相對路徑,比如,./storage/uploads/XXXXX測試.zip,如果不行,自己根據使用的框架,自己測試換,這裏用的是TP5.1,所以完整目錄是在public下的storage文件夾
ZipFile類代碼,可直接使用
<?php
/**
* Class ZipFile
* 壓縮類
* @author connor
*/
class ZipFile
{
protected $zip;
protected $root;
protected $ignored_names;
public function __construct(){
$this->zip = new ZipArchive;
}
/**
* 解壓zip文件到指定文件夾
* @access public
* @param string $zipfile 壓縮文件路徑
* @param string $path 壓縮包解壓到的目標路徑
* @return booleam 解壓成功返回 true 否則返回 false
*/
public function unzip ($zipfile, $path) {
if ($this->zip->open($zipfile) === true) {
$file_tmp = @fopen($zipfile, "rb");
$bin = fread($file_tmp, 15); //只讀15字節 各個不同文件類型,頭信息不一樣。
fclose($file_tmp);
/* 只針對zip的壓縮包進行處理 */
if (true === $this->getTypeList($bin))
{
$result = $this->zip->extractTo($path);
$this->zip->close();
return $result;
}
else
{
return false;
}
}
return false;
}
/**
* 創建壓縮文件
* @access public
* @param string $zipfile 將要生成的壓縮文件路徑
* @param strng $folder 將要被壓縮的文件夾路徑
* @param array $ignored 要忽略的文件列表
* @return booleam 壓縮包生成成功返回true 否則返回 false
*/
public function zip ($zipfile, $folder, $ignored = null) {
$del_folder=$folder;
$this->ignored_names = is_array($ignored) ? $ignored : $ignored ? array($ignored) : array();
//這裏要注意ZipArchive的寫法,ZipArchive纔沒問題,前面new也是用ZipArchive,網上很多教程使用ZIPARCHIVE是錯誤的
//模式一定要用CREATE才能創建成功
$open_zip_bool=$this->zip->open($zipfile, ZipArchive::CREATE);
if ($open_zip_bool !== true) {
throw new Exception($this->message($open_zip_bool));
}
$folder = substr($folder, -1) == '/' ? substr($folder, 0, strlen($folder)-1) : $folder;
if(strstr($folder, '/')) {
$this->root = substr($folder, 0, strrpos($folder, '/')+1);
$folder = substr($folder, strrpos($folder, '/')+1);
}
$this->createZip($folder,null);
$zip_close=$this->zip->close();
$this->deleteFile($del_folder,true);//刪除已被打包壓縮的目錄
return $zip_close;
}
/**
* 遞歸添加文件到壓縮包
* @access private
* @param string $folder 添加到壓縮包的文件夾路徑
* @param string $parent 添加到壓縮包的文件夾上級路徑
* @return void
*/
private function createZip ($folder, $parent=null) {
$full_path = $this->root . $parent . $folder;
$zip_path = $parent . $folder;
$this->zip->addEmptyDir($zip_path);
$dir = new DirectoryIterator($full_path);
foreach($dir as $file) {
if(!$file->isDot()) {
$filename =$file->getFilename();//獲取文件夾下的文件
if(!in_array($filename, $this->ignored_names)) {
if($file->isDir()) {
$this->createZip($filename, $zip_path.'/');
}else {
$this->zip->addFile($full_path.'/'.$filename, $zip_path.'/'.$filename);
}
}
}
}
}
/**
* 讀取壓縮包文件與目錄列表
* @access public
* @param string $zipfile 壓縮包文件
* @return array 文件與目錄列表
*/
public function fileList($zipfile) {
$file_dir_list = array();
$file_list = array();
if ($this->zip->open($zipfile) == true) {
for ($i = 0; $i < $this->zip->numFiles; $i++) {
$numfiles = $this->zip->getNameIndex($i);
if (preg_match('/\/$/i', $numfiles))
{
$file_dir_list[] = $numfiles;
}
else
{
$file_list[] = $numfiles;
}
}
}
return array('files'=>$file_list, 'dirs'=>$file_dir_list);
}
/**
* 得到文件頭與文件類型映射表
* @author wengxianhu
* @date 2013-08-10
* @param $bin string 文件的二進制前一段字符
* @return boolean
*/
private function getTypeList ($bin)
{
$array = array(
array("504B0304", "zip")
);
foreach ($array as $v)
{
$blen = strlen(pack("H*", $v[0])); //得到文件頭標記字節數
$tbin = substr($bin, 0, intval($blen)); ///需要比較文件頭長度
if(strtolower($v[0]) == strtolower(array_shift(unpack("H*", $tbin))))
{
return true;
}
}
return false;
}
/**
+-----------------------------------------------------------------------------------------
* 刪除目錄及目錄下所有文件或刪除指定文件
+-----------------------------------------------------------------------------------------
* @param str $path 待刪除目錄路徑
* @param int $delDir 是否刪除目錄,1或true刪除目錄,0或false則只刪除文件保留目錄(包含子目錄)
+-----------------------------------------------------------------------------------------
* @return bool 返回刪除狀態
+-----------------------------------------------------------------------------------------
*/
public function deleteFile($path, $delDir = FALSE) {
if (is_array($path)) {
foreach ($path as $subPath)
deleteFile($subPath, $delDir);
}
if (is_dir($path)) {
$handle = opendir($path);
if ($handle) {
while (false !== ( $item = readdir($handle) )) {
if ($item != "." && $item != "..")
is_dir("$path/$item") ? deleteFile("$path/$item", $delDir) : unlink("$path/$item");
}
closedir($handle);
if ($delDir)
return rmdir($path);
}
} else {
if (file_exists($path)) {
return unlink($path);
} else {
return FALSE;
}
}
clearstatcache();
}
/**
* 對應打開文件失敗的錯誤
* @author connor
* @param $code
* @return string
*/
public function message($code)
{
switch ($code)
{
case 0:
return '沒有錯誤!';
case 1:
return '不支持多磁盤zip存檔';
case 2:
return '重命名臨時文件失敗';
case 3:
return '關閉zip存檔失敗';
case 4:
return '尋求錯誤';
case 5:
return '讀錯誤';
case 6:
return '寫錯誤';
case 7:
return 'CRC錯誤';
case 8:
return '包含zip存檔已關閉';
case 9:
return '文件不存在';
case 10:
return '文件已存在';
case 11:
return '無法打開文件';
case 12:
return '無法創建臨時文件';
case 13:
return 'Zlib錯誤';
case 14:
return 'Malloc失敗';
case 15:
return '參賽作品已被更改';
case 16:
return '不支持壓縮方法';
case 17:
return 'Premature EOF';
case 18:
return 'Invalid argument';
case 19:
return '不是zip存檔';
case 20:
return '內部錯誤';
case 21:
return 'Zip存檔不一致';
case 22:
return '無法刪除文件';
case 23:
return '條目已被刪除';
default:
return '出現未知錯誤('.intval($code).')';
}
}
}
文件上傳處理調用ZipFile類
//打包壓縮文件
$zip_class=new \ZipFile();
$zip_file='./'.Config::get('app.upload_file').$zip_file_folder.'/'.$zip_name.'.zip';//不存在則創建$zip_name.zip文件
$zip_class->zip($zip_file,'./'.Config::get('app.upload_file').$folder);