PHP 關于 文件上傳 下載 斷點續傳問題
讓PHP下載代碼支持斷點續傳 主要靠的 HTTP協議中header? Content-Range來實現
先來說說 HTTP的下載原理
對于HTTP協議,向服務器請求某個文件時,只要發送類似如下的請求即可:
GET /Path/FileName HTTP/1.0
Host:?
www.server.com:80
Accept: **表示接收任何類型的數據。User-Agent表示用戶代理,這個字段可有可無,但強烈建議加上,因為它是服務器統計、追蹤以及識別客戶端的依據。Connection字段中的close表示使用非持久連接。
關于HTTP協議更多的細節可以參考RFC2616(HTTP 1.1)。因為我只是想通過HTTP協議實現文件下載,所以也只看了一部分,并沒有看全。
如果服務器成功收到該請求,并且沒有出現任何錯誤,則會返回類似下面的數據:
HTTP/1.0 200 OK
Content-Length: 13057672
Content-Type: application/octet-stream
Last-Modified: Wed, 10 Oct 2005 00:56:34 GMT
Accept-Ranges: bytes
ETag: "2f38a6cac7cec51:160c"
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Wed, 16 Nov 2005 01:57:54 GMT
Connection: close
下面來解釋下這些返回信息的含義
第一行是協議名稱及版本號,空格后面會有一個三位數的數字,是HTTP協議的響應狀態碼,200表示成功,OK是對狀態碼的簡短文字描述。狀態碼共有5類:
1xx屬于通知類;
2xx屬于成功類;
3xx屬于重定向類;
4xx屬于客戶端錯誤類;
5xx屬于服務端錯誤類。
對 于狀態碼,相信大家對404應該很熟悉,如果向一個服務器請求一個不存在的文件,就會得到該錯誤,通常瀏覽器也會顯示類似“HTTP 404 - 未找到文件”這樣的錯誤。Content-Length字段是一個比較重要的字段,它標明了服務器返回數據的長度,這個長度是不包含HTTP頭長度的。換句話說,我們的請求中并沒有Range字段(后面會說到),表示我們請求的是整個文件,所以Content-Length就是整個文件的大小。其余各字段是一些關于文件和服務器的屬性信息。
以上就是通過HTTP協議實現文件下載的全過程。但還不能實現斷點續傳,而實際上斷點續傳的實現非常簡單,只要在請求中加一個Range字段就可以了。
假如一個文件有1000個字節,那么其范圍就是0-999,則:
Range: bytes=500-??????表示讀取該文件的500-999字節,共500字節。
Range: bytes=500-599???表示讀取該文件的500-599字節,共100字節。
Range還有其它幾種寫法,但上面這兩種是最常用的,對于斷點續傳也足矣了。如果HTTP請求中包含Range字段,那么服務器會返回206(Partial Content),同時HTTP頭中也會有一個相應的Content-Range字段,類似下面的格式:
Content-Range: bytes 500-999/1000
Content-Range字段說明服務器返回了文件的某個范圍及文件的總長度。這時Content-Length字段就不是整個文件的大小了,而是對應文件這個范圍的字節數,這一點一定要注意。
下面來看PHP對斷點續傳支持的演示:
先定義一個函數? getRange() 這個函數用來處理? header中 Range 具體數據的處理
1
/*
* $file_size 文件大小
*/
2
?
function
getRange(
$file_size
){
3
$range
=
isset
(
$_SERVER
[
'
HTTP_RANGE
'
])
?
$_SERVER
[
'
HTTP_RANGE
'
]
:
null
;
4
if
(
!
empty
(
$range
)){
5
$range
=
preg_replace
(
'
/[\s|,].*/
'
,
''
,
$range
);
6
$range
=
explode
(
'
-
'
,
substr
(
$range
,
6
));
7
if
(
count
(
$range
)
<
2
) {
8
$range
[
1
]
=
$file_size
;
9
}
10
$range
=
array_combine
(
array
(
'
start
'
,
'
end
'
)
,
$range
);
11
if
(
empty
(
$range
[
'
start
'
])) {
12
$range
[
'
start
'
]
=
0
;
13
}
14
if
(
!
isset
(
$range
[
'
end
'
])
||
empty
(
$range
[
'
end
'
])) {
15
$range
[
'
end
'
]
=
$file_size
;
16
}
17
return
$range
;
18
}
19
return
null
;
20
}
假設文件的地址為 $file_path
1
$speed
=
512
;
//
此參數為下載最大速度
2
?
$pos
=
strrpos
(
$file_path
,
"
/
"
);
3
?
$file_name
=
substr
(
$file_path
,
$pos
+
1
);
4
$file_size
=
filesize
(
$file_path
);
5
$ranges
=
getRange(
$file_size
);
6
$fh
=
fopen
(
$file_path
,
"
rb
"
);
7
header
(
'
Cache-control: public
'
);
8
header
(
'
Content-Type: application/octet-stream
'
);
9
header
(
'
Content-Disposition: attachment; filename=
'
.
$file_name
);
10
if
(
$ranges
!=
null
) {
11
header
(
'
HTTP/1.1 206 Partial Content
'
);
12
header
(
'
Accept-Ranges: bytes
'
);
13
header
(
sprintf
(
'
Content-Length: %u
'
,
$ranges
[
'
end
'
]
-
$ranges
[
'
start
'
]));
14
header
(
sprintf
(
'
Content-Range: bytes %s-%s/%s
'
,
$ranges
[
'
start
'
]
,
$ranges
[
'
end
'
]
,
$file_size
));
15
fseek
(
$fh
,
sprintf
(
'
%u
'
,
$ranges
[
'
start
'
]));
16
}
else
{
17
header
(
"
HTTP/1.1 200 OK
"
);
18
header
(
sprintf
(
'
Content-Length: %s
'
,
$file_size
));
19
}
20
while
(
!
feof
(
$fh
))
21
{
22
echo
fread
(
$fh
,
round
(
$speed
*
1024
,
0
));
23
ob_flush
();
24
sleep
(
1
);
25
}
26
(
$fh
!=
null
)
&&
fclose
(
$fh
);
基本如此 就可以解決一般性文件的斷點續傳或者下載了
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

