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. MATLAB学习(十)实现文件、图像读写

    t=1:5; s1=sin(t); s2=cos(t); s=[t;s1;s2]; fid1=fopen('test.dat','wt'); fprintf(fid1,'\nThis is a For ...

  2. android stdio 首次安装配置

    http://www.cnblogs.com/smyhvae/p/4390905.html 不启用 加快模拟器调试 这个玩意儿打开老是报什么 android 1.0的问题 导致编译不起来 直接关了 S ...

  3. python 学习记录1

    存储 序号   分类    技术      用途 01      存储     Number  数字(不可变) String     字符串(不可变) List          列表 Tuple   ...

  4. PJzhang:python基础进阶的10个疗程-three

    猫宁!!! 参考:北京理工大学-python程序语言设计 第3节:基本数据类型 默写代码的重要性. 保留字一定要全部都会默写,不能有错. pow(x,y),计算x的y次方,整数没有大小限制 整数进制 ...

  5. FUZZ测试简介

    基本思想:利用黑盒方法,发送大量恶意/随机数据到被测试系统,通过监视系统运行过程中的异常,来发现应用程序中可能存在的安全问题.

  6. Elasticsearch基础入门,详情可见官方文档

    索引文档: 对于员工目录,我们将做如下操作: 每个员工索引一个文档,文档包含该员工的所有信息. 每个文档都将是 employee 类型 . 该类型位于 索引 megacorp 内. 该索引保存在我们的 ...

  7. python 其实不用框架你也可以实现ORM

    """ ORM思路归纳: 1.将每张表映射成不同的表类,一个表类映射一张表.表类的类属性 需要有表名.字段名 将每个字段类型映射为字段类型类,一个字段类型类映射一个类 字 ...

  8. OpenCV_复制一个或多个ROI图像区域

    在对图像进行处理过程中,我们经常需要对图像的某个或多个感兴趣区域进行处理.在OpenCV中我们能够非常方便地获取指定ROI区域的子图像.下面这段代码就演示了怎样获取指定单个ROI或多个ROI图像区域. ...

  9. PHP读取TXT中文乱码的解决方法

    //$fname文件名称 if ($fname = $_FILES['nickname']['tmp_name']) { //file_get_contents() 函数把整个文件读入一个字符串中. ...

  10. vultr 更换服务器

    今天打算去p站看看电影 结果发现自己的vps被封了......记录一下换服务器的过程 首先去 https://www.17ce.com/ ping一下,发现只有国外的服务器能ping通 果然是被封了. ...