Heim  >  Artikel  >  Backend-Entwicklung  >  php支持断点续传、分块下载的类_php技巧

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

WBOY
WBOYOriginal
2016-05-16 19:53:371154Durchsuche

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

<&#63;php
 
/**
 * User: djunny
 * Date: 2016-04-29
 * Time: 17:18
 * Mail: 199962760@qq.com
 * 支持断点下载的类
 */
class downloader {
 
  /**
   * download file to local path
   *
   * @param    $url
   * @param    $save_file
   * @param int  $speed
   * @param array $headers
   * @param int  $timeout
   * @return bool
   * @throws Exception
   */
  static function get($url, $save_file, $speed = 10240, $headers = array(), $timeout = 10) {
    $url_info = self::parse_url($url);
    if (!$url_info['host']) {
      throw new Exception('Url is Invalid');
    }
 
    // default header
    $def_headers = array(
      'Accept'     => '*/*',
      'User-Agent'   => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
      'Accept-Encoding' => 'gzip, deflate',
      'Host'      => $url_info['host'],
      'Connection'   => 'Close',
      'Accept-Language' => 'zh-cn',
    );
 
    // merge heade
    $headers = array_merge($def_headers, $headers);
    // get content length
    $content_length = self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers, $timeout);
 
    // content length not exist
    if (!$content_length) {
      throw new Exception('Content-Length is Not Exists');
    }
    // get exists length
    $exists_length = is_file($save_file) &#63; filesize($save_file) : 0;
    // get tmp data file
    $data_file = $save_file . '.data';
    // get tmp data
    $exists_data = is_file($data_file) &#63; json_decode(file_get_contents($data_file), 1) : array();
    // check file is valid
    if ($exists_length == $content_length) {
      $exists_data && @unlink($data_file);
      return true;
    }
    // check file is expire
    if ($exists_data['length'] != $content_length || $exists_length > $content_length) {
      $exists_data = array(
        'length' => $content_length,
      );
    }
    // write exists data
    file_put_contents($data_file, json_encode($exists_data));
 
    try {
      $download_status = self::download_content($url_info['host'], $url_info['port'], $url_info['request'], $save_file, $content_length, $exists_length, $speed, $headers, $timeout);
      if ($download_status) {
        @unlink($data_file);
      }
    } catch (Exception $e) {
      throw new Exception($e->getMessage());
    }
    return true;
  }
 
  /**
   * parse url
   *
   * @param $url
   * @return bool|mixed
   */
  static function parse_url($url) {
    $url_info = parse_url($url);
    if (!$url_info['host']) {
      return false;
    }
    $url_info['port']  = $url_info['port'] &#63; $url_info['host'] : 80;
    $url_info['request'] = $url_info['path'] . ($url_info['query'] &#63; '&#63;' . $url_info['query'] : '');
    return $url_info;
  }
 
  /**
   * download content by chunk
   *
   * @param $host
   * @param $port
   * @param $url_path
   * @param $headers
   * @param $timeout
   */
  static function download_content($host, $port, $url_path, $save_file, $content_length, $range_start, $speed, &$headers, $timeout) {
    $request = self::build_header('GET', $url_path, $headers, $range_start);
    $fsocket = @fsockopen($host, $port, $errno, $errstr, $timeout);
    stream_set_blocking($fsocket, TRUE);
    stream_set_timeout($fsocket, $timeout);
    fwrite($fsocket, $request);
    $status = stream_get_meta_data($fsocket);
    if ($status['timed_out']) {
      throw new Exception('Socket Connect Timeout');
    }
    $is_header_end = 0;
    $total_size  = $range_start;
    $file_fp    = fopen($save_file, 'a+');
    while (!feof($fsocket)) {
      if (!$is_header_end) {
        $line = @fgets($fsocket);
        if (in_array($line, array("\n", "\r\n"))) {
          $is_header_end = 1;
        }
        continue;
      }
      $resp    = fread($fsocket, $speed);
      $read_length = strlen($resp);
      if ($resp === false || $content_length < $total_size + $read_length) {
        fclose($fsocket);
        fclose($file_fp);
        throw new Exception('Socket I/O Error Or File Was Changed');
      }
      $total_size += $read_length;
      fputs($file_fp, $resp);
      // check file end
      if ($content_length == $total_size) {
        break;
      }
      sleep(1);
      // for test
      //break;
    }
    fclose($fsocket);
    fclose($file_fp);
    return true;
 
  }
 
  /**
   * get content length
   *
   * @param $host
   * @param $port
   * @param $url_path
   * @param $headers
   * @param $timeout
   * @return int
   */
  static function get_content_size($host, $port, $url_path, &$headers, $timeout) {
    $request = self::build_header('HEAD', $url_path, $headers);
    $fsocket = @fsockopen($host, $port, $errno, $errstr, $timeout);
    stream_set_blocking($fsocket, TRUE);
    stream_set_timeout($fsocket, $timeout);
    fwrite($fsocket, $request);
    $status = stream_get_meta_data($fsocket);
    $length = 0;
    if ($status['timed_out']) {
      return 0;
    }
    while (!feof($fsocket)) {
      $line = @fgets($fsocket);
      if (in_array($line, array("\n", "\r\n"))) {
        break;
      }
      $line = strtolower($line);
      // get location
      if (substr($line, 0, 9) == 'location:') {
        $location = trim(substr($line, 9));
        $url_info = self::parse_url($location);
        if (!$url_info['host']) {
          return 0;
        }
        fclose($fsocket);
        return self::get_content_size($url_info['host'], $url_info['port'], $url_info['request'], $headers, $timeout);
      }
      // get content length
      if (strpos($line, 'content-length:') !== false) {
        list(, $length) = explode('content-length:', $line);
        $length = (int)trim($length);
      }
    }
    fclose($fsocket);
    return $length;
 
  }
 
  /**
   * build header for socket
   *
   * @param   $action
   * @param   $url_path
   * @param   $headers
   * @param int $range_start
   * @return string
   */
  static function build_header($action, $url_path, &$headers, $range_start = -1) {
    $out = $action . " {$url_path} HTTP/1.0\r\n";
    foreach ($headers as $hkey => $hval) {
      $out .= $hkey . ': ' . $hval . "\r\n";
    }
    if ($range_start > -1) {
      $out .= "Accept-Ranges: bytes\r\n";
      $out .= "Range: bytes={$range_start}-\r\n";
    }
    $out .= "\r\n";
 
    return $out;
  }
}
 
 
#use age
/*
try {
  if (downloader::get('http://dzs.aqtxt.com/files/11/23636/201604230358308081.rar', 'test.rar')) {
    //todo
    echo 'Download Succ';
  }
} catch (Exception $e) {
  echo 'Download Failed';
}
*/
&#63;>

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

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn