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);         var_dump($url_info);         if (!$url_info['host']) {             return false;         }         if (!isset($url_info['port']))             $url_info['port'] = 80;         if (!isset($url_info['query']))             $url_info['query'] = '';         $url_info['request'] = $url_info['path'] . $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';
}
*/
?>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值