php实现断点续传大文件示例代码

一、断点续传原理

所谓断点续传,也就是要从文件已经下载的地方开始继续下载。在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。一般断点下载时才用到 Range 和 Content-Range 实体头。

不使用断点续传

get /down.zip http/1.1
accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
accept-language: zh-cn
accept-encoding: gzip, deflate
user-agent: mozilla/4.0 (compatible; msie 5.01; windows nt 5.0)
connection: keep-alive

服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:

HTTP/1.1 200 Ok
content-length=106786028
accept-ranges=bytes
date=mon, 30 apr 2001 12:56:11 gmt
etag=w/"02ca57e173c11:95b"
content-type=application/octet-stream
server=microsoft-iis/5.0
last-modified=mon, 30 apr 2001 12:56:11 gmt

使用断点续传

GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

多了这么一行Range: bytes=2000070-

这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。
Range的完整格式是:

Range: bytes=startOffset-targetOffset/sum [表示从startOffset读取,一直读取到targetOffset位置,读取总数为sum直接]

Range: bytes=startOffset-targetOffset [字节总数也可以去掉]

服务器收到这个请求以后,返回的信息如下:

HTTP/1.1 206 Partial Content
content-length=106786028
content-range=bytes 2000070-106786027/106786028
date=mon, 30 apr 2001 12:55:20 gmt
etag=w/"02ca57e173c11:95b"
content-type=application/octet-stream
server=microsoft-iis/5.0
last-modified=mon, 30 apr 2001 12:55:20 gmt

和前面服务器返回的信息比较一下,就会发现增加了一行:

Content-Range=bytes 2000070-106786027/106786028

返回的代码也改为206了,而不再是200了。

HTTP/1.1 206 Partial Content

知道了以上原理,就可以进行断点续传的编程了。

二、PHP实现

/** php下载类,支持断点续传
 * download: 下载文件
 * setSpeed: 设置下载速度
 * getRange: 获取header中Range
 */

class FileDownload{

 /** 下载
 * @param String $file 要下载的文件路径
 * @param String $name 文件名称,为空则与下载的文件名称一样
 * @param boolean $reload 是否开启断点续传
 */
 public function download($file, $name='', $reload=false){
 $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('content-length:'.$file_size);
 }

 while(!feof($fp)){
 //echo fread($fp, round($this->_speed*1024,0));
 //echo fread($fp, $file_size);
 echo fread($fp, 4096);
 ob_flush();
 }

 ($fp!=null) && fclose($fp);
 }else{
 return '';
 }
 }

 /** 设置下载速度
 * @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;
 }
}

$obj = new FileDownload();
$obj->download('http://down.golaravel.com/laravel/laravel-master.zip','', true);

以上就是php实现断点续传大文件示例代码的详细内容,更多关于php 断点续传大文件的资料请关注我们其它相关文章!

(0)

相关推荐

  • php断点续传之文件分割合并详解

    php实现断点续传,就需要把大文件分割成多个小文件,然后单个上传.传完后在合并. │ merge.php –合并文件脚本 │ merge.zip –合并后文件 │ socket.zip –需要分割的文件 │ split.php –分割文件脚本 │ └─split –分割后小文件目录 下面是源码 split.php <?php $fp = fopen("socket.zip", "rb"); $filesize = 10; $i = 0; $no = 1; wh

  • 前端实现文件的断点续传(前端文件提交+后端PHP文件接收)

    早就听说过断点续传这种东西,前端也可以实现一下.断点续传在前端的实现主要依赖着HTML5的新特性,所以一般来说在老旧浏览器上支持度是不高的. 本文通过断点续传的简单例子(前端文件提交+后端PHP文件接收),理解其大致的实现过程 还是先以图片为例,看看最后的样子 一.一些知识准备 断点续传,既然有断,那就应该有文件分割的过程,一段一段的传. 以前文件无法分割,但随着HTML5新特性的引入,类似普通字符串.数组的分割,我们可以可以使用slice方法来分割文件. 所以断点续传的最基本实现也就是:前端通

  • php断点续传之如何分割合并文件

    复制代码 代码如下: <?php ini_set("memory_limit", "50M");//必须的,根据你环境的实际情况尽量大,防止报错 ini_set("max_execution_time", "100"); //file_exists() 函数检查文件或目录是否存在,存在则返回 true,否则返回 false. //fread() 函数读取文件(可安全用于二进制文件).fread() 从文件指针 file

  • php实现大文件断点续传下载实例代码

    php实现大文件断点续传下载实例,看完你就知道超过100M以上的大文件如何断点传输了,这个功能还是比较经典实用的,毕竟大文件上传功能经常用得到. require_once('download.class.php'); date_default_timezone_set('Asia/Shanghai'); error_reporting(E_STRICT); function errorHandler($errno, $errstr, $errfile, $errline) { echo '<p>

  • php实现的支持断点续传的文件下载类

    本文实例讲述了php实现的支持断点续传的文件下载类及其用法,是非常实用的技巧.分享给大家供大家参考.具体方法如下: 通常来说,php支持断点续传,主要依靠HTTP协议中 header HTTP_RANGE实现. HTTP断点续传原理: Http头 Range.Content-Range() HTTP头中一般断点下载时才用到Range和Content-Range实体头, Range用户请求头中,指定第一个字节的位置和最后一个字节的位置,如(Range:200-300) Content-Range用

  • 前端js实现文件的断点续传 后端PHP文件接收

    早就听说过断点续传这种东西,前端也可以实现一下. 断点续传在前端的实现主要依赖着HTML5的新特性,所以一般来说在老旧浏览器上支持度是不高的 本文通过断点续传的简单例子(前端文件提交+后端PHP文件接收),理解其大致的实现过程 还是先以图片为例,看看最后的样子 一.一些知识准备 断点续传,既然有断,那就应该有文件分割的过程,一段一段的传. 以前文件无法分割,但随着HTML5新特性的引入,类似普通字符串.数组的分割,我们可以可以使用slice方法来分割文件. 所以断点续传的最基本实现也就是:前端通

  • PHP实现断点续传乱序合并文件的方法

    本文实例讲述了PHP实现断点续传乱序合并文件的方法.分享给大家供大家参考,具体如下: 分割成多个文件发送,由于网络原因并不上先发就能发接收到.所以我们不能按顺序合并. 分割文件源码前面一篇文章<PHP断点续传之文件分割合并> merge2.php <?php $fileTotaiSize = filesize("socket.zip"); $filelist = glob('./split/*socket*.tmp'); $filesize = 3096; //打乱读

  • 关于php支持分块与断点续传文件下载功能代码

    本文章要介绍了这篇文章是一篇关于php流下载,就是可以支持分块与断点续传文件下载,有需要的朋友可以看看.代码如下 复制代码 代码如下: $dowmFile = dirname ( __FILE__ ) . '/Nokia – Always Here.mp3′; //要下载的文件,绝对或相对 $dowmName = 'Nokia – Always Here.mp3′; ob_start (); getlocalfile ( $dowmFile, $dowmName ); flush (); ob_

  • 解决PHP超大文件下载,断点续传下载的方法详解

    最近导出的时候出现一个php内存溢出的问题,原因就是在于下载的时候读取生成的临时文件过大,PHP内存无法容纳,一开如是想到更改PHP内存限制,但是这个只是一个缓兵之计,于是想到了另外一个方法是把文件分次读取,并下载. 以下是源代码: 复制代码 代码如下: <?php $sourceFile = "1.tmp"; //要下载的临时文件名 $outFile = "用户订单.xls"; //下载保存到客户端的文件名 $file_extension = strtolo

  • PHP实现文件下载断点续传详解

    如果我们的网站提供文件下载的服务,那么通常我们都希望下载可以断点续传(Resumable Download),也就是说用户可以暂停下载,并在未来的某个时间从暂停处继续下载,而不必重新下载整个文件. 通常情况下,Web服务器(如Apache)会默认开启对断点续传的支持.因此,如果直接通过Web服务器来提供文件的下载,可以不必做特别的配置,即可享受到断点续传的好处.由于这些文件直接通过Web服务器来提供下载,后端脚本无法对这个下载过程进行控制.这对于仅提供公开.静态文件的网站来说不是问题,但对于需要

  • PHP使用range协议实现输出文件断点续传代码实例

    range协议用途:一般是用在断点续传的时候,但是实际的用户很大,例如你的web server需要输出一个大文件,那么用range可以分段输出,缓解压力.同时在提供音乐视频等服务时可以缓冲下载,如果用户中途关闭,可以节约网络带宽. <?php // 文件名 $filename = $_GET ['filename']; // 文件路径 $location = 'media/' . $filename; // 后缀 $extension = substr ( strrchr ( $filename

随机推荐