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. Python新利器之pipenv

    前言 之前学习异步asyncio库的时候,因为asyncio库支持Python3.5以上的版本,而我的Ubuntu14.04只有Python3.4,虽然下载了Python3.6,但是想直接利用ipyt ...

  2. MATLAB学习(六)绘图图形功能

    >> x=0:.1:2*pi;plot(x,sin(x),x,cos(x))                               >> plot(x,sin(x),'p ...

  3. React Native安卓代码混淆和打包

    一上午就整了个React Native的打包,中间还遇到各种问题,这里还是记录下吧: 文档链接: http://reactnative.cn/docs/0.45/signed-apk-android. ...

  4. DevOps - 虚拟环境构建工具Vagrant

    1 - Vagrant HomePage: https://www.vagrantup.com/ Download: https://www.vagrantup.com/downloads.html ...

  5. harbor API 与tag 清理

    harbor API 官方swagger swagger在线查看 harbor tag 清理 python程序 import requests import json class RequestCli ...

  6. 常用小技巧之PyCharm IDE

    Pycharm控制台窗口怎样可以显示不同程序的运行结果 默认情况下,每次运行会把之前的那个结果给清理掉. 有时候运行多个程序像对比结果,不太方便. 可以在pycharm的控制台那里点击右键,在弹出的菜 ...

  7. linux上安装tcl、tk、expect

    linux上安装tcl.tk.expect   1.tcl安装tcl8.5.9-src.tar.gz cd /tmp tar -zxvf tcl8.5.9-src.tar.gz cd tcl8.5.9 ...

  8. scrapy生成json中文为ASCII码解决

    修改pipelines.py 即可 修改内容如下: import json import codecs import os class BaiduNewsPipeline(object): #增加的 ...

  9. T100——上传图片

    例子可参考aooi100,上传集团logo的程序 ON ACTION btn_updatelogo #選取上傳檔案,GDC專用 LET gs_upload = NULL CALL cl_client_ ...

  10. X86逆向4:VMP壳内寻找注册码

    本节课将讲解一下重启验证,重启验证在软件中也是非常的常见的,重启验证的原理很简单,用户在注册界面输入注册码以后程序会自动将输入的注册信息保存到配置文件中,这里可能保存到注册表,也可能使用INI文件来保 ...