经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
php实现大文件断点续传下载实例
来源:cnblogs  作者:mrlime  时间:2019/10/8 9:32:00  对本文有异议

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

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

download.class.php

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


本文转自:https://www.sucaihuo.com/php/277.html 转载请注明出处!

 

原文链接:http://www.cnblogs.com/mrlime/p/11615025.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号