PHP操作ZIP之ZipArchive类以及如何避免生成压缩文件带有目录层级的问题

news2024/11/22 21:14:10

常用的方法

php ZipArchive可以说是php自带的一个函数了,他可对对文件进行压缩与解压缩处理,但是使用此类之前我们必须在php.ini中把extension=php_zip.dll前面的分号有没有去掉,然后再重启Apache这样才能使用这个类库。

ziparchive 可选参数,更多的使用例子,参考PHP - Manual: ZipArchive - 互联网笔记

ZipArchive::addEmptyDir

添加一个新的文件目录

<?php
$zip = new ZipArchive;
if ($zip->open('test.zip') === TRUE) {
    if($zip->addEmptyDir('newDirectory')) {
        echo 'Created a new root directory';
    } else {
        echo 'Could not create the directory';
    }
    $zip->close();
} else {
    echo 'failed';
}
?>

ZipArchive::addFile

将文件添加到指定zip压缩包中。

ZipArchive::addFromString

添加的文件同时将内容添加进去

ZipArchive::close

关闭ziparchive

ZipArchive::extractTo

将压缩包解压

ZipArchive::open

打开一个zip压缩包

ZipArchive::getStatusString

返回压缩时的状态内容,包括错误信息,压缩信息等等

ZipArchive::deleteIndex

删除压缩包中的某一个文件,如:deleteIndex(0)删除第一个文件

ZipArchive::deleteName

删除压缩包中的某一个文件名称,同时也将文件删除。

ZipArchive::open

<?php
$zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if ($res === TRUE) {
    $zip->addFromString('test.txt', 'file content goes here');
    $zip->addFile('data.txt', 'entryname.txt');
    $zip->close();
    echo 'ok';
} else {
    echo 'failed';
}
?>

<?php
$name = tempnam(sys_get_temp_dir(), "FOO");
$zip = new ZipArchive;
$res = $zip->open($name, ZipArchive::OVERWRITE); /* truncate as empty file is not valid */
if ($res === TRUE) {
    $zip->addFile('data.txt', 'entryname.txt');
    $zip->close();
    echo 'ok';
} else {
    echo 'failed';
}
?>

基本使用例

解压缩zip文件

注意,解压的文件夹中不要有中文!会引起乱码!

$zip = new ZipArchive;//新建一个ZipArchive的对象
/*
通过ZipArchive的对象处理zip文件
$zip->open这个方法的参数表示处理的zip文件名。
如果对zip文件对象操作成功,$zip->open这个方法会返回TRUE
*/

if ($zip->open('test.zip'))
{
    $zip->extractTo('images');//假设解压缩到在当前路径下images文件夹的子文件夹php
    $zip->close();//关闭处理的zip文件
}

文件追加内容添加到zip文件

zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if ($res) {
    $zip->addFromString('test.txt', 'file content goes here');
    $zip->close();
    echo 'ok';
} else {
  echo 'failed';
}

建议:$zip->open 使用try-catch去捕捉

try {
   $zipResult = $zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
    //关闭处理的zip文件
    $zip->close();
}  catch (Exception $e) {
    exit( $e->getMessage());
}

将服务器上的文件夹打包成zip文件

function addFileToZip($path, $zip) {

    $handler = opendir($path); //打开当前文件夹由$path指定。
    
    /*
    循环的读取文件夹下的所有文件和文件夹
    其中$filename = readdir($handler)是每次循环的时候将读取的文件名赋值给$filename,
    为了不陷于死循环,所以还要让$filename !== false。
    一定要用!==,因为如果某个文件名如果叫'0',或者某些被系统认为是代表false,用!=就会停止循环
    */
    
    while (($filename = readdir($handler)) !== false) {
        //文件夹文件名字为'.'和‘..’,不要对他们进行操作
        if ($filename != "." && $filename != "..") {
            $filePath = "{$path}/{$filename}";
            // 如果读取的某个对象是文件夹,则递归
            if (is_dir($filePath)) {
                addFileToZip($filePath, $zip);
            } else { 
                var_dump($filePath);
                // 将文件加入zip对象 传入第二个参数是避免出现目录层级的问题
                $zip->addFile($filePath, pathinfo($filePath, PATHINFO_BASENAME));
            }
        }
    }
    @closedir($path);
}
$STATICS_PATH = 'd:/xampp/htdocs/xin-card';
$templatePath = '2023/03/0d9cf19188485dc70e21a1aae4ffad8d';
// 要下载文件的最终目录
$finalPath = "{$STATICS_PATH}/templates/{$templatePath}";

if(!file_exists($finalPath)) {
    exit('路径不存在');
}

$zip = new ZipArchive();
$zipName = time() . '.zip';
// d:/xampp/htdocs/xin-card/zip/187823213.zip
$zipPath = "{$STATICS_PATH}/zip/{$zipName}";
try {
    $zipResult = $zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
    //调用方法,对要打包的根目录进行操作,并将ZipArchive的对象传递给方法
    addFileToZip($finalPath, $zip); 
    //关闭处理的zip文件
    $zip->close();
}  catch (Exception $e) {
    exit( $e->getMessage());
}

解决生成压缩文件带有目录层级的问题

比如上面的addFileToZip方法,我一开始是这么写的:

if (is_dir($filePath)) {
       addFileToZip($filePath, $zip);
} else { 
       $zip->addFile($filePath);
}

这样写最终导致的后果就是生成的压缩文件,里面带有目录层级!

像这样:D:\xampp\htdocs\xin-card\statics\templates-packages\1679986315\D_\xampp\htdocs\xin-card\statics\templates-packages\2023\03\0d9cf19188485dc70e21a1aae4ffad8d 

实际上只有最后的文件夹才是我想要的!

如果你使用php ZipArchive  addFile 方法把多个文件压缩在1个目录时会产生一个问题,我们只想要在当前目录把所有文件放在一起,结果他安装每个文件的所在目录在当前目录创建一遍,解决方式如下:

$allAttachment = [
    '1.png',   
    '2.png',   
    '3.png',   
    '4.png',    
];

// 循环保存文件到Zip中
foreach ($allAttachment as $attachmentItem) {
    $rootpath = 'd:/xampp/htdocs/xin-cards/';
    if ($attachmentItem) {
        $attachmentItem = "$rootpath/$attachmentItem";
        // 添加文件
        $zip->addFile($attachmentItem);
        // 对添加的文件重新命名,避免出现目录问题
        $zip->renameName($attachmentItem, basename($attachmentItem));
    }
}

// 关闭
$zip->close();
如果不能解决您的问题,可以尝试如下方式

// 添加文件
$zip->addFile($attachmentItem, pathinfo($attachmentItem, PATHINFO_BASENAME));

浏览器下载并删除压缩文件

以下是打包服务器上某个文件夹中所有文件,并下载的然后再删除压缩文件的全部代码:

<?php
$STATICS_PATH = PATH['statics'];
$templatePath = '2023/03/0d9cf19188485dc70e21a1aae4ffad8d';
$finalPath = "{$STATICS_PATH}/templates-packages/{$templatePath}";
if(!file_exists($finalPath)) {
    exit('路径不存在');
}

function addFileToZip($path, $zip) {

    $handler = opendir($path); //打开当前文件夹由$path指定。
    
    /*
    循环的读取文件夹下的所有文件和文件夹
    其中$filename = readdir($handler)是每次循环的时候将读取的文件名赋值给$filename,
    为了不陷于死循环,所以还要让$filename !== false。
    一定要用!==,因为如果某个文件名如果叫'0',或者某些被系统认为是代表false,用!=就会停止循环
    */
    
    while (($filename = readdir($handler)) !== false) {
        //文件夹文件名字为'.'和‘..’,不要对他们进行操作
        if ($filename != "." && $filename != "..") {
            $filePath = "{$path}/{$filename}";
            // 如果读取的某个对象是文件夹,则递归
            if (is_dir($filePath)) {
                addFileToZip($filePath, $zip);
            } else { 
                // 将文件加入zip对象 传入第二个参数是避免出现目录层级的问题
                $zip->addFile($filePath, pathinfo($filePath, PATHINFO_BASENAME));
            }
        }
    }
    @closedir($path);
}

$zip = new ZipArchive();
$zipName = time() . '.zip';
$zipPath = "{$STATICS_PATH}/templates-packages/{$zipName}";
try {
    $zipResult = $zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
    //调用方法,对要打包的根目录进行操作,并将ZipArchive的对象传递给方法
    addFileToZip($finalPath, $zip); 
    //关闭处理的zip文件
    $zip->close();

    //下载文件
    $file = fopen($zipPath, "r");
    //返回的文件类型
    Header("Content-type: application/octet-stream");
    //按照字节大小返回
    Header("Accept-Ranges: bytes");
    //返回文件的大小
    Header("Accept-Length: " . filesize($zipPath));
    //这里设置客户端的弹出对话框显示的文件名
    Header("Content-Disposition: attachment; filename=" . $zipName);
    //一次性将数据传输给客户端
    //echo fread($file, filesize($filePath));
    //一次只传输1024个字节的数据给客户端
    //向客户端回送数据
    $buffer = 1024;//
    //判断文件是否读完
    while (!feof($file)) {
        //将文件读入内存
        $file_data = fread($file, $buffer);
        //每次向客户端回送1024个字节的数据
        echo $file_data;
 
    }
    //将生成的zip文件在服务器端删除,只需要客户端下载就行了
    @unlink($zipPath);

}  catch (Exception $e) {
    exit( $e->getMessage());
}

相关资料

解决phpZipArchive生成压缩文件带有目录层级的问题【阿里开发者社区】

解决phpZipArchive生成压缩文件带有目录层级的问题

php开启ziparchivephpZipArchive类使用实例详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1305358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决:Component name “index“ should always be multi-word

原因 要求组件名称以驼峰格式命名&#xff0c;自定义组件名称应该由多单纯组成&#xff0c;防止和html标签冲突&#xff0c;所以index.vue 会报错 解决 1、按照规则驼峰格式&#xff0c;如&#xff1a;appIndex.vue 2、若有.eslintrc.js文件&#xff0c;并在规则中(rules)关…

排序算法4:【快速排序】、查看每趟归并后的结果,定义一个全局变量,用来计数作为总趟数

一、快速排序——时间复杂度&#xff1a;、 最坏的情况 1、原理&#xff1a; 快速排序是通过多次比较和交换来实现排序&#xff0c;首先&#xff0c;先从数列中&#xff0c;任意选择一个数作为基准&#xff08;或叫分界值&#xff09;&#xff0c;比如&#xff0c;第一个数&a…

MySQL的事务以及springboot中如何使用事务

事务的四大特性&#xff1a; 概念&#xff1a; 事务 是一组操作的集合&#xff0c;它是不可分割的工作单元。事务会把所有操作作为一个整体&#xff0c;一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 注意&#xff1a; 默认MySQ…

图解transformer中的自注意力机制(备忘)

注意力机制 在整个注意力过程中&#xff0c;模型会学习了三个权重:查询、键和值。查询、键和值的思想来源于信息检索系统。所以我们先理解数据库查询的思想。 假设有一个数据库&#xff0c;里面有所有一些作家和他们的书籍信息。现在我想读一些Rabindranath写的书&#xff1a…

网络编程----select 模型总结

为什么要使用select模型&#xff1f; 答&#xff1a;解决基本C/S模型中&#xff0c;accept()、recv()、send()阻塞的问题 select模型与C/S模型的不同点 C/S模型中accept()会阻塞一直傻等socket来链接select模型只解决accept()傻等的问题&#xff0c;不解决recv(),send()执行…

Android View闪烁动画AlphaAnimation,Kotlin

Android View闪烁动画AlphaAnimation&#xff0c;Kotlin private fun flickerAnimation(view: View?) {val animation: Animation AlphaAnimation(1f, 0f) //不透明到透明。animation.duration 500 // 1次过程时长。animation.interpolator LinearInterpolator() // 线性速…

一天搞定jmeter入门到入职全套教程之Jmeter分布式测试

随着并发量的增大&#xff0c;一台机器就不能满足需求了&#xff0c;所以我们采用分布式&#xff08;Master-Slaver&#xff09;的方案去执行高并发的测试 注意事项&#xff1a; Master机器一般我们不执测试&#xff0c;所以可以拿一台配置差些的机器&#xff0c;主要用来采集…

YOLOv8改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv8(超级轻量化精度更高)

一、本文介绍 本文给大家带来利用RT-DETR模型主干HGNet去替换YOLOv8的主干&#xff0c;RT-DETR是今年由百度推出的第一款实时的ViT模型&#xff0c;其在实时检测的领域上号称是打败了YOLO系列&#xff0c;其利用两个主干一个是HGNet一个是ResNet&#xff0c;其中HGNet就是我们…

养牛场北斗综合管理系统解决方案

1.系统架构 随着我国北斗卫星导航定位系统的快速发展和定位精度的持续不断提高&#xff0c;在牛身上穿戴定位终端后可以实现对牛的位置和温度的测量&#xff0c;在蜂窝网络正常的情况下&#xff0c;定位和温度数据通过蜂窝网络通信方式回传到监控云平台&#xff0c;在蜂窝网络缺…

使用docker编排容器

使用Dockerfile构建一个自定义的nginx 首先用docker拉一个nginx镜像 docker pull nginx拉取完成后&#xff0c;编辑一个Dockerfile文件 vim Dockerfile命令如下所示,FROM 后面跟的你的基础镜像&#xff0c;而run则是表示你构建镜像时需要执行的指令&#xff0c;下面的指令意…

mysql的ON DELETE CASCADE 和ON DELETE RESTRICT区别

​​ON DELETE CASCADE​​​ 和 ​​ON DELETE RESTRICT​​ 是 MySQL 中两种不同的外键约束级联操作。它们之间的主要区别在于当主表中的记录被删除时,子表中相关记录的处理方式。 ON DELETE CASCADE:当在主表中删除一条记录时,所有与之相关的子表中的匹配记录也会被自动删…

Android studio:打开应用程序闪退的问题2.0

目录 找到问题分析问题解决办法 找到问题 老生常谈&#xff0c;可能这东西真的很常见吧&#xff0c;在之前那篇文章中 linkhttp://t.csdnimg.cn/UJQNb 已经谈到了关于打开Androidstuidio开发的软件后明明没有报错却无法运行&#xff08;具体表现为应用程序闪退的问题&#xff…

MySQL之创建时间类型的字段表

mysql之创建时间类型的字段表 CREATE TABLE tab(birthday DATE, -- 生日job_time DATETIME, -- 记录年月日时分秒login_time TIMESTAMP -- 时间戳NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP )解释&#xff1a; NOT NULL DEFAULT &#xff1a;默认不为空…

快速幂(C语言)

前言 快速幂算法一般用于高次幂取模的题目中&#xff0c;比如求3的10000次方对7取模。这时候有些同学会说&#xff1a;这还不简单&#xff1f;我直接调用pow函数然后对结果%7不得了么&#xff1f;可是3的10000次方这么庞大的数字&#xff0c;真的能储存在计算机里么&#xff1f…

Logstash输入Kafka输出Es配置

Logstash介绍 Logstash是一个开源的数据收集引擎&#xff0c;具有实时管道功能。它可以从各种数据源中动态地统一和标准化数据&#xff0c;并将其发送到你选择的目的地。Logstash的早期目标主要是用于收集日志&#xff0c;但现在的功能已经远远超出这个范围。任何事件类型都可…

技术资讯:VSCode大更新,这两个功能终于有了

大家好&#xff0c;我是大澈&#xff01; 本文约1200字&#xff0c;整篇阅读大约需要2分钟。 感谢关注微信公众号&#xff1a;“程序员大澈”&#xff0c;然后免费加入问答群&#xff0c;从此让解决问题的你不再孤单&#xff01; 1. 资讯速览 就在前阵子&#xff0c;前端人都…

【Android嵌入式开发及实训课程实验】【项目1】 图形界面——计算器项目

【项目1】 图形界面——计算器项目 需求分析界面设计实施1、创建项目2、 界面实现实现代码1.activity_main.xml2.Java代码 - MainActivity.java 3、运行测试 注意点结束~ 需求分析 开发一个简单的计算器项目&#xff0c;该程序只能进行加减乘除运算。要求界面美观&#xff0c;…

【Java 基础】27 XML 解析

文章目录 1.SAX 解析器1&#xff09;什么是 SAX2&#xff09;SAX 工作流程初始化实现事件处理类解析 3&#xff09;示例代码 2.DOM 解析器1&#xff09;什么是 DOM2&#xff09;DOM 工作流程初始化解析 XML 文档操作 DOM 树 3&#xff09;示例代码 总结 在项目开发中&#xff0…

电脑ffmpeg.dll丢失如何修复?3个详细修复的教程分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“ffmpeg.dll丢失”。ffmpeg.dll是FFmpeg多媒体框架中的一个重要组件&#xff0c;它负责处理音频和视频的编解码。当这个文件丢失或损坏时&#xff0c;可能会导致一些应用程序无法正常运行。…

iframe 与主应用页面之间如何互相通信传递数据

背景 当我们的Web页面需要复用现有网站的页面时&#xff0c;我们通常会考虑代码层面的抽离引用&#xff0c;但是对于一些过于复杂的页面&#xff0c;通过 iframe 嵌套现有的网站页面也是一种不错的方式&#xff0c;。目前我就职的项目组就有多个业务利用 iframe 完成业务的复用…