当前位置:首页 > PHP教程 > php类库 > 列表

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

发布:smiling 来源: PHP粉丝网  添加日期:2019-08-16 10:04:02 浏览: 评论:0 

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

  1. <?php
  2.  
  3. /** 
  4.  
  5.  * User: djunny 
  6.  
  7.  * Date: 2016-04-29 
  8.  
  9.  * Time: 17:18 
  10.  
  11.  * Mail: 199962760@qq.com 
  12.  
  13.  * 支持断点下载的类 
  14.  
  15.  */ 
  16.  
  17. class downloader { 
  18.  
  19.    
  20.  
  21.   /** 
  22.  
  23.    * download file to local path 
  24.  
  25.    * 
  26.  
  27.    * @param    $url 
  28.  
  29.    * @param    $save_file 
  30.  
  31.    * @param int  $speed 
  32.  
  33.    * @param array $headers 
  34.  
  35.    * @param int  $timeout 
  36.  
  37.    * @return bool 
  38.  
  39.    * @throws Exception 
  40.  
  41.    */ 
  42.  
  43.   static function get($url$save_file$speed = 10240, $headers = array(), $timeout = 10) { 
  44.  
  45.     $url_info = self::parse_url($url); 
  46.  
  47.     if (!$url_info['host']) { 
  48.  
  49.       throw new Exception('Url is Invalid'); 
  50.  
  51.     } 
  52.  
  53.    
  54.  
  55.     // default header 
  56.  
  57.     $def_headers = array
  58.  
  59.       'Accept'     => '*/*'
  60.  
  61.       'User-Agent'   => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)'
  62.  
  63.       'Accept-Encoding' => 'gzip, deflate'
  64.  
  65.       'Host'      => $url_info['host'], 
  66.  
  67.       'Connection'   => 'Close'
  68.  
  69.       'Accept-Language' => 'zh-cn'
  70.  
  71.     ); 
  72.  
  73.    
  74.  
  75.     // merge heade 
  76.  
  77.     $headers = array_merge($def_headers$headers); 
  78.  
  79.     // get content length 
  80.  
  81.     $content_length = self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers$timeout); 
  82.  
  83.    
  84.  
  85.     // content length not exist 
  86.  
  87.     if (!$content_length) { 
  88.  
  89.       throw new Exception('Content-Length is Not Exists'); 
  90.  
  91.     } 
  92.  
  93.     // get exists length 
  94.  
  95.     $exists_length = is_file($save_file) ? filesize($save_file) : 0; 
  96.  
  97.     // get tmp data file 
  98.  
  99.     $data_file = $save_file . '.data'
  100.  
  101.     // get tmp data 
  102.  
  103.     $exists_data = is_file($data_file) ? json_decode(file_get_contents($data_file), 1) : array(); 
  104.  
  105.     // check file is valid 
  106.  
  107.     if ($exists_length == $content_length) { 
  108.  
  109.       $exists_data && @unlink($data_file); 
  110.  
  111.       return true; 
  112.  
  113.     } 
  114.  
  115.     // check file is expire 
  116.  
  117.     if ($exists_data['length'] != $content_length || $exists_length > $content_length) { 
  118.  
  119.       $exists_data = array
  120.  
  121.         'length' => $content_length
  122.  
  123.       ); 
  124.  
  125.     } 
  126.  
  127.     // write exists data 
  128.  
  129.     file_put_contents($data_file, json_encode($exists_data)); 
  130.  
  131.    
  132.  
  133.     try { 
  134.  
  135.       $download_status = self::download_content($url_info['host'], $url_info['port'], $url_info['request'], $save_file$content_length$exists_length$speed$headers$timeout); 
  136.  
  137.       if ($download_status) { 
  138.  
  139.         @unlink($data_file); 
  140.  
  141.       } 
  142.  
  143.     } catch (Exception $e) { 
  144.  
  145.       throw new Exception($e->getMessage()); 
  146.  
  147.     } 
  148.  
  149.     return true; 
  150.  
  151.   } 
  152.  
  153.    
  154.  
  155.   /** 
  156.  
  157.    * parse url 
  158.  
  159.    * 
  160.  
  161.    * @param $url 
  162.  
  163.    * @return bool|mixed 
  164.  
  165.    */ 
  166.  
  167.   static function parse_url($url) { 
  168.  
  169.     $url_info = parse_url($url); 
  170.  
  171.     if (!$url_info['host']) { 
  172.  
  173.       return false; 
  174.  
  175.     } 
  176.  
  177.     $url_info['port']  = $url_info['port'] ? $url_info['host'] : 80; 
  178.  
  179.     $url_info['request'] = $url_info['path'] . ($url_info['query'] ? '?' . $url_info['query'] : ''); 
  180.  
  181.     return $url_info
  182.  
  183.   } 
  184.  
  185.    
  186.  
  187.   /** 
  188.  
  189.    * download content by chunk 
  190.  
  191.    * 
  192.  
  193.    * @param $host 
  194.  
  195.    * @param $port 
  196.  
  197.    * @param $url_path 
  198.  
  199.    * @param $headers 
  200.  
  201.    * @param $timeout 
  202.  
  203.    */ 
  204.  
  205.   static function download_content($host$port$url_path$save_file$content_length$range_start$speed, &$headers$timeout) { 
  206.  
  207.     $request = self::build_header('GET'$url_path$headers$range_start); 
  208.  
  209.     $fsocket = @fsockopen($host$port$errno$errstr$timeout); 
  210.  
  211.     stream_set_blocking($fsocket, TRUE); 
  212.  
  213.     stream_set_timeout($fsocket$timeout); 
  214.  
  215.     fwrite($fsocket$request); 
  216.  
  217.     $status = stream_get_meta_data($fsocket); 
  218.  
  219.     if ($status['timed_out']) { 
  220.  
  221.       throw new Exception('Socket Connect Timeout'); 
  222.  
  223.     } 
  224.  
  225.     $is_header_end = 0; 
  226.  
  227.     $total_size  = $range_start
  228.  
  229.     $file_fp    = fopen($save_file'a+'); 
  230.  
  231.     while (!feof($fsocket)) { 
  232.  
  233.       if (!$is_header_end) { 
  234.  
  235.         $line = @fgets($fsocket); 
  236.  
  237.         if (in_array($linearray("\n""\r\n"))) { 
  238.  
  239.           $is_header_end = 1; 
  240.  
  241.         } 
  242.  
  243.         continue
  244.  
  245.       } 
  246.  
  247.       $resp    = fread($fsocket$speed); 
  248.  
  249.       $read_length = strlen($resp); 
  250.  
  251.       if ($resp === false || $content_length < $total_size + $read_length) { 
  252.  
  253.         fclose($fsocket); 
  254.  
  255.         fclose($file_fp); 
  256.  
  257.         throw new Exception('Socket I/O Error Or File Was Changed'); 
  258.  
  259.       } 
  260.  
  261.       $total_size += $read_length
  262.  
  263.       fputs($file_fp$resp); 
  264.  
  265.       // check file end 
  266.  
  267.       if ($content_length == $total_size) { 
  268.  
  269.         break
  270.  
  271.       } 
  272.  
  273.       sleep(1); 
  274.  
  275.       // for test 
  276.  
  277.       //break; 
  278.  
  279.     } 
  280.  
  281.     fclose($fsocket); 
  282.  
  283.     fclose($file_fp); 
  284.  
  285.     return true; 
  286.  
  287.    
  288.  
  289.   } 
  290.  
  291.    
  292.  
  293.   /** 
  294.  
  295.    * get content length 
  296.  
  297.    * 
  298.  
  299.    * @param $host 
  300.  
  301.    * @param $port 
  302.  
  303.    * @param $url_path 
  304.  
  305.    * @param $headers 
  306.  
  307.    * @param $timeout 
  308.  
  309.    * @return int 
  310.  
  311.    */ 
  312.  
  313.   static function get_content_size($host$port$url_path, &$headers$timeout) { 
  314.  
  315.     $request = self::build_header('HEAD'$url_path$headers); 
  316.  
  317.     $fsocket = @fsockopen($host$port$errno$errstr$timeout); 
  318.  
  319.     stream_set_blocking($fsocket, TRUE); 
  320.  
  321.     stream_set_timeout($fsocket$timeout); 
  322.  
  323.     fwrite($fsocket$request); 
  324.  
  325.     $status = stream_get_meta_data($fsocket); 
  326.  
  327.     $length = 0; 
  328.  
  329.     if ($status['timed_out']) { 
  330.  
  331.       return 0; 
  332.  
  333.     } 
  334.  
  335.     while (!feof($fsocket)) { 
  336.  
  337.       $line = @fgets($fsocket); 
  338.  
  339.       if (in_array($linearray("\n""\r\n"))) { 
  340.  
  341.         break
  342.  
  343.       } 
  344.  
  345.       $line = strtolower($line); 
  346.  
  347.       // get location 
  348.  
  349.       if (substr($line, 0, 9) == 'location:') { 
  350.  
  351.         $location = trim(substr($line, 9)); 
  352.  
  353.         $url_info = self::parse_url($location); 
  354.  
  355.         if (!$url_info['host']) { 
  356.  
  357.           return 0; 
  358.  
  359.         } 
  360.  
  361.         fclose($fsocket); 
  362.  
  363.         return self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers$timeout); 
  364.  
  365.       } 
  366.  
  367.       // get content length 
  368.  
  369.       if (strpos($line'content-length:') !== false) { 
  370.  
  371.         list(, $length) = explode('content-length:'$line); 
  372.  
  373.         $length = (int)trim($length); 
  374.  
  375.       } 
  376.  
  377.     } 
  378.  
  379.     fclose($fsocket); 
  380.  
  381.     return $length
  382.  
  383.    
  384.  
  385.   } 
  386.  
  387.    
  388.  
  389.   /** 
  390.  
  391.    * build header for socket 
  392.  
  393.    * 
  394.  
  395.    * @param   $action 
  396.  
  397.    * @param   $url_path 
  398.  
  399.    * @param   $headers 
  400.  
  401.    * @param int $range_start 
  402.  
  403.    * @return string 
  404.  
  405.    */ 
  406.  
  407.   static function build_header($action$url_path, &$headers$range_start = -1) { 
  408.  
  409.     $out = $action . " {$url_path} HTTP/1.0\r\n"
  410.  
  411.     foreach ($headers as $hkey => $hval) { 
  412.  
  413.       $out .= $hkey . ': ' . $hval . "\r\n"
  414.  
  415.     } 
  416.  
  417.     if ($range_start > -1) { 
  418.  
  419.       $out .= "Accept-Ranges: bytes\r\n"
  420.  
  421.       $out .= "Range: bytes={$range_start}-\r\n"
  422.  
  423.     } 
  424.  
  425.     $out .= "\r\n"
  426.  
  427.    
  428.  
  429.     return $out
  430.  
  431.   } 
  432.  
  433.  
  434.    
  435.  
  436.    
  437.  
  438. #use age 
  439.  
  440. /* 
  441.  
  442. try { 
  443.  
  444.   if (downloader::get('http://dzs.aqtxt.com/files/11/23636/201604230358308081.rar', 'test.rar')) { 
  445.  
  446.     //todo 
  447.  
  448.     echo 'Download Succ'; 
  449. //phpfensi.com 
  450.   } 
  451.  
  452. } catch (Exception $e) { 
  453.  
  454.   echo 'Download Failed'; 
  455.  
  456. } 
  457.  
  458. */ 
  459.  
  460. ?> 

Tags: php断点续传 php分块下载

分享到: