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


Posted in PHP onMay 02, 2016

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

<?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) ? filesize($save_file) : 0;
    // get tmp data file
    $data_file = $save_file . '.data';
    // get tmp data
    $exists_data = is_file($data_file) ? 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'] ? $url_info['host'] : 80;
    $url_info['request'] = $url_info['path'] . ($url_info['query'] ? '?' . $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';
}
*/
?>

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

PHP 相关文章推荐
浅谈php serialize()与unserialize()的用法
Jun 05 PHP
PHP json_encode中文乱码问题的解决办法
Sep 09 PHP
php从文件夹随机读取文件的方法
Jun 01 PHP
详解PHP中的PDO类
Jul 06 PHP
如何使用Gitblog和Markdown建自己的博客
Jul 31 PHP
基于JQuery+PHP编写砸金蛋中奖程序
Sep 08 PHP
CodeIgniter基于Email类发邮件的方法
Mar 29 PHP
PHP模板引擎Smarty之配置文件在模板变量中的使用方法示例
Apr 11 PHP
cakephp2.X多表联合查询join及使用分页查询的方法
Feb 23 PHP
phpMyAdmin无法登陆的解决方法
Apr 27 PHP
php微信开发之关键词回复功能
Jun 13 PHP
laravel 解决paginate查询多个字段报错的问题
Oct 22 PHP
php数组分页实现方法
Apr 30 #PHP
thinkPHP使用pclzip打包备份mysql数据库的方法
Apr 30 #PHP
php打包压缩文件之ZipArchive方法用法分析
Apr 30 #PHP
php使用pclzip类实现文件压缩的方法(附pclzip类下载地址)
Apr 30 #PHP
php简单实现数组分页的方法
Apr 30 #PHP
php简单创建zip压缩文件的方法
Apr 30 #PHP
Yii2 rbac权限控制操作步骤实例教程
Apr 29 #PHP
You might like
PHP得到某段时间区间的时间戳 php定时任务
2012/04/12 PHP
php递归使用示例(php递归函数)
2014/02/14 PHP
php curl模拟post请求和提交多维数组的示例代码
2015/11/19 PHP
laravel自定义分页效果
2017/07/23 PHP
在线编辑器中换行与内容自动提取
2009/04/24 Javascript
Jquery判断IE6等浏览器的代码
2011/04/05 Javascript
Javascript 中 null、NaN和undefined的区别总结
2013/04/10 Javascript
jquery查找tr td 示例模拟
2014/05/08 Javascript
基于NodeJS的前后端分离的思考与实践(四)安全问题解决方案
2014/09/26 NodeJs
JS代码防止SQL注入的方法(超简单)
2016/04/12 Javascript
JavaScript第一篇之实现按钮全选、功能
2016/08/21 Javascript
JavaScript数组复制详解
2017/02/02 Javascript
配置一个vue3.0项目的完整步骤
2019/04/26 Javascript
简单通过settimeout看javascript的运行机制
2019/05/10 Javascript
JS数组方法push()、pop()用法实例分析
2020/01/18 Javascript
Vue使用axios引起的后台session不同操作
2020/08/14 Javascript
Python mutiprocessing多线程池pool操作示例
2019/01/30 Python
Python 数据库操作 SQLAlchemy的示例代码
2019/02/18 Python
基于Python获取docx/doc文件内容代码解析
2020/02/17 Python
英国著名的小众美容品牌网站:Alyaka
2017/08/08 全球购物
奥地利票务门户网站:oeticket.com
2019/12/31 全球购物
自我鉴定怎么写
2013/12/05 职场文书
英文简历中的自我评价用语
2013/12/09 职场文书
劳动之星获奖感言
2014/02/01 职场文书
求职自荐信怎么写
2014/03/06 职场文书
2014年十一国庆向国旗敬礼寄语
2014/04/11 职场文书
《春雨》教学反思
2014/04/24 职场文书
大学生求职计划书
2014/04/30 职场文书
保护黄河倡议书
2014/05/16 职场文书
党员“四风”方面存在问题及整改措施
2014/09/24 职场文书
试用期旷工辞退通知书
2015/04/17 职场文书
上帝也疯狂观后感
2015/06/09 职场文书
“学党章、守党纪、讲党规”学习心得体会
2016/01/14 职场文书
Nginx优化服务之网页压缩的实现方法
2021/03/31 Servers
Mysql实现主从配置和多主多从配置
2021/06/02 MySQL
Vue的列表之渲染,排序,过滤详解
2022/02/24 Vue.js