日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

php 远程下载大文件,php下载远程文件(支持断点续传,支持超大文件)

發布時間:2025/3/15 php 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php 远程下载大文件,php下载远程文件(支持断点续传,支持超大文件) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

斷點下載的原理:http請求頭添加Range參數告訴文件服務器端需要的字節范圍

例如1個文本文件的字節為1000,

第一次請求Range: bytes=0-500

第二次請求Range: bytes=501-1000

通過每次的請求將返回的流追加寫入到文件。

注意的項目:斷點下載服務器端的每次只返回字節傳輸的范圍的字節流,同時返回的狀態碼應該為206。

以下是我封裝的php下載遠程文件,可以通過命令行執行,也可以通過fpm執行,由于web服務器存在執行超時的問題,代碼中做了重復執行繼續斷點下載,超時后再次執行即可,解決大文件下載超時問題。例如我沒有服務器,只有虛擬主機,就可以用這個腳本來下載超大文件。<?php

class?download

{

/**

*?遠程文件的路徑

*?@var?string

*/

private?$siteUrl?=?'';

/**

*?分片下載大小

*?@var?int

*/

private?$burstBytes?=?2048;

/**

*?設置遠程下載文件的路徑

*?@param?string?$url?遠程文件的路徑

*?@return?$this

*/

public?function?setUrl($url)

{

$this->siteUrl?=?$url;

return?$this;

}

/**

*?設置分段下載字節大小

*?@param?int?$byte?字節大小

*?@return?$this

*/

public?function?setBurst($byte)

{

$this->burstBytes?=?$byte;

return?$this;

}

/**

*?獲取遠程文件的信息

*?@return?array

*?@throws?Exception

*/

private?function?getSiteFiLeInfo()

{

if?(!$this->siteUrl)

{

throw?new?Exception('請先設置遠程文件url!');

}

$responseHeader?=?get_headers($this->siteUrl,?1);

if?(!$responseHeader)

{

throw?new?Exception('獲取遠程文件信息失敗!');

}

if?(!empty($responseHeader['Location']))

{

//處理文件下載302問題

$this->siteUrl?=?$responseHeader['Location'];

return?$this->getSiteFiLeInfo();

}

return?$responseHeader;

}

/**

*?保存文件到本地

*?@param?string?$fileName?保存到本地的文件名稱

*?@throws

*/

public?function?saveFile($fileName)

{

//獲取遠程文件的信息

$siteFileInfo?=?$this->getSiteFiLeInfo();

$siteFileLength?=?$siteFileInfo['Content-Length']????0;

//根據文件是否存在創建文件句柄、計算斷點下載開始字節

$fd?=?null;

if?(file_exists($fileName))

{

$fd?=?fopen($fileName,?'ab');

}

else

{

$fd?=?fopen($fileName,?'wb');

}

if?(!$fd)

{

throw?new?Exception('創建或打開本地文件失敗!');

}

//加上文件鎖,防止刷新搶占資源句柄

if?(!flock($fd,?LOCK_EX?|?LOCK_NB))

{

throw?new?Exception('已有相關進程操作執行下載本文件!');

}

//檢查文件是否已經下載完成

$fileSize?=?filesize($fileName);

if?($fileSize?&&?$fileSize?>=?$siteFileLength)

{

throw?new?Exception('原文件已下載完成,請勿重復下載!');

}

//計算斷點下載結束字節

$sByte?=?$fileSize;

$eByte?=?$sByte?+?$this->burstBytes;

//循環下載文件

while?(true)

{

//文件下載完成

if?($fileSize?>=?$siteFileLength)

{

fclose($fd);

break;

}

//傳遞分片范圍

$xRange?=?"{$sByte}-$eByte";

//請求curl

$result?=?$this->curl($xRange);

//檢查是否正常請求

$code?=?$result['code']????0;

if?(!$code)

{

throw?new?Exception('Http請求異常!');

}

if?($code?!=?206)

{

throw?new?Exception('Http狀態碼異常,可能不支持斷點的資源或已完成下載!');

}

//返回流長度

$streamLength?=?$result['length']????0;

//返回流內容

$streamContent?=?$result['stream']????'';

if?($streamLength?>?0)

{

file_put_contents('log.txt',?$xRange?.?PHP_EOL,?FILE_APPEND);

$saveRes?=?fwrite($fd,?$streamContent);

if?(!$saveRes)

{

throw?new?Exception('寫入流到文件失敗!');

}

if?($saveRes?!=?$streamLength)

{

//講道理這種情況基本不會遇到,除非分段數設置過大,暫時未做兼容處理,重新執行就行

throw?new?Exception('數據異常:返回大小和寫入大小不一致!');

}

//遞增range

$sByte?=?$eByte?+?1;

$eByte?=?$sByte?+?$this->burstBytes;

//記錄文件大小

$fileSize?=?$fileSize?+?$saveRes;

}

}

}

/**

*?獲取下載文件流

*?@param?string?$range?分片字節范圍

*?@param?array?$header?Http請求頭

*?@return?array

*?@throws

*/

private?function?curl($range,?$header?=?[])

{

$ch?=?curl_init();

curl_setopt($ch,?CURLOPT_URL,?$this->siteUrl);

curl_setopt($ch,?CURLOPT_RETURNTRANSFER,?1);

curl_setopt($ch,?CURLOPT_CUSTOMREQUEST,?'GET');

curl_setopt($ch,?CURLOPT_HEADER,?TRUE);

//設置關閉SSL

curl_setopt($ch,?CURLOPT_SSL_VERIFYPEER,?0);

curl_setopt($ch,?CURLOPT_SSL_VERIFYHOST,?0);

//設置分片

curl_setopt($ch,?CURLOPT_RANGE,?$range);

//設置header

if?($header)

{

curl_setopt($ch,?CURLOPT_HTTPHEADER,?$header);

}

//執行請求

$response?=?curl_exec($ch);

if?(curl_errno($ch))

{

throw?new?Exception('下載文件異常:'?.?curl_error($ch));

}

//提取response_header和response_body

$headSize?=?curl_getinfo($ch,?CURLINFO_HEADER_SIZE);

$httpHeader?=?substr($response,?0,?$headSize);

if?(!$httpHeader)

{

throw?new?Exception('下載文件異常:未獲取到響應頭');

}

$fileStream?=?substr($response,?$headSize);

//解析header

$length?=?$this->getResHeaderValue('Content-Length',?$httpHeader);

$httpCode?=?$this->getResHeaderValue('Http-Code',?$httpHeader);

curl_close($ch);

//返回

return?[

'code'?=>?$httpCode,

'length'?=>?$length,

'stream'?=>?$fileStream,

];

}

/**

*?獲取響應頭某個Key的值

*?@param?string?$key?header頭的key

*?@param?string?$responseHead?header頭字符串

*?@return?string

*/

private?function?getResHeaderValue($key,?$responseHead)

{

$value?=?'';

$headArr?=?explode("\r\n",?$responseHead);

foreach?($headArr?as?$loop)

{

if?($key?==?'Http-Code')

{

if?(preg_match('/HTTP\/1\.[0-9]{1}?([0-9]{3})/',?$loop,?$matches))

{

return?$matches['1'];

}

}

else

{

if?(strpos($loop,?$key)?!==?false)

{

$value?=?trim(str_replace($key?.?':',?'',?$loop));

}

}

}

return?$value;

}

}

//設置下載文件的url

$url?=?'https://www.gaojiufeng.cn/demo/1.tar.gz';

//設置分段下載的字節大小

$burst?=?4048;

//設置保存到服務器本地的文件名

$filename?=?'11.tar.gz';

try

{

//初始化下載器

$download?=?new?download();

//開始下載

$download->setUrl($url)->setBurst($burst)->saveFile($filename);

}

catch?(Exception?$exception)

{

var_dump($exception->getMessage());

}

腳本是單進程下載文件,如果你愿意可以修改為curl批量請求,每個請求執行一個范圍,保存為多個文件,最后合并文件即可。

總結

以上是生活随笔為你收集整理的php 远程下载大文件,php下载远程文件(支持断点续传,支持超大文件)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。