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

解決 PHP file_get_contents 獲取遠程頁面亂碼問題:GZIP 壓縮與編碼雙重應對

     編輯:PHP 相關知識

file_get_contents 直接讀取 GZIP 壓縮回應會得到亂碼。本文提供三種解決方案:zlib 串流封裝、cURL 自動解壓、手動解壓判斷。

問題根因

伺服器回應 Content-Encoding: gzip,file_get_contents 返回壓縮後的二進位資料,直接輸出即為亂碼。

方案一:zlib:// 串流封裝 (最簡單、推薦)

<?php
$url = 'https://example.com/page';

// 關鍵:加上 compress.zlib:// 前綴
$content = file_get_contents('compress.zlib://' . $url);

// 無論是否壓縮都能正常工作
echo $content;

✅ 優點:零配置、自動偵測、相容非壓縮回應
⚠️ 需求:PHP 編譯時啟用 --with-zlib (預設啟用)

方案二:cURL 自動解壓 (功能最完整)

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

// 使用
$html = curlGet('https://example.com');

方案三:手動偵測 + 解壓 (理解原理、特殊場景)

function fetchWithGzipHandling($url) {
    // 1. 先用 HEAD 請求檢查 Content-Encoding
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY => true,
        CURLOPT_HEADER => true,
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $headResponse = curl_exec($ch);
    curl_close($ch);
    
    $isGzipped = stripos($headResponse, 'Content-Encoding: gzip') !== false;
    
    // 2. 正式請求
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => $isGzipped ? 'gzip' : 'identity',
    ]);
    $content = curl_exec($ch);
    curl_close($ch);
    
    return $content;
}

// 或:讀取前 2 bytes 判斷 GZIP 魔數 (0x1f8b)
function isGzippedContent($content) {
    return strlen($content) >= 2 
        && ord($content[0]) === 0x1f 
        && ord($content[1]) === 0x8b;
}

function autoDecompress($content) {
    if (isGzippedContent($content)) {
        return gzdecode($content); // PHP 5.4+ 內建
        // 舊版:return gzinflate(substr($content, 10, -8));
    }
    return $content;
}

完整編碼處理流程

<?php
function fetchPage($url) {
    // 1. 獲取內容 (自動解壓)
    $content = file_get_contents('compress.zlib://' . $url);
    
    // 2. 編碼偵測與轉換
    $encoding = mb_detect_encoding($content, ['UTF-8', 'GBK', 'BIG5', 'ISO-8859-1'], true);
    
    if ($encoding && $encoding !== 'UTF-8') {
        $content = iconv($encoding, 'UTF-8//IGNORE', $content);
    }
    
    // 3. 強制宣告 UTF-8 (防止瀏覽器誤判)
    header('Content-Type: text/html; charset=UTF-8');
    
    return $content;
}

// 使用
echo fetchPage('https://example.com');

方案比較總結

方案適用場景優點缺點
compress.zlib://簡單 GET、允許 url_fopen最簡潔、自動偵測無法控制逾時、標頭、Cookie
cURL + ENCODING生產環境、複雜需求功能完整、支援 brotli (br)需 cURL 擴充
手動 gzdecode已獲取壓縮資料、特殊處理完全控制需自行偵測

常見編碼問題對照

現象可能原因解決
(鑽石問號)UTF-8 被當作 ISO-8859-1 輸出header('Content-Type: ... charset=UTF-8')
亂碼 (中文變亂碼)GBK/Big5 未轉 UTF-8iconv('GBK', 'UTF-8//IGNORE', $str)
空白/截斷GZIP 未解壓compress.zlib:// 或 CURLOPT_ENCODING
(單一替換字元)iconv 遇到非法字元加 //IGNORE 或 //TRANSLIT
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved