欢迎来到福编程网,本站提供各种互联网专业知识!

php支持断点续传、分块下载的类

发布时间:2016-05-02 作者:deajunny 来源:转载
这篇文章主要介绍了php支持断点续传、分块下载的类的相关资料,需要的朋友可以参考下

本文是为大家分享php支持断点续传、分块下载的类,供大家参考,具体内容如下

代码
  1. <?php
  2. /**
  3. * User: djunny
  4. * Date: 2016-04-29
  5. * Time: 17:18
  6. * Mail: 199962760@qq.com
  7. * 支持断点下载的类
  8. */
  9. class downloader {
  10. /**
  11. * download file to local path
  12. *
  13. * @param $url
  14. * @param $save_file
  15. * @param int $speed
  16. * @param array $headers
  17. * @param int $timeout
  18. * @return bool
  19. * @throws Exception
  20. */
  21. static function get($url, $save_file, $speed = 10240, $headers = array(), $timeout = 10) {
  22. $url_info = self::parse_url($url);
  23. if (!$url_info['host']) {
  24. throw new Exception('Url is Invalid');
  25. }
  26. // default header
  27. $def_headers = array(
  28. 'Accept' => '*/*',
  29. 'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  30. 'Accept-Encoding' => 'gzip, deflate',
  31. 'Host' => $url_info['host'],
  32. 'Connection' => 'Close',
  33. 'Accept-Language' => 'zh-cn',
  34. );
  35. // merge heade
  36. $headers = array_merge($def_headers, $headers);
  37. // get content length
  38. $content_length = self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers, $timeout);
  39. // content length not exist
  40. if (!$content_length) {
  41. throw new Exception('Content-Length is Not Exists');
  42. }
  43. // get exists length
  44. $exists_length = is_file($save_file) ? filesize($save_file) : 0;
  45. // get tmp data file
  46. $data_file = $save_file . '.data';
  47. // get tmp data
  48. $exists_data = is_file($data_file) ? json_decode(file_get_contents($data_file), 1) : array();
  49. // check file is valid
  50. if ($exists_length == $content_length) {
  51. $exists_data && @unlink($data_file);
  52. return true;
  53. }
  54. // check file is expire
  55. if ($exists_data['length'] != $content_length || $exists_length > $content_length) {
  56. $exists_data = array(
  57. 'length' => $content_length,
  58. );
  59. }
  60. // write exists data
  61. file_put_contents($data_file, json_encode($exists_data));
  62. try {
  63. $download_status = self::download_content($url_info['host'], $url_info['port'], $url_info['request'], $save_file, $content_length, $exists_length, $speed, $headers, $timeout);
  64. if ($download_status) {
  65. @unlink($data_file);
  66. }
  67. } catch (Exception $e) {
  68. throw new Exception($e->getMessage());
  69. }
  70. return true;
  71. }
  72. /**
  73. * parse url
  74. *
  75. * @param $url
  76. * @return bool|mixed
  77. */
  78. static function parse_url($url) {
  79. $url_info = parse_url($url);
  80. if (!$url_info['host']) {
  81. return false;
  82. }
  83. $url_info['port'] = $url_info['port'] ? $url_info['host'] : 80;
  84. $url_info['request'] = $url_info['path'] . ($url_info['query'] ? '?' . $url_info['query'] : '');
  85. return $url_info;
  86. }
  87. /**
  88. * download content by chunk
  89. *
  90. * @param $host
  91. * @param $port
  92. * @param $url_path
  93. * @param $headers
  94. * @param $timeout
  95. */
  96. static function download_content($host, $port, $url_path, $save_file, $content_length, $range_start, $speed, &$headers, $timeout) {
  97. $request = self::build_header('GET', $url_path, $headers, $range_start);
  98. $fsocket = @fsockopen($host, $port, $errno, $errstr, $timeout);
  99. stream_set_blocking($fsocket, TRUE);
  100. stream_set_timeout($fsocket, $timeout);
  101. fwrite($fsocket, $request);
  102. $status = stream_get_meta_data($fsocket);
  103. if ($status['timed_out']) {
  104. throw new Exception('Socket Connect Timeout');
  105. }
  106. $is_header_end = 0;
  107. $total_size = $range_start;
  108. $file_fp = fopen($save_file, 'a+');
  109. while (!feof($fsocket)) {
  110. if (!$is_header_end) {
  111. $line = @fgets($fsocket);
  112. if (in_array($line, array("n", "rn"))) {
  113. $is_header_end = 1;
  114. }
  115. continue;
  116. }
  117. $resp = fread($fsocket, $speed);
  118. $read_length = strlen($resp);
  119. if ($resp === false || $content_length < $total_size + $read_length) {
  120. fclose($fsocket);
  121. fclose($file_fp);
  122. throw new Exception('Socket I/O Error Or File Was Changed');
  123. }
  124. $total_size += $read_length;
  125. fputs($file_fp, $resp);
  126. // check file end
  127. if ($content_length == $total_size) {
  128. break;
  129. }
  130. sleep(1);
  131. // for test
  132. //break;
  133. }
  134. fclose($fsocket);
  135. fclose($file_fp);
  136. return true;
  137. }
  138. /**
  139. * get content length
  140. *
  141. * @param $host
  142. * @param $port
  143. * @param $url_path
  144. * @param $headers
  145. * @param $timeout
  146. * @return int
  147. */
  148. static function get_content_size($host, $port, $url_path, &$headers, $timeout) {
  149. $request = self::build_header('HEAD', $url_path, $headers);
  150. $fsocket = @fsockopen($host, $port, $errno, $errstr, $timeout);
  151. stream_set_blocking($fsocket, TRUE);
  152. stream_set_timeout($fsocket, $timeout);
  153. fwrite($fsocket, $request);
  154. $status = stream_get_meta_data($fsocket);
  155. $length = 0;
  156. if ($status['timed_out']) {
  157. return 0;
  158. }
  159. while (!feof($fsocket)) {
  160. $line = @fgets($fsocket);
  161. if (in_array($line, array("n", "rn"))) {
  162. break;
  163. }
  164. $line = strtolower($line);
  165. // get location
  166. if (substr($line, 0, 9) == 'location:') {
  167. $location = trim(substr($line, 9));
  168. $url_info = self::parse_url($location);
  169. if (!$url_info['host']) {
  170. return 0;
  171. }
  172. fclose($fsocket);
  173. return self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers, $timeout);
  174. }
  175. // get content length
  176. if (strpos($line, 'content-length:') !== false) {
  177. list(, $length) = explode('content-length:', $line);
  178. $length = (int)trim($length);
  179. }
  180. }
  181. fclose($fsocket);
  182. return $length;
  183. }
  184. /**
  185. * build header for socket
  186. *
  187. * @param $action
  188. * @param $url_path
  189. * @param $headers
  190. * @param int $range_start
  191. * @return string
  192. */
  193. static function build_header($action, $url_path, &$headers, $range_start = -1) {
  194. $out = $action . " {$url_path} HTTP/1.0rn";
  195. foreach ($headers as $hkey => $hval) {
  196. $out .= $hkey . ': ' . $hval . "rn";
  197. }
  198. if ($range_start > -1) {
  199. $out .= "Accept-Ranges: bytesrn";
  200. $out .= "Range: bytes={$range_start}-rn";
  201. }
  202. $out .= "rn";
  203. return $out;
  204. }
  205. }
  206. #use age
  207. /*
  208. try {
  209. if (downloader::get('http://dzs.aqtxt.com/files/11/23636/201604230358308081.rar', 'test.rar')) {
  210. //todo
  211. echo 'Download Succ';
  212. }
  213. } catch (Exception $e) {
  214. echo 'Download Failed';
  215. }
  216. */
  217. ?>

以上就是本文的全部内容,希望对大家的学习有所帮助。

相关推荐

返回顶部