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

PHP 用 cURL 重写 file_get_contents:超时控制、重定向、SSL 验证完整替代方案

     編輯:PHP 綜合知識

为什么替换 file_get_contents?

问题file_get_contentscURL 方案
超时控制仅支持 stream_context 全局秒级连接/读取分离毫秒级 CURLOPT_CONNECTTIMEOUT_MS
重定向跟随不跟随 301/302CURLOPT_FOLLOWLOCATION 可限制层数
SSL 验证默认不验证,不安全强制验证 CURLOPT_SSL_VERIFYPEER
错误诊断仅返回 falsecurl_errno()/curl_error() 精确码
性能阻塞流支持多句柄并发 curl_multi
协议支持HTTP/HTTPS/FTPHTTP/HTTPS/FTP/SMTP/IMAP/...

标准替代函数

<?php
/**
 * cURL 版 file_get_contents
 * @param string $url
 * @param array $options 额外 curl_setopt 数组
 * @return string|false 失败返回 false
 */
function curl_file_get_contents(string $url, array $options = []): string|false
{
    $ch = curl_init($url);

    // 默认安全配置
    $defaults = [
        CURLOPT_RETURNTRANSFER => true,      // 返回字符串而非输出
        CURLOPT_FOLLOWLOCATION => true,      // 跟随重定向
        CURLOPT_MAXREDIRS => 5,              // 最大重定向次数
        CURLOPT_CONNECTTIMEOUT_MS => 3000,   // 连接超时 3 秒
        CURLOPT_TIMEOUT_MS => 10000,         // 总超时 10 秒
        CURLOPT_SSL_VERIFYPEER => true,      // 验证 SSL 证书
        CURLOPT_SSL_VERIFYHOST => 2,         // 验证域名匹配
        CURLOPT_USERAGENT => 'PHP-cURL/' . PHP_VERSION,
        CURLOPT_ENCODING => 'gzip, deflate', // 自动解压
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    ];

    curl_setopt_array($ch, $defaults);
    if ($options) curl_setopt_array($ch, $options); // 允许覆盖

    $content = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($errno) {
        // 可选:触发错误日志
        error_log("cURL [$errno] $error for $url");
        return false;
    }

    if ($httpCode >= 400) {
        error_log("HTTP $httpCode for $url");
        return false;
    }

    return $content;
}

进阶:支持 POST / Header / Cookie

function curl_request(
    string $url,
    string $method = 'GET',
    array $data = [],
    array $headers = [],
    array $options = []
): string|false {
    $ch = curl_init($url);

    $defaults = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_CONNECTTIMEOUT_MS => 3000,
        CURLOPT_TIMEOUT_MS => 15000,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_USERAGENT => 'PHP-cURL/' . PHP_VERSION,
        CURLOPT_ENCODING => '',
    ];

    // 方法处理
    if (strtoupper($method) === 'POST') {
        $defaults[CURLOPT_POST] = true;
        if (isset($options[CURLOPT_POSTFIELDS])) {
            // 已手动设置
        } elseif (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'json') !== false) {
            $defaults[CURLOPT_POSTFIELDS] = json_encode($data, JSON_UNESCAPED_UNICODE);
        } else {
            $defaults[CURLOPT_POSTFIELDS] = http_build_query($data);
        }
    } elseif ($data) {
        // GET 附加查询串
        $url .= (strpos($url, '?') ? '&' : '?') . http_build_query($data);
        curl_setopt($ch, CURLOPT_URL, $url);
    }

    // Header 处理
    if ($headers) {
        $headerArr = [];
        foreach ($headers as $k => $v) {
            $headerArr[] = "$k: $v";
        }
        $defaults[CURLOPT_HTTPHEADER] = $headerArr;
    }

    curl_setopt_array($ch, $defaults);
    if ($options) curl_setopt_array($ch, $options);

    $content = curl_exec($ch);
    $errno = curl_errno($ch);
    curl_close($ch);

    if ($errno) return false;
    return $content;
}

使用示例

// 简单 GET
$html = curl_file_get_contents('https://api.example.com/users/1');

// 带 Header GET
$html = curl_request('https://api.example.com/profile', 'GET', [], [
    'Authorization' => 'Bearer ' . $token,
    'Accept' => 'application/json',
]);

// POST JSON
$result = curl_request('https://api.example.com/orders', 'POST', [
    'product_id' => 123,
    'quantity' => 2,
], [
    'Content-Type' => 'application/json',
    'Authorization' => 'Bearer ' . $token,
]);

// 文件上传 (multipart)
$result = curl_request('https://api.example.com/upload', 'POST', [
    'file' => new CURLFile('/path/to/image.jpg', 'image/jpeg', 'avatar.jpg'),
], [], [
    CURLOPT_HTTPHEADER => ['Expect:'], // 取消 100-continue
]);

批量并发请求 (curl_multi)

function curl_multi_request(array $urls, int $maxConcurrent = 10): array
{
    $mh = curl_multi_init();
    $handles = [];
    $results = [];

    // 初始化句柄
    foreach ($urls as $i => $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT_MS => 10000,
            CURLOPT_SSL_VERIFYPEER => true,
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[$i] = $ch;
    }

    $running = null;
    do {
        curl_multi_exec($mh, $running);
        // 限制并发:简单实现,生产用更复杂的队列
        while ($running > $maxConcurrent) {
            usleep(10000);
            curl_multi_exec($mh, $running);
        }
        curl_multi_select($mh, 0.1);
    } while ($running);

    // 收集结果
    foreach ($handles as $i => $ch) {
        $results[$i] = [
            'content' => curl_multi_getcontent($ch),
            'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
            'error' => curl_error($ch),
        ];
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_cleanup($mh);
    return $results;
}

结语

彻底弃用 file_get_contents 做 HTTP 请求。上述 curl_file_get_contents() 兼容原函数签名,仅内部替换为 cURL,即可获得:可控超时、重定向跟随、SSL 安全、错误诊断、并发能力。新项目直接使用 curl_request() 或引入 Guzzle 享受 PSR-18 标准客户端。

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