PHP ZipArchive 大文件分片下载压缩 支持断点续传

阅读: 评论:0

PHP ZipArchive 大文件分片下载压缩 支持断点续传

PHP ZipArchive 大文件分片下载压缩 支持断点续传

安装扩展

压缩使用的是 PHP扩展 ZipArchive,确保当前的PHP版本已经安装了这个拓展类;

<?php
// 使用phpinfo()查看有没有zip扩展
echo phpinfo();
?>

有了这个则是已经有这个扩展了

  • 没有的下载对应版本的扩展包,
  • 下载地址
  • 我的版本是7.4.3的所以我下载的是7.4
    • 把解压的php_zip.dll文件放到php-5.6.27-nts/ext目录
    • 在php.ini添加以下配置:extension=php_zip.dll ; 打开zlib.output_compression=On off改成On
    • 重启Apache

实现原理

  1. 创建临时目录:

    • 使用mkdir()创建一个临时目录,并设置权限为777。
    • 使用uniqid()生成一个唯一的ID,将其与临时目录路径拼接形成唯一的目录名。
  2. 压缩文件操作:

    • 使用ZipArchive类创建一个压缩文件对象。
    • 使用open方法打开压缩文件,并指定文件名和创建模式为ZipArchive::CREATE
      • 使用open方法的时候,第二个参数是可选的,用来指定对打开的zip文件的处理方式,共有四种情况
        • ZIPARCHIVE::OVERWRITE总是创建一个新的文件,如果指定的zip文件存在,则会覆盖掉
        • ZIPARCHIVE::CREATE 如果指定的zip文件不存在,则新建一个
        • ZIPARCHIVE::EXCL 如果指定的zip文件存在,则会报错
        • ZIPARCHIVE::CHECKCONS
    • 使用addFile方法将文件添加到压缩文件中,使用basename($file_path)作为文件在压缩文件中的名称。
  3. 文件分块传输:

    • 定义了文件分块传输的相关参数,其中$chunkSize表示每个文件块的大小。
    • 通过$_SERVER['HTTP_RANGE']获取请求头中的HTTP_RANGE值,判断是否支持文件分块传输。
    • 使用正则表达式匹配请求头中的bytes=(d+)格式,提取起始位置$startPos
  4. 读取文件内容:

    • 使用fopen打开文件,模式为二进制读取。
    • 使用fseek设置文件指针位置为起始位置$startPos
    • 使用fread从文件中读取指定大小的内容,将文件内容读入内存。
  5. 压缩文件下载:

    • 使用header函数设置响应头信息,包括文件类型、文件名和文件大小。

    • 使用filesize获取压缩文件的大小,并设置响应头中的文件大小。

    • 如果请求头中存在HTTP_RANGE值,则进行分块传输:

      • 对请求头中的HTTP_RANGE进行处理,获取起始位置和结束位置。
      • 使用fopen打开压缩文件,并设置文件指针位置为起始位置。
      • 使用fpassthru将文件内容直接发送给浏览器进行下载或输出。
    • 如果请求头中不存在HTTP_RANGE值,则直接使用readfile函数将压缩文件内容输出给浏览器。

  6. 删除临时文件和目录:

    • 使用glob函数获取临时目录下的所有文件路径,使用通配符*匹配所有文件。
    • 使用array_map函数将unlink函数应用到每个文件路径上,即删除对应的文件。
    • 使用rmdir函数删除临时目录。

源码

<?php
class File extends Backend
{/*** @description: 压缩下载* @param {*} $params['uid']:用户ID,用于查询数据库中的文件列表。* @param {*} $temp_dir:临时目录路径。* @param {*} $username:用户名。* @param {*} $zip_name:压缩文件名。* @param {*} $chunkSize:每次读取文件的大小。* @param {*} $range:请求头中的 HTTP_RANGE 值。* @param {*} $startPos:传输文件的起始位置。* @param {*} $files:用户的文件列表。* @param {*} $file_path:文件路径。* @param {*} $fp:文件资源。* @param {*} $chunk:每次读取的文件内容的缓冲区。* @param {*} $contentLength:压缩文件* @return {*}*/public function export(){// TODO 1.创建一个临时目录,并检查是否已存在。如果不存在,则创建该目录$temp_dir = './temp/' . '-' . uniqid();if (!is_dir($temp_dir))  mkdir($temp_dir, 0777, true);// TODO 2.创建一个 ZipArchive 对象,并指定压缩文件名。$zip = new ZipArchive();$zip_name = $temp_dir . '/' . $username . '.zip';if ($zip->open($zip_name, ZipArchive::CREATE) !== true) exit("文件创建失败!");// TODO 3.定义文件分块传输的相关参数$chunkSize = 1024 * 1024 * 1;  // 定义文件分块传输的相关参数。$range = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : '';   //  获取请求头中的 HTTP_RANGE 值,如果请求头中不存在 HTTP_RANGE 值,则将其设为空字符串// TODO 4.定义传输文件的起始位置$startPos = 0;// preg_match(),用于执行正则表达式的匹配操作。它接受一个正则表达式模式和一个要搜索的字符串作为参数,并尝试在字符串中找到与模式匹配的部分。如果匹配成功,则返回 1,否则返回 0。if (preg_match('/bytes=(d+)/', $range, $matches))  $startPos = intval($matches[1]);   //  如果请求头中的 HTTP_RANGE 值匹配了 bytes=(d+) 的正则表达式,则将该值的整数部分赋值给 $startPos 变量。// TODO 5.遍历文件列表foreach ($files as $file) {$file_path = '.' . $file['file_url'];   //构建文件路径,添加文件路径前缀 '.' 并取出 $file['file_url'] 值。$fp = fopen($file_path, 'rb');  // 打开文件,并将资源赋值给 $fp 变量。if ($fp === false) exit("文件打开失败: $file_path");fseek($fp, $startPos);  //设置文件指针位置为起始位置 $startPos(0)// TODO 6.通过文件路径打开文件,读取文件内容,并将每次读取的数据添加到压缩文件中。while (!feof($fp)) {  // 判断文件是否读完$chunk = fread($fp, $chunkSize);  // 从文件中读取指定大小的内容,成功读取内容时返回读取的数据,将文件读入内存if ($chunk === false) exit("文件读取失败: $file_path");$zip->addFile($file_path, basename($file_path));  // 将文件内容添加到压缩文件中,使用 basename($file_path) 作为文件在压缩文件中的名称。成功添加文件时返回 true// $zip->addFile($file_path, basename($file_path));  //  addFile 函数会一次性将整个文件加载到内存中,然后添加到 ZIP 压缩文件中。// $zip->addFromString(basename($file_path), $chunk);  // 将文件的每个数据块逐个添加到 ZIP 压缩文件中。}fclose($fp);  // 关闭文件}// TODO 7.关闭压缩文件,并设置响应头信息,包括文件类型、文件名和文件大小。$zip->close();header('Content-Type: application/zip');  //设置响应头信息为 ZIP 文件类型header('Content-Disposition: attachment; filename="' . $username . '_all.zip"');  // 这里对客户端的弹出对话框, 设置响应头中的文件名为 $XXX_all.zipheader('Content-Length: ' . filesize($zip_name));  // 设置响应头中的文件大小为压缩文件的大小$contentLength = filesize($zip_name);  //获取压缩文件的大小,返回值是文件的大小(字节数)// TODO 8.如果请求头中存在 HTTP_RANGE 值,则进行分块传输if ($range != '') {// TODO 9.首先对请求头中的 HTTP_RANGE 进行处理,获取起始位置和结束位置$range = preg_replace('/[s|,].*/', '', $range);  //preg_replace() 用于执行正则表达式的替换操作。它接受一个正则表达式模式、一个替换字符串和一个要进行替换的字符串作为参数,并尝试在字符串中找到与模式匹配的部分并进行替换$ranges = explode('-', $range);$startPos = intval($ranges[0]);$endPos = $contentLength - 1;if (isset($ranges[1]) && is_numeric($ranges[1]) && $ranges[1] < $endPos) {$endPos = intval($ranges[1]);}header('HTTP/1.1 206 Partial Content');  //设置响应头状态为 206 Partial Content,表示只返回部分内容header("Content-Range: bytes $startPos-$endPos/$contentLength");   // 设置响应头中的 Content-Range,指定返回的内容范围$fp = fopen($zip_name, 'rb');  //打开压缩文件fseek($fp, $startPos); //设置文件指针位置为起始位置fpassthru($fp); // 直接将文件内容发送给浏览器进行下载或输出ob_flush(); // 刷新输出缓冲区,将内容发送到浏览器fclose($fp);  //关闭文件} else {readfile($zip_name);  //直接输出响应}// TODO 10.删除临时文件和目录// array_map('unlink', glob($temp_dir . '/*'))的作用是先使用glob函数获取指定目录下的所有文件路径(使用通配符*获取目录下所有文件的路径)并返回一个数组,然后使用array_map函数将unlink函数应用到该数组的每个元素上,即删除对应的文件。//  array_map('unlink', glob($temp_dir . '/*'));unlink($zip_name);rmdir($temp_dir);exit;}

PHP 操作方法

fopen( file,'rb')
  • 用于打开文件或 URL,并返回一个文件资源。它接受两个参数:文件名或 URL,以及打开文件的模式(读取、写入、追加等)。
fclose(要关闭的文件资源)
  • 用于关闭先前由 fopen() 打开的文件资源。
feof(要检测的文件资源)
  • 用于检测文件指针是否已到达文件末尾。
  • 在循环中使用 feof() 可以判断文件是否已被完全读取。
fread(文件资源,要读取的字节数)
  • 用于从文件中读取指定数量的字节。
  • 使用 fread() 可以将文件内容读入内存。
fseek(文件资源,偏移量,偏移起始位置)
  • 用于设置文件指针的位置
  • 可以在文件中移动文件指针,以便从指定位置开始读取文件内容。
fpassthru(要传输的文件资源)
  • 用于直接将文件内容传输给浏览器进行下载或输出。
  • 避免将整个文件内容加载到内存中,特别适用于传输大文件或二进制文件。
filesize(要获取大小的文件名)
  • 用于获取文件的大小(字节数)。
ob_flush()
  • 用于刷新输出缓冲区,并将缓冲区的内容发送到浏览器。它没有参数。
  • 在输出被缓冲时,使用 ob_flush() 可以确保缓冲区的内容立即发送到客户端。
flush()
  • 它将输出缓冲区的内容立即发送给客户端,但仅刷新当前脚本的输出缓冲区。
readfile(要输出的文件名)
  • 用于直接将文件内容输出给浏览器。适用于简单的文件下载或输出。
basename(要提取文件名的路径)
  • 可以从文件路径中提取文件名,用于设置压缩文件中的文件名。
preg_match(正则表达式模式,要搜索的字符串)
  • 使用 preg_match() 可以判断一个字符串是否与指定的正则表达式模式匹配,从而进行相应的操作。
  • glob(要搜索的文件模式)
    • 可以获取符合指定模式的文件路径列表,用于遍历文件或进行文件操作。
  • uniqid(前缀,更改器)
    • 生成一个基于当前时间的唯一字符串,可用于创建临时文件、目录或其他需要唯一标识符的场景。

header 请求头

header('HTTP/1.1 206 Partial Content'):
  • 这个请求头用于指示部分内容的响应,即只返回请求范围内的内容,而不是完整的文件内容。
  • HTTP状态码206表示部分内容,用于支持文件分块传输或断点续传。
  • 当客户端请求指定范围的文件内容时,服务器可以使用此响应头来通知客户端,只返回请求的部分内容。
header("Content-Range: bytes):
  • Content-Range 请求头用于指定响应中返回的内容范围。
  • 当使用分块传输或断点续传时,Content-Range 可以指定具体的字节范围。
  • 例如,Content-Range: bytes 0-1023/2048 表示返回从0字节到1023字节的内容,总共有2048字节。
header('Content-Type: application/zip'):
  • Content-Type 请求头用于指定响应内容的媒体类型。
  • 在这种情况下,application/zip 表示响应的内容是一个ZIP压缩文件。
  • 当客户端接收到响应时,根据 Content-Type 来确定如何处理和显示响应的内容。
  • Content-type类型:
    • text/html: 用于指示响应内容是 HTML 格式的文本。
    • text/plain: 用于指示响应内容是纯文本格式,不包含任何样式或标记。
    • application/json: 用于指示响应内容是 JSON 格式的数据。JSON 是一种常用的数据交换格式。
    • application/xml: 用于指示响应内容是 XML 格式的数据。XML 是一种用于表示结构化数据的标记语言。
    • application/pdf: 用于指示响应内容是 PDF 格式的文件。PDF 是一种用于跨平台文档显示的格式。
    • image/jpeg: 用于指示响应内容是 JPEG 图像格式。
    • image/png: 用于指示响应内容是 PNG 图像格式
    • audio/mpeg: 用于指示响应内容是 MP3 音频格式
    • video/mp4: 用于指示响应内容是 MP4 视频格式。
    • multipart/form-data: 用于指示响应内容是表单数据,通常用于文件上传。
header('Content-Disposition: attachment; filename="' . $username . '_all.zip"'):
  • Content-Disposition 请求头用于指示客户端如何处理响应的内容。
  • 在这里,attachment 表示客户端应将响应内容作为附件下载,而不是在浏览器中直接打开。
  • filename="' . $username . '_all.zip" 部分用于指定下载的文件名,将变量 $username 加入文件名以个性化命名。
header('Content-Length: ' . filesize($zip_name)):
  • Content-Length 请求头用于指定响应内容的长度(字节数)。
  • 在这种情况下,filesize($zip_name) 用于获取压缩文件的大小,并将文件大小作为响应的长度进行设置。
  • 客户端在接收到响应时,可以使用 Content-Length 来知道响应的总大小,从而进行进度显示或其他处理。

ZipArchive方法:

  • ZipArchive::addEmptyDir — Add a new directory
  • ZipArchive::addFile — Adds a file to a ZIP archive from the given path
  • ZipArchive::addFromString — Add a file to a ZIP archive using its contents
  • ZipArchive::addGlob — Add files from a directory by glob pattern
  • ZipArchive::addPattern — Add files from a directory by PCRE pattern
  • ZipArchive::close — Close the active archive (opened or newly created)
  • ZipArchive::deleteIndex — delete an entry in the archive using its index
  • ZipArchive::deleteName — delete an entry in the archive using its name
  • ZipArchive::extractTo — Extract the archive contents
  • ZipArchive::getArchiveComment — Returns the Zip archive comment
  • ZipArchive::getCommentIndex — Returns the comment of an entry using the entry index
  • ZipArchive::getCommentName — Returns the comment of an entry using the entry name
  • ZipArchive::getExternalAttributesIndex — Retrieve the external attributes of an entry defined by its index
  • ZipArchive::getExternalAttributesName — Retrieve the external attributes of an entry defined by its name
  • ZipArchive::getFromIndex — Returns the entry contents using its index
  • ZipArchive::getFromName — Returns the entry contents using its name
  • ZipArchive::getNameIndex — Returns the name of an entry using its index
  • ZipArchive::getStatusString — Returns the status error message, system and/or zip messages
  • ZipArchive::getStream — Get a file handler to the entry defined by its name (read only).
  • ZipArchive::locateName — Returns the index of the entry in the archive
  • ZipArchive::open — Open a ZIP file archive
  • ZipArchive::renameIndex — Renames an entry defined by its index
  • ZipArchive::renameName — Renames an entry defined by its name
  • ZipArchive::setArchiveComment — Set the comment of a ZIP archive
  • ZipArchive::setCommentIndex — Set the comment of an entry defined by its index
  • ZipArchive::setCommentName — Set the comment of an entry defined by its name
  • ZipArchive::setExternalAttributesIndex — Set the external attributes of an entry defined by its index
  • ZipArchive::setExternalAttributesName — Set the external attributes of an entry defined by its name
  • ZipArchive::statIndex — Get the details of an entry defined by its index.
  • ZipArchive::statName — Get the details of an entry defined by its name.
  • ZipArchive::unchangeAll — Undo all changes done in the archive
  • ZipArchive::unchangeArchive — Revert all global changes done in the archive.
  • ZipArchive::unchangeIndex — Revert all changes done to an entry at the given index
  • ZipArchive::unchangeName — Revert all changes done to an entry with the given name.
  • 资料查询

参考文章:(98条消息) PHP扩展类ZipArchive实现压缩解压Zip文件和文件打包下载_php ziparchive解压缩文件_dreamboycx的博客-CSDN博客

本文发布于:2024-02-04 08:40:25,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170703320254040.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23