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

file_get_contents 被禁用完整替代方案:cURL 封裝與自動降級策略

     編輯:PHP 相關知識

虛擬主機常禁用 file_get_contents、fsockopen 等網路 IO 函式防禦 DDOS。本文提供 **cURL 完整封裝**、**自動偵測降級**、**超時與錯誤處理** 的生產級解決方案。

核心替代:cURL 封裝函式

<?php
/**
 * 通用 HTTP GET 取得內容
 * 自動偵測 file_get_contents / cURL 可用性
 * 支援 HTTPS、超時、重導向、自定義 Header
 */
function http_get($url, array $options = []) {
    $defaults = [
        'timeout'         => 10,        // 連線+讀取總超時(秒)
        'connect_timeout' => 5,         // 連線階段超時
        'follow_location' => true,      // 跟隨 3xx 重導向
        'max_redirects'   => 5,
        'ssl_verify'      => true,      // 驗證 SSL 憑證
        'headers'         => [],        // 額外請求標頭
        'user_agent'      => 'PHP-HTTP-Client/1.0',
    ];
    $opts = array_merge($defaults, $options);
    
    // 優先使用 file_get_contents(原生、效能較好)
    if (ini_get('allow_url_fopen') && function_exists('file_get_contents')) {
        $ctx = stream_context_create([
            'http' => [
                'method'        => 'GET',
                'timeout'       => $opts['timeout'],
                'header'        => array_merge(
                    ['User-Agent: ' . $opts['user_agent']],
                    $opts['headers']
                ),
                'follow_location' => $opts['follow_location'],
                'max_redirects'   => $opts['max_redirects'],
                'ignore_errors'   => true, // 取得 4xx/5xx 內容
            ],
            'ssl' => [
                'verify_peer'      => $opts['ssl_verify'],
                'verify_peer_name' => $opts['ssl_verify'],
            ],
        ]);
        $content = @file_get_contents($url, false, $ctx);
        if ($content !== false) {
            return ['content' => $content, 'info' => ['method' => 'file_get_contents']];
        }
        // 失敗則降級 cURL
    }
    
    // cURL 實作
    if (!function_exists('curl_init')) {
        throw new RuntimeException('file_get_contents 與 cURL 皆不可用');
    }
    
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => $opts['timeout'],
        CURLOPT_CONNECTTIMEOUT => $opts['connect_timeout'],
        CURLOPT_FOLLOWLOCATION => $opts['follow_location'],
        CURLOPT_MAXREDIRS      => $opts['max_redirects'],
        CURLOPT_SSL_VERIFYPEER => $opts['ssl_verify'],
        CURLOPT_SSL_VERIFYHOST => $opts['ssl_verify'] ? 2 : 0,
        CURLOPT_USERAGENT      => $opts['user_agent'],
        CURLOPT_HTTPHEADER     => array_merge(
            ['User-Agent: ' . $opts['user_agent']],
            $opts['headers']
        ),
        CURLOPT_ENCODING       => 'gzip, deflate', // 自動解壓
    ]);
    
    $content = curl_exec($ch);
    $errno = curl_errno($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
    
    if ($errno !== CURLE_OK) {
        throw new RuntimeException("cURL error ($errno): " . curl_strerror($errno));
    }
    
    return ['content' => $content, 'info' => $info];
}

// 使用範例
try {
    $result = http_get('https://api.example.com/data', [
        'timeout' => 15,
        'headers' => ['Authorization: Bearer ' . $token],
    ]);
    $data = json_decode($result['content'], true);
} catch (Exception $e) {
    error_log("HTTP GET failed: " . $e->getMessage());
}

POST 請求對應版本

<?php
function http_post($url, $data, array $options = []) {
    $defaults = [
        'timeout' => 15,
        'content_type' => 'application/json',
    ];
    $opts = array_merge($defaults, $options);
    
    $postData = is_array($data) ? json_encode($data) : $data;
    
    if (ini_get('allow_url_fopen') && function_exists('file_get_contents')) {
        $ctx = stream_context_create([
            'http' => [
                'method'  => 'POST',
                'header'  => "Content-Type: {$opts['content_type']}\r\n" .
                             "Content-Length: " . strlen($postData),
                'content' => $postData,
                'timeout' => $opts['timeout'],
            ],
        ]);
        $result = @file_get_contents($url, false, $ctx);
        if ($result !== false) return $result;
    }
    
    // cURL POST
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $postData,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => $opts['timeout'],
        CURLOPT_HTTPHEADER     => [
            'Content-Type: ' . $opts['content_type'],
            'Content-Length: ' . strlen($postData),
        ],
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

Windows PHP 啟用 cURL

  1. 開啟 php.ini
  2. 搜尋 extension=curl 或 extension=php_curl.dll
  3. 移除前方分號 ;
  4. 確認 libssh2.dll, libcrypto-*.dll, libssl-*.dll 在 PHP 目錄或 System32
  5. 重啟 Apache/Nginx/PHP-FPM

Linux 安裝 cURL 擴展

# Ubuntu/Debian
apt-get install php-curl
systemctl restart php8.1-fpm

# CentOS/RHEL
yum install php-curl
systemctl restart php-fpm

# 編譯安裝 PHP 時
./configure --with-curl=/usr/local/curl ...

效能與安全建議

  • 重用 cURL handle:高頻請求用 curl_multi_* 或連線池(GuzzleHttp/Client 內建)
  • 驗證 SSL:生產環境保持 CURLOPT_SSL_VERIFYPEER = true,若需忽略請配合 CURLOPT_CAINFO 指定自簽憑證
  • 設定超時:永遠設定 CURLOPT_TIMEOUT 與 CURLOPT_CONNECTTIMEOUT,避免阻塞進程
  • 限制重導向:CURLOPT_MAXREDIRS = 5 防無限循環
  • User-Agent:設定可識別的 UA,便於對方日誌分析
現代建議:新專案直接使用 GuzzleHTTP 或 HTTPlug,已封裝上述所有細節,支援 PSR-18、中介軟體、非同步請求。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved