本文是为大家分享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'],$content_length,$exists_length,$speed,$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,$range_start,&$headers,$timeout) {
$request = self::build_header('GET',$range_start);
$fsocket = @fsockopen($host,$errno,$errstr,$timeout);
stream_set_blocking($fsocket,TRUE);
stream_set_timeout($fsocket,$timeout);
fwrite($fsocket,$request);
$status = streamgetMeta_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,$timeout) {
$request = self::build_header('HEAD',$headers);
$fsocket = @fsockopen($host,$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,"\r\n"))) {
break;
}
$line = strtolower($line);
// get location
if (substr($line,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'],$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,$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';
}
/
?>
以上就是本文的全部内容,希望对大家的学习有所帮助。