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. BeanUtils.getProperty性能分析

    接上文Java各种反射性能对比 BeanUtils.getProperty的原理其实以下方法类似,但稍有不同 //代码片段4.1        PropertyDescriptor descripto ...

  2. ubantu使用小结

    一.root账户问题 1.初始登录的时候root密码是随机的,自己改一个. 2.登录界面没有root选项 解决: #gedit /usr/share/lightdm/lightdm.conf.d/50 ...

  3. 配置glance使用ceph作为后端存储

    在ceph监视器上执行 1.创建pool池 为glance服务创建pool池(因为我只有一个OSD节点,所以要将副本数设置为1) ceph osd pool create glance-images  ...

  4. 一、linux基础命令

    一. 常用系统工作命令 1.echo 命令 ​ echo命令用于在终端输出字符串或者变量提取后的值 ​ echo $SHELL 2.date命令 ​ date命令用于显示及设置系统的时间或者日期 参数 ...

  5. 零零散散的python笔记 2

    python2和python3的兼容性方面 工具 2to3 python3中自带的工具,可以检查python2升级到python3的diff: 2to3 x.py 2to3 -w x.py     # ...

  6. 论文阅读 | HotFlip: White-Box Adversarial Examples for Text Classification

    [code] [pdf] 白盒 beam search 基于梯度 字符级

  7. Minimum Number of Arrows to Burst Balloons

    There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided ...

  8. 【Python】【demo实验5】【练习实例】【多个数字组合成不重复三位数】

    题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 程序源代码 ...

  9. Java利用模板生成pdf并导出

    1.准备工作 (1)Adobe Acrobat pro软件:用来制作导出模板 (2)itext的jar包 2.开始制作pdf模板 (1)先用word做出模板界面 (2)文件另存为pdf格式文件 (3) ...

  10. BOF和EOF详解2

    在学生信息管理系统中有多处用到EOF和BOF,使用BOF和EOF属性可确定Recordset对象是否包含记录,或者从一个记录移动到另一个记录是否超出Recordset对象的限制. BOF和EOF他们是 ...