一、写在文章开始:
有时我们经常需要压缩下载多个文件,我这里主要采用在fastadmin框架中添加了一个表格自定义按钮,并为按钮绑定相应的事件来实现。
添加自定义按钮可以参考我的博客:fastadmin在表格列表中创建一个自定义按钮。
本代码可以实现文件的压缩下载,但对于大文件的下载会出现问题。后续在第二篇中会介绍另一种代码执行效率较高的代码。
需要注意的是:在点击按钮触发控制器对应的方法时不能采用ajax的方式,因为Ajax的返回值类型是json,text,html,xml类型,或者可以说ajax的接收类型只能是string字符串,不是流类型,所以无法实现文件下载。但用Ajax仍然可以获得文件的内容,该文件将被保留在内存中,无法将文件保存到磁盘。这是因为JavaScript无法和磁盘进行交互,否则这会是一个严重的安全问题,js无法调用到浏览器的下载处理机制和程序,会被浏览器阻塞。
二、完整代码及详细讲解
(1)获取到你需要下载的文件的链接集合,得到一个数组,我在这里的存储的路径格式为:/uploads/20230714/文件名.文件后缀(pptx/excel)。
(2)创建压缩包存放目录,这里使用的存放目录是存在了public/uploads/zip文件夹下创建了日期文件夹。mkdir()是创建目录的函数。
(3)实例化ZipArchive类,打开压缩包,循环文件添加到压缩包中。
在PHP中使用ZipArchive类可以从一个充满文件的文件夹中创建一个压缩包。这个类的实例创建了一个句柄来读取或写入压缩档案的文件。
(4)最后分片下载文件,使用的是fread()函数。
friad函数详解:
fread() 函数读取打开的文件。
函数会在到达指定长度或读到文件末尾(EOF)时(以先到者为准),停止运行。
该函数返回读取的字符串,如果失败则返回 FALSE。
总的代码如下:
public function download() { //获取需要下载哪个用户的资源 $id = input(); $row = db('files')->where('id', $id['ids'])->find(); $datas = db('files')->where('uid', $row['uid'])->select(); //获取到数据表中某用户对应的数据集合,表中存储的是文件路径 $arr = []; foreach ($datas as $key => $value) { array_push($arr, $value['path']); } // 压缩多个文件 //创建压缩包存放目录 $path = "./uploads/zip/" . date('Y-m-d'); if (!file_exists($path)) { mkdir(iconv("UTF-8", "GBK", $path), 0777, true); } $zip = new \ZipArchive(); $zip_name = $path . '/' . date('H-i-s') . '.zip'; $res = $zip->open($zip_name, \ZipArchive::CREATE); //打开压缩包 if ($res === true) { //循环文件添加到创建好的压缩包中 foreach ($arr as $file) { $path_url = '.' . $file; $handle = fopen($path_url, 'rb'); //打开文件目录对应的文件 $zip->addFile($path_url, basename($file)); //向压缩包中添加文件 fclose($handle); //关闭文件 } } $zip->close(); //关闭压缩包 if (!file_exists($zip_name)) { exit("无法找到文件"); //即使创建,仍有可能失败 } //如果报错,检查服务器上面的压缩文件是否可以正确的解压,如果可以你就可以加一个ob_clean试一下报错是否还存在 ob_clean(); header('Content-Type:application/zip;charset=utf-8'); header('Content-disposition:attachment;filename=' . basename($zip_name)); $filesize = filesize($zip_name); //要下载文件的大小 header('Content-length:' . $filesize); // readfile($zip_name); //可以直接使用readfile方法来进行下载 //分片下载 $read_buffer = 1024*1024;分片大小,这里设置为1MB $sum_buffer = 0; $f = fopen($zip_name, 'rb'); if ($f === false) exit("文件打开失败"); //一般在文件操作,中经常使用feof()判断文件是否结束。 while(!feof($f) && $sum_buffer<$filesize) { echo fread($f, $read_buffer); $sum_buffer += $read_buffer; } fclose($handle); exit; }
欢迎留言评论进行指导,我是一个虚心学习的程序员。