'*/*',
'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';
}
*/
?> 0
0
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。
8
2026.01.15
公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。
44
2026.01.15
(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。
58
2026.01.15
笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。
11
2026.01.15
本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。
65
2026.01.14
热门下载
精品课程





