首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 通過 HEAD 請求獲取遠程圖片大小

     編輯:PHP 相關知識

傳統獲取遠程圖片大小需下載完整內容再 strlen(),效率極低。本文介紹發送 HTTP HEAD 請求讀取 Content-Length 響應頭的高效方案,附 fsockopen 完整實現與現代替代方案。

核心原理

HTTP HEAD 請求僅返回響應頭,不包含實體內容。服務器對靜態資源通常返回 Content-Length 表示文件大小(字節數)。

fsockopen 底層實現

<?php
function getRemoteFileSize($host, $path, $port = 80, $timeout = 10) {
    $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
    if (!$fp) {
        return ['error' => "$errstr ($errno)"];
    }
    
    // 構造 HEAD 請求
    $out = "HEAD $path HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Connection: Close\r\n\r\n";
    
    fwrite($fp, $out);
    
    $size = null;
    while (!feof($fp)) {
        $header = fgets($fp, 1024);
        if (stripos($header, 'Content-Length:') !== false) {
            $size = (int)trim(substr($header, strpos($header, ':') + 1));
            break; // 找到即可停止讀取
        }
    }
    
    fclose($fp);
    
    return $size !== null ? ['size' => $size] : ['error' => 'Content-Length header not found'];
}

// 使用示例
$result = getRemoteFileSize('www.baidu.com', '/img/baidu_sylogo1.gif');
if (isset($result['size'])) {
    echo "圖片大小: {$result['size']} bytes (" . round($result['size']/1024, 2) . " KB)";
} else {
    echo "錯誤: {$result['error']}";
}
?>

關鍵細節

  1. 請求行:HEAD /path HTTP/1.1 (必須包含 Host 頭)
  2. 換行符:HTTP 規範要求 \r\n (非 \n)
  3. 提前終止:讀到 Content-Length 即 break,不讀取剩餘頭
  4. HTTPS 支持:fsockopen('ssl://host', 443) 或改用 cURL/流上下文

現代替代方案對比

1. cURL (推薦生產環境)

function getSizeCurl($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY => true,      // HEAD 請求
        CURLOPT_HEADER => true,      // 包含頭
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true, // 跟隨重定向
        CURLOPT_TIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => false, // 開發環境
    ]);
    curl_exec($ch);
    $size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
    curl_close($ch);
    return $size > 0 ? $size : null;
}

2. get_headers() (簡單但有陷阱)

$headers = get_headers('https://example.com/image.jpg', 1);
// 返回關聯數組時,Content-Length 可能被合併為數組
$size = $headers['Content-Length'] ?? ($headers['Content-Length'][0] ?? null);
/* 
注意:get_headers() 默認發送 GET 請求!
PHP 7.1+ 可用 stream_context 設置 method:
$ctx = stream_context_create(['http' => ['method' => 'HEAD']]);
$headers = get_headers($url, 1, $ctx);
*/

3. ストリーム上下文 (原生、靈活)

$ctx = stream_context_create([
    'http' => [
        'method' => 'HEAD',
        'timeout' => 10,
        'header' => 'User-Agent: PHP/' . PHP_VERSION,
    ],
    'ssl' => ['verify_peer' => false, 'verify_peer_name' => false]
]);
$fp = fopen($url, 'r', false, $ctx);
$meta = stream_get_meta_data($fp);
fclose($fp);

// 解析 $meta['wrapper_data'] 獲取頭信息
foreach ($meta['wrapper_data'] as $header) {
    if (stripos($header, 'Content-Length:') === 0) {
        return (int)trim(substr($header, 15));
    }
}

方案選型建議

方案優點缺點推薦場景
fsockopen無依賴、底層可控手動處理協議、HTTPS 麻煩教學、極簡環境
cURL功能全、自動重定向、HTTPS 友好、性能好需擴展生產環境首選
stream_context原生、面向對象流操作代碼較繁瑣不想裝 cURL 時
get_headers一行代碼默認 GET、行為不一致快速腳本、已知支持 HEAD

常見陷阱

  • 動態腳本無 Content-Length:PHP 輸出圖片時若無緩衝/未設置頭,可能返回 Transfer-Encoding: chunked
  • CDN/防盜鏈:需攜帶 Referer、User-Agent、Cookie
  • 重定向:HEAD 請求可能不自動跟隨 301/302,cURL 需 CURLOPT_FOLLOWLOCATION
  • 大文件:Content-Length 可能超過 32 位整數範圍,用 float 或 CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (cURL 7.55+)

採用 cURL + HEAD 請求是獲取遠程文件大小的工業級標準做法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved