首页 > 编程语言 >php实现大文件断点续传下载实例

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

时间:2023-09-20 18:22:42浏览次数:40  
标签:mimeType 断点续传 filePath bytes header range 实例 sprintf php

php实现大文件断点续传下载实例,看完你就知道超过100M以上的大文件如何断点传输了,这个功能还是比较经典实用的,毕竟大文件上传功能经常用得到。

复制代码
 1 require_once('download.class.php'); 
 2 date_default_timezone_set('Asia/Shanghai'); 
 3 error_reporting(E_STRICT); 
 4  
 5 function errorHandler($errno, $errstr, $errfile, $errline) { 
 6     echo '<p>error:', $errstr, '</p>'; 
 7     exit(); 
 8 } 
 9  
10 set_error_handler('errorHandler'); 
11 define('IS_DEBUG', true); 
12  
13 $filePath = 'test.zip'; 
14 $mimeType = 'audio/x-matroska'; 
15 $range = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : null; 
16 if (IS_DEBUG) { 
17 //    $range = "bytes=1000-1999\n2000"; 
18 //    $range = "bytes=1000-1999,2000";  
19 //    $range = "bytes=1000-1999,-2000";  
20 //    $range = "bytes=1000-1999,2000-2999";  
21 } 
22 set_time_limit(0); 
23 $transfer = new Transfer($filePath, $mimeType, $range); 
24 if (IS_DEBUG) { 
25     $transfer->setIsLog(true); 
26 } 
27 $transfer->send();
复制代码

download.class.php

复制代码
  1 /** 
  2  * 文件传输,支持断点续传。 
  3  * 2g以上超大文件也有效 
  4  * @author MoXie 
  5  */ 
  6 class Transfer { 
  7  
  8     /** 
  9      * 缓冲单元 
 10      */ 
 11     const BUFF_SIZE = 5120; // 1024 * 5 
 12  
 13     /** 
 14      * 文件地址 
 15      * @var <String> 
 16      */ 
 17  
 18     private $filePath; 
 19  
 20     /** 
 21      * 文件大小 
 22      * @var <String> Php超大数字 字符串形式描述 
 23      */ 
 24     private $fileSize; 
 25  
 26     /** 
 27      * 文件类型 
 28      * @var <String> 
 29      */ 
 30     private $mimeType; 
 31  
 32     /** 
 33      * 请求区域(范围) 
 34      * @var <String> 
 35      */ 
 36     private $range; 
 37  
 38     /** 
 39      * 是否写入日志 
 40      * @var <Boolean> 
 41      */ 
 42     private $isLog = false; 
 43  
 44     /** 
 45      * 
 46      * @param <String> $filePath 文件路径 
 47      * @param <String> $mimeType  文件类型 
 48      * @param <String> $range 请求区域(范围) 
 49      */ 
 50     function __construct($filePath, $mimeType = null, $range = null) { 
 51         $this->filePath = $filePath; 
 52         $this->fileSize = sprintf('%u', filesize($filePath)); 
 53         $this->mimeType = ($mimeType != null) ? $mimeType : "application/octet-stream"; //  bin 
 54         $this->range = trim($range); 
 55     } 
 56  
 57     /** 
 58      *  获取文件区域 
 59      * @return <Map> {'start':long,'end':long} or null 
 60      */ 
 61     private function getRange() { 
 62         /** 
 63          *  Range: bytes=-128 
 64          *  Range: bytes=-128 
 65          *  Range: bytes=28-175,382-399,510-541,644-744,977-980 
 66          *  Range: bytes=28-175\n380 
 67          *  type 1 
 68          *  RANGE: bytes=1000-9999 
 69          *  RANGE: bytes=2000-9999 
 70          *  type 2 
 71          *  RANGE: bytes=1000-1999 
 72          *  RANGE: bytes=2000-2999 
 73          *  RANGE: bytes=3000-3999 
 74          */ 
 75         if (!empty($this->range)) { 
 76             $range = preg_replace('/[\s|,].*/', '', $this->range); 
 77             $range = explode('-', substr($range, 6)); 
 78             if (count($range) < 2) { 
 79                 $range[1] = $this->fileSize; // Range: bytes=-100 
 80             } 
 81             $range = array_combine(array('start', 'end'), $range); 
 82             if (empty($range['start'])) { 
 83                 $range['start'] = 0; 
 84             } 
 85             if (!isset($range['end']) || empty($range['end'])) { 
 86                 $range['end'] = $this->fileSize; 
 87             } 
 88             return $range; 
 89         } 
 90         return null; 
 91     } 
 92  
 93     /** 
 94      * 向客户端发送文件 
 95      */ 
 96     public function send() { 
 97         $fileHande = fopen($this->filePath, 'rb'); 
 98         if ($fileHande) { 
 99             // setting 
100             ob_end_clean(); // clean cache 
101             ob_start(); 
102             ini_set('output_buffering', 'Off'); 
103             ini_set('zlib.output_compression', 'Off'); 
104             $magicQuotes = get_magic_quotes_gpc(); 
105 //            set_magic_quotes_runtime(0); 
106             // init 
107             $lastModified = gmdate('D, d M Y H:i:s', filemtime($this->filePath)) . ' GMT'; 
108             $etag = sprintf('w/"%s:%s"', md5($lastModified), $this->fileSize); 
109             $ranges = $this->getRange(); 
110             // headers 
111             header(sprintf('Last-Modified: %s', $lastModified)); 
112             header(sprintf('ETag: %s', $etag)); 
113             header(sprintf('Content-Type: %s', $this->mimeType)); 
114             $disposition = 'attachment'; 
115             if (strpos($this->mimeType, 'image/') !== FALSE) { 
116                 $disposition = 'inline'; 
117             } 
118             header(sprintf('Content-Disposition: %s; filename="%s"', $disposition, basename($this->filePath))); 
119  
120             if ($ranges != null) { 
121                 if ($this->isLog) { 
122                     $this->log(json_encode($ranges) . ' ' . $_SERVER['HTTP_RANGE']); 
123                 } 
124                 header('HTTP/1.1 206 Partial Content'); 
125                 header('Accept-Ranges: bytes'); 
126                 header(sprintf('Content-Length: %u', $ranges['end'] - $ranges['start'])); 
127                 header(sprintf('Content-Range: bytes %s-%s/%s', $ranges['start'], $ranges['end'], $this->fileSize)); 
128                 // 
129                 fseek($fileHande, sprintf('%u', $ranges['start'])); 
130             } else { 
131                 header("HTTP/1.1 200 OK"); 
132                 header(sprintf('Content-Length: %s', $this->fileSize)); 
133             } 
134             // read file 
135             $lastSize = 0; 
136             while (!feof($fileHande) && !connection_aborted()) { 
137                 $lastSize = sprintf("%u", bcsub($this->fileSize, sprintf("%u", ftell($fileHande)))); 
138                 if (bccomp($lastSize, self::BUFF_SIZE) > 0) { 
139                     $lastSize = self::BUFF_SIZE; 
140                 } 
141                 echo fread($fileHande, $lastSize); 
142                 ob_flush(); 
143                 flush(); 
144             } 
145             set_magic_quotes_runtime($magicQuotes); 
146             ob_end_flush(); 
147         } 
148         if ($fileHande != null) { 
149             fclose($fileHande); 
150         } 
151     } 
152  
153     /** 
154      * 设置记录 
155      * @param <Boolean> $isLog  是否记录 
156      */ 
157     public function setIsLog($isLog = true) { 
158         $this->isLog = $isLog; 
159     } 
160  
161     /** 
162      * 记录 
163      * @param <String> $msg  记录信息 
164      */ 
165     private function log($msg) { 
166         try { 
167             $handle = fopen('transfer_log.txt', 'a'); 
168             fwrite($handle, sprintf('%s : %s' . PHP_EOL, date('Y-m-d H:i:s'), $msg)); 
169             fclose($handle); 
170         } catch (Exception $e) { 
171             // null; 
172         } 
173     } 
174  
175 }
复制代码

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/20/php%e5%ae%9e%e7%8e%b0%e5%a4%a7%e6%96%87%e4%bb%b6%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0%e4%b8%8b%e8%bd%bd%e5%ae%9e%e4%be%8b/

欢迎入群一起讨论

 

 

 

 



标签:mimeType,断点续传,filePath,bytes,header,range,实例,sprintf,php
From: https://www.cnblogs.com/songsu/p/17718031.html

相关文章

  • phpstudy无法启动mysql(启动之后立马关闭)
    好久没有打开本地环境,直到昨天打开phpstudy,正常启动,但是在任务管理器中发现没有mysql服务于是在mysql的bin目录下执行.\mysqld.exe--install  mysql服务是有了,但这个问题就来了重启phpstudy无法启动mysql注意:在此之前注意备份mysql数据,查看现在设置的mysql密码,以便本地项......
  • yourls安装-报错AbstractExtendedPdo.php
    1`Fatalerror:UncaughtPDOException:SQLSTATE[HY000]:Generalerror:3Errorwritingfile'./example_com/yourls_url.frm'(Errcode:28)in/www/wwwroot/example.com/includes/vendor/aura/sql/src/AbstractExtendedPdo.php:565Stacktrace:#0/www/w......
  • PHP如何上传超大文件
    前言最近在开发一个视频播放网站,用的是PHP技术。视频播放网站用户上传的都是视频资料,小的有几十M,大的都超过G了,对于这种超大文件的上传,我们不能用常规的上传方式,必须对大文件进行分块上传,否则一方面会造成服务器内存爆满,另一方如果上传的文件太大也很容造成上传超时的情况发生。......
  • 整理php防注入和XSS攻击通用过滤
    对网站发动XSS攻击的方式有很多种,仅仅使用php的一些内置过滤函数是对付不了的,即使你将filter_var,mysql_real_escape_string,htmlentities,htmlspecialchars,strip_tags这些函数都使用上了也不一定能保证绝对的安全。那么如何预防XSS注入?主要还是需要在用户数据过滤方面得考虑......
  • 如何实现断点续传
    断点续传是指在网络传输中,当传输过程中出现异常或者用户主动停止传输时,能够恢复传输过程,避免重新传输已经传输过的数据,提高传输效率。实现断点续传可以通过以下方式:HTTP协议支持的断点续传在HTTP协议中,通过设置请求头Range来实现断点续传。Range头指示服务器返回指定范围的响应内......
  • 大文件上传如何做断点续传?
    是什么不管怎样简单的需求,在量级达到一定层次时,都会变得异常复杂文件上传简单,文件变大就复杂上传大文件时,以下几个变量会影响我们的用户体验服务器处理数据的能力请求超时网络波动上传时间会变长,高频次文件上传失败,失败后又需要重新上传等等为了解决上述问题,我们需要对大文件......
  • thinkphp上传文件失败的一次记录
    问题出现有用户反映上传图片报网络错误,问题转到开发之后怀疑可能是用户上传的图片比较大导致的错误,后面测试发现在上传8m左右大小的图片的时候就会报错,但是报的错误不是代码里面图片大小验证规则的错误,而是异常捕获的错误,让我很纳闷后来决定先让前端在页面提......
  • web前端Tips:断点续传如何实现?
    在Web前端中实现断点续传功能的一种常见方式是使用HTTPRange请求和文件分片上传。以下是一个简单的断点续传实现的步骤:前端将要上传的文件分成多个固定大小的片段(chunk),例如每个片段的大小为1MB。当用户选择上传文件时,前端发送一个初始请求到服务器,询问服务器当前已上传的文件......
  • springframework中关于bean的装配方式、初始化、实例化流程
    ●bean的配置方式?○xml文件配置○bean的配置范围(scope范围)○bean的延迟加载(applicationContext是立即加载,如果需要延迟加载设置lazy-init为true,在getBean的时候才进行加载,加载实例化完了之后回存储到单例池中去,后续使用该bean直接从单例池中获取即可,本质上该bean还是单例的)......
  • PHP面试题2
    1.$a='b';$b='$a';$c="$b";$d="$$a";$e=$$a;echo$c.PHP_EOL;//$aecho$d.PHP_EOL;//$becho$e.PHP_EOL;//$aif($a==0){echo0;}else{echo1;}//02.浏览器输入url后发生了什么?1.DNS对域名进行解析;2.建立TCP连接(......