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

PHP file_get_contents 逾時處理方案:stream context 與 cURL 兩種實現

     編輯:PHP 相關知識

file_get_contents 預設無逾時控制,跨網段請求易導致腳本卡死。本文提供 stream context 與 cURL 兩種逾時解決方案,並整合為通用函式。

問題場景

  • 跨機房/跨國請求 (中國↔美國) 延遲高、丟包率高
  • 目標服務無回應導致 PHP 腳本長時間阻塞
  • 預設 60 秒逾時不符合業務 SLA 需求

方案一:stream_context_create (file_get_contents 原生)

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

$ctx = stream_context_create([
    'http' => [
        'timeout' => 10,           // 總逾時秒數 (含連線+傳輸)
        'method' => 'GET',
        'header' => 'User-Agent: PHP Client\r\n',
        'follow_location' => 1,
        'max_redirects' => 5,
    ],
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
    ]
]);

$result = @file_get_contents($url, false, $ctx);

if ($result !== false) {
    var_dump($result);
} else {
    // 區分錯誤類型
    $error = error_get_last();
    echo "獲取失敗: " . ($error['message'] ?? '未知錯誤');
}

關鍵參數說明

參數說明單位
timeout讀取/寫入/連線總逾時秒
methodHTTP 方法-
header自定標頭 (字串或陣列)-
follow_location自動追蹤重定向0/1
max_redirects最大重定向次數整數
protocol_versionHTTP 版本 (1.0/1.1)-

方案二:cURL 精確逾時控制 (推薦生產環境)

function zhozGetContents($url, $second = 5) {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_HEADER => 0,
        CURLOPT_TIMEOUT => $second,           // 總執行逾時 (秒)
        CURLOPT_CONNECTTIMEOUT => min(5, $second), // 連線逾時 (秒)
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP Client)',
    ]);
    
    $content = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
    
    if ($errno) {
        // 區分逾時類型
        if ($errno === CURLE_OPERATION_TIMEDOUT) {
            throw new Exception("請求逾時 ({$second}s): $url");
        } elseif ($errno === CURLE_COULDNT_CONNECT) {
            throw new Exception("無法連線: $url");
        }
        throw new Exception("cURL 錯誤 [$errno]: $error");
    }
    
    $httpCode = $info['http_code'];
    if ($httpCode >= 400) {
        throw new Exception("HTTP 錯誤 $httpCode: $url");
    }
    
    return $content;
}

// 使用範例
try {
    echo date('Y-m-d H:i:s') . "\n";
    $buffer = zhozGetContents('https://zhoz.com/zhoz.php', 10);
    echo date('Y-m-d H:i:s') . "\n";
    
    if (empty($buffer)) {
        echo "回應為空\n";
    } else {
        echo "獲取成功,長度: " . strlen($buffer) . "\n";
    }
} catch (Exception $e) {
    echo "錯誤: " . $e->getMessage() . "\n";
}

毫秒級精確控制 (PHP 5.2.3+ / cURL 7.16.2+)

curl_setopt_array($ch, [
    CURLOPT_TIMEOUT_MS => 5000,        // 總逾時 5000ms
    CURLOPT_CONNECTTIMEOUT_MS => 2000, // 連線逾時 2000ms
]);

整合通用函式:環境自適應

function vitaGetUrlContent($url, $timeout = 10) {
    // 策略 1: cURL 可用時優先使用 (功能最完整)
    if (function_exists('curl_init')) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_CONNECTTIMEOUT => min(5, $timeout),
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 5,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP Client)',
        ]);
        $content = curl_exec($ch);
        if (curl_errno($ch) === 0) {
            curl_close($ch);
            return $content;
        }
        curl_close($ch);
    }
    
    // 策略 2: file_get_contents + stream context (允許 url fopen 時)
    if (ini_get('allow_url_fopen')) {
        $ctx = stream_context_create([
            'http' => [
                'timeout' => $timeout,
                'follow_location' => 1,
                'max_redirects' => 5,
            ],
            'ssl' => ['verify_peer' => true, 'verify_peer_name' => true],
        ]);
        $content = @file_get_contents($url, false, $ctx);
        if ($content !== false) return $content;
    }
    
    // 策略 3: 最後嘗試 (無逾時控制,極慢環境慎用)
    return @file_get_contents($url);
}

逾時錯誤碼速查表

常數值含義
CURLE_OPERATION_TIMEDOUT28操作逾時 (總逾時)
CURLE_COULDNT_CONNECT7無法連線到主機
CURLE_COULDNT_RESOLVE_HOST6DNS 解析失敗
CURLE_OPERATION_TIMEOUTED28舊版別名 (同 TIMEDOUT)
CURLE_SSL_CONNECT_ERROR35SSL 握手失敗
CURLE_RECV_ERROR56接收資料失敗

最佳實踐建議

  1. 生產環境強制使用 cURL:功能完整、錯誤可辨識、支援毫秒級控制
  2. 設定合理逾時:連線 3-5 秒、總計 10-30 秒,視業務 SLA 調整
  3. 區分逾時類型:連線逾時 vs 傳輸逾時 vs DNS 逾時,採取不同重試策略
  4. 記錄慢請求:超過閾值記錄日誌,定期分析優化上游服務
  5. 熔斷機制:連續失敗達標時暫停請求,避免雪崩效應
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved