需在不下載完整檔案的情況下取得遠端檔案大小,常用三種方法:file_get_contents (下載全文)、get_headers (HEAD 請求)、fsockopen (原始 Socket)。本文比較三者原理、程式碼、效能與限制。
<?php
$url = 'https://example.com/large.zip';
$content = file_get_contents($url); // 下載整個檔案到記憶體
$size = strlen($content);
echo "Size: $size bytes";
memory_limit。allow_url_fopen = On<?php
$url = 'https://example.com/large.zip';
$headers = get_headers($url, true); // 第二參數 true 回傳關聯陣列
$size = $headers['Content-Length'] ?? null;
if ($size !== null) {
echo "Size: $size bytes (" . round($size/1024/1024, 2) . " MB)";
} else {
echo "無法取得大小 (可能為分塊傳輸或伺服器不回傳 Content-Length)";
}
Transfer-Encoding: chunked 無 Content-Length。allow_url_fopen = On<?php
function get_remote_size($url) {
$parts = parse_url($url);
if (empty($parts['host'])) return false;
$host = $parts['host'];
$port = $parts['port'] ?? ($parts['scheme'] === 'https' ? 443 : 80);
$path = $parts['path'] ?? '/';
if (!empty($parts['query'])) $path .= '?' . $parts['query'];
$timeout = 10;
$fp = @fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$fp) return false;
// HTTP/1.1 需 Host 標頭
$request = "HEAD $path HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";
fwrite($fp, $request);
while (!feof($fp)) {
$line = fgets($fp, 1024);
if (trim($line) === '') break; // 標頭結束
if (stripos($line, 'Content-Length:') === 0) {
fclose($fp);
return (int)trim(substr($line, 15));
}
}
fclose($fp);
return false;
}
// 使用
$size = get_remote_size('https://example.com/file.zip');
if ($size !== false) echo "Size: $size";
else echo "Failed";
allow_url_fopen,完全控制請求細節,可處理特殊協定。stream_socket_client + SSL context,錯誤處理繁瑣。| 指標 | file_get_contents | get_headers | fsockopen |
|---|---|---|---|
| 網路流量 | 完整檔案大小 | ~幾百 Bytes | ~幾百 Bytes |
| 記憶體用量 | 檔案大小 | 極低 | 極低 |
| 執行時間 | 下載時間 | RTT x 1-2 | RTT x 1-2 |
| 支援 HTTPS | 是 | 是 | 需 SSL context |
| 需 allow_url_fopen | 是 | 是 | 否 |
| 適用大檔案 | 否 | 是 | 是 |
| 分塊傳輸支援 | 自動合併 | 無 Content-Length | 無 Content-Length |
Transfer-Encoding: chunked:無法預知大小,只能下載計算或接受未知。Range: bytes=0-0 取得 Content-Range: bytes 0-0/123456 解析總大小。<?php
function get_size_via_range($url) {
$ctx = stream_context_create(['http' => [
'method' => 'HEAD',
'header' => 'Range: bytes=0-0',
]]);
$headers = get_headers($url, true, $ctx);
if (isset($headers['Content-Range'])) {
// bytes 0-0/123456
return (int)substr(strrchr($headers['Content-Range'], '/'), 1);
}
return $headers['Content-Length'] ?? null;
}
get_headers():標準、輕量、PHP 內建。fsockopen 或 stream_socket_client。curl_multi 非阻塞批次發送 HEAD 請求。false/null,記錄日誌、預設值處理。