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

PHP 判斷網頁是否啟用 GZIP 壓縮:多種偵測方法與自動處理

     編輯:PHP 相關知識

採集網頁時遇到亂碼常因 GZIP 壓縮。本文提供 HTTP 標頭檢查、內容魔數偵測、cURL 自動解壓三種方案,並整合為智慧型獲取函式。

方法一:HTTP 標頭檢查 (最標準)

<?php
function isGzippedByHeader($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY => true,      // HEAD 請求
        CURLOPT_HEADER => true,      // 返回標頭
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 5,
    ]);
    $response = curl_exec($ch);
    curl_close($ch);
    
    return stripos($response, 'Content-Encoding: gzip') !== false;
}

方法二:內容魔數偵測 (無需額外請求)

GZIP 檔案前 2 位元組固定為 0x1f 0x8b (十進位 31 139):

<?php
function isGzippedByMagic($content) {
    if (strlen($content) < 2) return false;
    $bytes = unpack('C2', $content);
    return $bytes[1] === 0x1f && $bytes[2] === 0x8b;
}

// 實際應用:讀取前 2 bytes 判斷
$url = 'https://www.miercn.com';
$fp = fopen($url, 'rb');
$bin = fread($fp, 2);
fclose($fp);

$bytes = unpack('C2', $bin);
$typeCode = $bytes[1] * 256 + $bytes[2]; // 或直接比對陣列

$isGzip = ($typeCode === 0x1f8b); // 8063

if ($isGzip) {
    $url = 'compress.zlib://' . $url;
}

$html = file_get_contents($url);
$html = iconv('GBK', 'UTF-8', $html);
echo $html;

方法三:cURL 自動解壓 (推薦生產)

function fetchAutoDecompress($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_ENCODING => '',      // 關鍵:接受所有編碼 (gzip, deflate, br)
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP Client)',
    ]);
    
    $content = curl_exec($ch);
    $errno = curl_errno($ch);
    curl_close($ch);
    
    if ($errno) {
        throw new Exception("獲取失敗: " . curl_error($ch));
    }
    return $content;
}

整合:智慧型獲取函式

<?php
function smartFetch($url, $targetEncoding = 'UTF-8') {
    // 策略 1: cURL 自動解壓 (最完整)
    if (function_exists('curl_init')) {
        return fetchAutoDecompress($url);
    }
    
    // 策略 2: file_get_contents + zlib 串流
    if (ini_get('allow_url_fopen')) {
        // 先嘗試 zlib 串流 (自動偵測)
        $content = @file_get_contents('compress.zlib://' . $url);
        if ($content !== false) {
            return convertEncoding($content, $targetEncoding);
        }
        
        // 失敗則嘗試直接讀取
        $content = @file_get_contents($url);
        if ($content !== false) {
            // 檢查是否為 GZIP 內容
            if (isGzippedByMagic($content)) {
                $content = gzdecode($content); // PHP 5.4+
            }
            return convertEncoding($content, $targetEncoding);
        }
    }
    
    throw new Exception("無可用 HTTP 客戶端: allow_url_fopen=Off 且無 cURL");
}

function convertEncoding($content, $targetEncoding) {
    $detected = mb_detect_encoding($content, ['UTF-8', 'GBK', 'BIG5', 'ISO-8859-1'], true);
    if ($detected && $detected !== $targetEncoding) {
        return iconv($detected, $targetEncoding . '//IGNORE', $content);
    }
    return $content;
}

function isGzippedByMagic($content) {
    return strlen($content) >= 2 
        && ord($content[0]) === 0x1f 
        && ord($content[1]) === 0x8b;
}

編碼偵測與轉換最佳實踐

<?php
// 完整流程:獲取 → 解壓 → 編碼偵測 → 轉換 → 輸出
$url = 'https://example.com/page';

try {
    $html = smartFetch($url);
    
    // 強制宣告輸出編碼
    header('Content-Type: text/html; charset=UTF-8');
    echo $html;
} catch (Exception $e) {
    header('Content-Type: text/plain; charset=UTF-8');
    echo '錯誤: ' . $e->getMessage();
}

常見壓縮格式魔數對照

格式魔數 (Hex)魔數 (Decimal)Content-Encoding
GZIP1F 8B31 139gzip
ZLIB (deflate)78 9C / 78 DA / 78 01120 156 / 120 218 / 120 1deflate
BrotliCE B2 / CF B2206 178 / 207 178br
ZSTD28 B5 2F FD40 181 47 253zstd

注意事項

  • CURLOPT_ENCODING => '' 會發送 Accept-Encoding: gzip, deflate, br (視 cURL 版本支援)
  • 某些 CDN 返回 Content-Encoding: gzip 但內容未壓縮,cURL 會自動處理不報錯
  • gzdecode() 需 PHP 5.4+,舊版用 gzinflate(substr($data, 10, -8))
  • 大檔案建議串流處理,避免記憶體耗盡
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved