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

PHP file_get_contents 抓取 Gzip 網頁亂碼的三種解決方案

     編輯:PHP 相關知識

使用 file_get_contents 抓取開啟了 Gzip 壓縮的網頁時,直接輸出會顯示亂碼。判斷依據:響應頭包含 Content-Encoding: gzip。本文提供三種成熟解決方案。

方案一:使用 PHP 內建 zlib 流封裝(最簡潔)

前提:服務器已安裝並啟用 zlib 擴展。

$data = file_get_contents("compress.zlib://" . $url);

PHP 會自動解壓並返回原始內容,無需額外代碼。

方案二:改用 cURL 並啟用自動解壓(推薦)

function curl_get($url, $gzip = false) {
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
    if ($gzip) curl_setopt($curl, CURLOPT_ENCODING, "gzip"); // 關鍵行
    $content = curl_exec($curl);
    curl_close($curl);
    return $content;
}

// 使用
$html = curl_get('https://example.com', true);

優勢:cURL 更穩健,支援 HTTPS、重定向、超時控制、自定義 Header 等複雜場景。

方案三:手寫 gzdecode 解壓函數(無擴展環境)

若環境禁用 zlib 且無 cURL,可用純 PHP 實現 RFC 1952 標準解壓:

function gzdecode($data) {
    $len = strlen($data);
    if ($len < 18 || substr($data, 0, 2) !== "\x1f\x8b") return null; // 非 GZIP

    $method = ord($data[2]);
    $flags  = ord($data[3]);
    if ($flags & 31 != $flags) return null; // 保留位檢查

    $mtime     = unpack("V", substr($data, 4, 4)); $mtime = $mtime[1];
    $xfl       = $data[8];
    $os        = $data[8];
    $headerlen = 10;
    $extralen  = 0;
    $extra     = "";

    // 處理 FEXTRA
    if ($flags & 4) {
        if ($len - $headerlen - 2 < 8) return false;
        $extralen = unpack("v", substr($data, 8, 2)); $extralen = $extralen[1];
        if ($len - $headerlen - 2 - $extralen < 8) return false;
        $extra = substr($data, 10, $extralen);
        $headerlen += 2 + $extralen;
    }

    // 處理 FNAME
    $filenamelen = 0; $filename = "";
    if ($flags & 8) {
        if ($len - $headerlen - 1 < 8) return false;
        $filenamelen = strpos(substr($data, 8 + $extralen), chr(0));
        if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) return false;
        $filename = substr($data, $headerlen, $filenamelen);
        $headerlen += $filenamelen + 1;
    }

    // 處理 FCOMMENT
    $commentlen = 0; $comment = "";
    if ($flags & 16) {
        if ($len - $headerlen - 1 < 8) return false;
        $commentlen = strpos(substr($data, 8 + $extralen + $filenamelen), chr(0));
        if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) return false;
        $comment = substr($data, $headerlen, $commentlen);
        $headerlen += $commentlen + 1;
    }

    // 處理 FHCRC
    $headercrc = "";
    if ($flags & 1) {
        if ($len - $headerlen - 2 < 8) return false;
        $calccrc = crc32(substr($data, 0, $headerlen)) & 0xffff;
        $headercrc = unpack("v", substr($data, $headerlen, 2)); $headercrc = $headercrc[1];
        if ($headercrc != $calccrc) return false;
        $headerlen += 2;
    }

    // 解壓主體
    $datacrc = unpack("V", substr($data, -8, 4)); $datacrc = $datacrc[1];
    $isize   = unpack("V", substr($data, -4));     $isize   = $isize[1];
    $bodylen = $len - $headerlen - 8;
    if ($bodylen < 1) return null;

    $body = substr($data, $headerlen, $bodylen);
    $data = "";
    if ($bodylen > 0) {
        switch ($method) {
            case 8: $data = gzinflate($body); break; // DEFLATE
            default: return false;
        }
    }

    // 校驗 CRC32 與長度
    if ($isize != strlen($data) || crc32($data) != $datacrc) return false;
    return $data;
}

// 使用
$html = file_get_contents('https://www.example.com/');
$html = gzdecode($html);

方案選擇建議

方案適用場景優點缺點
zlib:// 流環境有 zlib,代碼極簡一行代碼,無依賴無法控制超時/重定向
cURL + ENCODING生產環境首選功能全、穩健、自動處理多種編碼需 cURL 擴展
手寫 gzdecode極受限環境純 PHP,零擴展依賴代碼長、維護難、性能較差

實際項目中強烈建議方案二,兼容性最好且代碼可維護性最高。

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