php下载单文件 以及 多文件打包下载,支持断点续传

  • 断点续传的功能未经验证
  • 需要nginx或者apache服务器指定静态文件,png, mp4, zip等后缀文件的目录,
  • 直接实例化并调用 download 方法, $file 与 $name为前台传过来的参数, 实验时,可以先设置默认值来调用。
<?php
/**
* User: LiZheng 271648298@qq.com
* Date: 2019/10/14
*/ namespace app\services; use app\foundation\Service; class DownloadService extends Service
{ private $_speed = 4096; // 下载速度, 未启用
/**
* 下载,$file 与 $name为前台传过来的参数, 实验时,可以先设置默认值来调用。
* @param String $file 要下载的文件路径(此处我的路径为URL路径,非服务器上的绝对路径, 前期试验为了简化过程,可以直接使用使用服务器路径,删除路径转换的代码)
* @param String $name 文件名称,为空则与下载的文件名称一样
* @param boolean $reload 是否开启断点续传, 默认不开启
* @return string
* User: LiZheng 271648298@qq.com
* Date: 2019/10/14
*/
public function download($file, $name = '', $reload = false)
{
$filePath = explode(',', $file);
$count = count($filePath);
if($count > 1)
{
// 生成zip打包下载
$zip = new \ZipArchive();
//服务器类型, WIN是本地,否则linux,
$media_dir = strtoupper(substr(PHP_OS,0,3))==='WIN'?'d:/media_space':'/media_space';
$tmp = "cache/".date('Y-m-d')."/";
// 压缩文件的临时目录
$root_dir = $media_dir."/".$tmp;
//是否存在图片根目录,不存在则创建
if(!is_dir($root_dir))
{
//权限是否OK
mkdir($root_dir, 0777, true) && chmod($root_dir, 0777);
}
// 生成zip文件, 文件名要求唯一
$unique = md5((time().mt_rand(10,99).mt_rand(10,99))/mt_rand(1,100)).'.zip';
$root_dir .= $unique;
$URLs = PIC_HOST.$tmp.$unique;
touch($root_dir);
// 必须先新建.zip文件才可以执行foreach中的代码
if($zip->open($root_dir) === true){
foreach ($filePath as $item){
$item = $media_dir.substr($item, strpos($item,'com.cn/')+6);
$zip->addFile($item, basename($item));
}
$zip->close();
$file = $URLs;
}else{
$this -> setError('压缩失败!');
return false;
}
}else
{
// 如果是单文件,直接使用文件名称
$file = $filePath[0];
}
$fp = @fopen($file, 'rb');
if ($fp) {
if ($name == '') {
$name = basename($file);
}
$header_array = get_headers($file, true);
//var_dump($header_array);die;
// 下载本地文件,获取文件大小
if (!$header_array) {
$file_size = filesize($file);
} else {
$file_size = $header_array['Content-Length'];
}
$ranges = $this->getRange($file_size);
$ua = $_SERVER["HTTP_USER_AGENT"];//判断是什么类型浏览器
header('cache-control:public');
header('content-type:application/octet-stream'); $encoded_filename = urlencode($name);
$encoded_filename = str_replace("+", "%20", $encoded_filename); //解决下载文件名乱码
if (preg_match("/MSIE/", $ua) || preg_match("/Trident/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
header('Content-Disposition: attachment; filename*="utf8\'\'' . $name . '"');
} else if (preg_match("/Chrome/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else {
header('Content-Disposition: attachment; filename="' . $name . '"');
}
//header('Content-Disposition: attachment; filename="' . $name . '"'); if ($reload && $ranges != null) { // 使用续传
header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges:bytes'); // 剩余长度
header(sprintf('content-length:%u', $ranges['end'] - $ranges['start'])); // range信息
header(sprintf('content-range:bytes %s-%s/%s', $ranges['start'], $ranges['end'], $file_size));
//file_put_contents('test.log',sprintf('content-length:%u',$ranges['end']-$ranges['start']),FILE_APPEND);
// fp指针跳到断点位置
fseek($fp, sprintf('%u', $ranges['start']));
} else {
// file_put_contents('test.log', '2222', FILE_APPEND);
header('HTTP/1.1 200 OK');
header('Accept-Ranges:bytes');
header('content-length:' . $file_size);
} while (!feof($fp)) {
//echo fread($fp, round($this->_speed*1024,0)); // 如限速,调用 setSpeed()
//echo fread($fp, $file_size);
echo fread($fp, 4096);
ob_flush();
} ($fp != null) && fclose($fp);
// TODO 删除临时文件压缩包
if(isset($root_dir))
{
unlink($root_dir);
}
} else {
$this -> setError('下载失败!');
return false;
}
} /** 设置下载速度
* @param int $speed
*/
public function setSpeed($speed)
{
if (is_numeric($speed) && $speed > 16 && $speed < 4096) {
$this->_speed = $speed;
}
} /** 获取header range信息
* @param int $file_size 文件大小
* @return Array
*/
private function getRange($file_size)
{
//file_put_contents('range.log', json_encode($_SERVER), FILE_APPEND);
if (isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])) {
$range = $_SERVER['HTTP_RANGE'];
$range = preg_replace('/[\s|,].*/', '', $range);
$range = explode('-', substr($range, 6));
if (count($range) < 2) {
$range[1] = $file_size;
}
$range = array_combine(array('start', 'end'), $range);
if (empty($range['start'])) {
$range['start'] = 0;
}
if (empty($range['end'])) {
$range['end'] = $file_size;
}
return $range;
}
return null;
}
}

上面为php下载的代码,正常在浏览器访问该接口,设置上默认的参数file:文件URL,会弹出下载框

  • 请使用前端调用该下载接口,而不是PHP
  • 如果使用ajax调用时仅返回二进制数据流不弹出下载框,请使用隐藏表单进行请求,不建议使用get打开新窗口下载
- 仅为演示代码,

<form id="downloadForm" style="display: none" method="post">
<input name="filePath" id="filePath" type="hidden">
<input name="newName" id="newName" type="hidden">
</form>
<script>
//文件下载
$("#down").click(function () {
var data = [];
$('input.both-all:checked').map(function (i,v) {
data.push($(v).val());
});
if(data.length==0){
alert('请勾选!');
return false;
}
$.ajax({
type:"post"
,dataType:"Json"
,url:"pan/files/down" // 这里的php代码主要用来整理下载时用到的参数,如果不想使用php整理,也可以直接在JS中整理。
,data:{id:data}
,success:function (result) {
console.log(result)
var host = result.data.host; // 文件服务器的接口地址(下载)
var filePath = result.data.filePath; // 通过文件的ID获取文件的url,以,为分隔符拼接为字符串
var newName = result.data.newName; // 文件下载后的名称,不填默认为原文件名称(多文件时生成特定的文件名,后缀为.zip即可)
var form = $("#downloadForm"); // 隐藏的下载表单
var input_filePath = $("#filePath"); // 表单中的input filePath 字段,
var input_newName = $("#newName"); // 表单中的input newName 字段
form.attr('target',''); // _blank 也可
form.attr('action',host); // 文件服务器的接口地址(下载)
input_filePath.attr('value',filePath);
input_newName.attr('value',newName);
alert("submit")
form.submit(); // 提交表单
}
,error:function (e) {
// alert(e.msg)
} })
})
</script>

php打包下载以及断点续传的更多相关文章

  1. 2014年最新720多套Android源码2.0GB免费一次性打包下载

    之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共 ...

  2. ASP.NET五步打包下载Zip文件

    本文版权归博客园和作者吴双共同所有,转载和爬虫请注明原文地址:www.cnblogs.com/tdws 首先分享几个振奋人心的新闻: 1.谷歌已经宣布加入.NET基金会 2.微软加入Linux基金会, ...

  3. 射手网字幕打包下载(73.16G)

    射手网陪着我度过15年了. 我所希望射手网所具有的价值,就是能令更多人跨越国家的樊篱,了解世界上不同的文化. 如果这个网站有帮到人,我就已经很满足了. 但是,需要射手网的时代已经走开了. 因此,今天, ...

  4. Android开发之多线程下载、断点续传、进度条和文本显示

    代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...

  5. Java开发之多线程下载和断点续传

    代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...

  6. java多线程下载和断点续传

    java多线程下载和断点续传,示例代码只实现了多线程,断点只做了介绍.但是实际测试结果不是很理想,不知道是哪里出了问题.所以贴上来请高手修正. [Java]代码 import java.io.File ...

  7. ASP.NET 打包下载文件

    使用的类库为:ICSharpCode.SharpZipLib.dll 一种是打包整个文件夹,另一种是打包指定的多个文件,大同小异: using ICSharpCode.SharpZipLib.Zip; ...

  8. C#.NET快速开发框架-企业版V4.0截图打包下载

    C/S系统开发框架-企业版 V4.0 (Enterprise Edition) http://www.csframework.com/cs-framework-4.0.htm 其它图片打包下载: ht ...

  9. cocos2d-x 通过socket实现http下载及断点续传的实现

    cocos2d-x 通过socket实现http下载及断点续传的实现 代码未经进一步的整理,可能比较混乱. 首先,2dx的socket库由BSSocket组成.可跨平台,在windows上已验证. 1 ...

随机推荐

  1. selenium 2019 笔记

    1.get打开本地目录的方法

  2. Windows10系统python环境下安装Dlib库(转载,蔡军帅亲测可用)

    Dlib是一个很优秀的机器学习库,最近做人脸识别要用到这个库,简要记录一下配置过程,准备工作: 1.python环境 2.安装好pip(这里有个简单的安装教程) 3.Dlib包,贴一个我安装的版本,链 ...

  3. Python之网络模型与图形绘制工具networkx

    笔记 # https://www.jianshu.com/p/e543dc63454f import networkx as nx import matplotlib.pyplot as plt ## ...

  4. 纹理特征描述之自相关函数法 纹理粗糙性与自相关函数的扩展成正比 matlab代码实现

    图像中通常采用自相关函数作为纹理测度 自相关函数的定义为: ​ 调用自定义函数 zxcor()对砖墙面和大理石面纹理进行分析: 自定义函数 zxcor(): function [epsilon,eta ...

  5. linux 中的命令是什么?执行命令的几种方式?如何自己创建命令?

    linux 中的命令是什么? 命令是可执行的二进制程序 执行命令的几种方式? ./test.sh                     #相对路径执行 /data/test.sh           ...

  6. 【POJ - 2078】Matrix(dfs)

    -->Matrix Descriptions: 输入一个n×n的矩阵,可以对矩阵的每行进行任意次的循环右移操作,行的每一次右移后,计算矩阵中每一列的和的最大值,输出这些最大值中的最小值. Sam ...

  7. java使用validator进行校验

    不管是html页面表单提交的对象数据还是和第三方公司进行接口对接,都需要对接收到的数据进行校验(非空.长度.格式等等).如果使用if一个个进行校验(字段非常多),这是让人崩溃的过程.幸好jdk或hib ...

  8. 20191204-使用nginx解决ajax测试调用接口跨域问题

    问题描述 之前要测试一个http的接口,在postman中测试成功,但使用ajax调用却跨域.于是通过使用ngin反向代理的方式来解决ajax调用跨域问题 测试页面的内容 <html> & ...

  9. Log4j2配置之Appender详解

    Log4j2配置之Appender详解 Appender负责将日志事件传递到其目标.每个Appender都必须实现Appender接口.大多数Appender将扩展AbstractAppender,它 ...

  10. 怎么将本地项目放到码云(gitee)上面?图文详解

    git的好处什么的,在此就不多赘述.现在很多公司都在用git了. 那么怎么将本地已经有的项目放到码云(gitee)上呢? 前置条件说明: 1:原来项目所在位置:D:\workspace01\class ...