php打包下载以及断点续传
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打包下载以及断点续传的更多相关文章
- 2014年最新720多套Android源码2.0GB免费一次性打包下载
之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共 ...
- ASP.NET五步打包下载Zip文件
本文版权归博客园和作者吴双共同所有,转载和爬虫请注明原文地址:www.cnblogs.com/tdws 首先分享几个振奋人心的新闻: 1.谷歌已经宣布加入.NET基金会 2.微软加入Linux基金会, ...
- 射手网字幕打包下载(73.16G)
射手网陪着我度过15年了. 我所希望射手网所具有的价值,就是能令更多人跨越国家的樊篱,了解世界上不同的文化. 如果这个网站有帮到人,我就已经很满足了. 但是,需要射手网的时代已经走开了. 因此,今天, ...
- Android开发之多线程下载、断点续传、进度条和文本显示
代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...
- Java开发之多线程下载和断点续传
代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...
- java多线程下载和断点续传
java多线程下载和断点续传,示例代码只实现了多线程,断点只做了介绍.但是实际测试结果不是很理想,不知道是哪里出了问题.所以贴上来请高手修正. [Java]代码 import java.io.File ...
- ASP.NET 打包下载文件
使用的类库为:ICSharpCode.SharpZipLib.dll 一种是打包整个文件夹,另一种是打包指定的多个文件,大同小异: using ICSharpCode.SharpZipLib.Zip; ...
- C#.NET快速开发框架-企业版V4.0截图打包下载
C/S系统开发框架-企业版 V4.0 (Enterprise Edition) http://www.csframework.com/cs-framework-4.0.htm 其它图片打包下载: ht ...
- cocos2d-x 通过socket实现http下载及断点续传的实现
cocos2d-x 通过socket实现http下载及断点续传的实现 代码未经进一步的整理,可能比较混乱. 首先,2dx的socket库由BSSocket组成.可跨平台,在windows上已验证. 1 ...
随机推荐
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-02 微服务调用方式之ribbon实战 订单调用商品服务
笔记 2.微服务调用方式之ribbon实战 订单调用商品服务 简介:实战电商项目 订单服务 调用商品服务获取商品信息 1.创建order_service项目 2 ...
- Jmeter性能测试工具的使用(Web性能测试)
Jmeter性能测试工具的使用(Web性能测试) 1.下载 http://pan.baidu.com/s/1o7p18Ye 该软件不用安装,直接解压打开即可使用. 2.使用 这里就在win下进行,图形 ...
- Python--多任务(多进程,多线程,协程)
1.单核CPU实现“多任务”:(注意:这里的多任务假的,是轮训执行多个任务一段时间) 1)时间片轮转 2)优先级调度算法 2.并行:真的多任务执行(CPU核数>=任务数):即在某个时刻点上,有多 ...
- docker下载镜像
注意:必须先搜索镜像,否则有时候无法下载 Docker下载Redis镜像并运行容器 .搜索查找镜像 docker search redis .下载镜像 docker pull redis:latest ...
- DS18b20温度传感器基础使用
认识管脚 认识唯一标示的64位地址序列号 寄存器数据译码成温度值(下面只针对12位转化的,还有9..10等其他位的转化方式,不同位的转化,其精度也不同) 传感器存储器 配置寄存器使用说明 DS18b2 ...
- BUGKU (Mountain climbing)
UPX壳,手脱后打不开,可能是在windows10脱壳的缘故吧.放在XP虚拟机上手脱可能会好,但是提示缺少dll.无奈,智能用工具了. 用的这个,感觉蛮好用的. 先打开程序.随便输入一个数,提示err ...
- python基础学习19,01
听说python入门很容易,所以想试试对我这个零基础会不会很友好呢.做随笔也顺便督促自己不要轻易放弃学习. #登录接口 print("请输入用户名密码") _username = ...
- 利用ceph-deploy安装ceph
手工安装https://www.jianshu.com/p/b8f085ca0307 在ceph所有节点上执行 1.配置hosts cat << EOF >> /etc/hos ...
- 2019年最新Web安全攻防班课程
咨询请加QQ:1373721311 或 2644148223 课程核心大纲总览 Web安全攻防班以业界权威的OWASP TOP 10的漏洞为主干课程.更加详细教学思维导图可访问如下链接:https:/ ...
- 深入理解C语言-接口封装设计思想
断层思维 在设计时候,不需要知道实现,只需要知道如何使用 接口设计的设计思路 Sckclient客户端api模型 第一套API (*.h) #ifndef _SCK_CLINT_H_ #define ...