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

PHP cURL 庫實戰指南:從基礎請求到高級場景的 10 個常用代碼片段

     編輯:PHP 綜合知識

前言

cURL 是 PHP 與外部 HTTP 服務交互的瑞士軍刀。本文精選 10 個高頻實戰場景,提供可直接落地的代碼模板,涵蓋 GET/POST、代理、FTP、JSON API、文件下載、斷點續傳等,助你快速解決 90% 的網絡請求需求。

0. 基礎請求模板(GET + 超時 + 錯誤處理)

function httpGet(string $url, array $options = []): ?string {
    $ch = curl_init($url);
    $defaultOpts = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER         => false,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_SSL_VERIFYPEER => true, // 生產環境必開
        CURLOPT_USERAGENT      => 'MyApp/1.0 (+https://example.com/bot)',
    ];
    curl_setopt_array($ch, array_merge($defaultOpts, $options));
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($errno !== 0) {
        error_log("cURL Error [$errno]: $error for $url");
        return null;
    }
    if ($httpCode < 200 || $httpCode >= 300) {
        error_log("HTTP $httpCode for $url");
        return null;
    }
    return $response;
}

1. 網站存活監控(HEAD 請求 + 狀態碼判斷)

function isSiteUp(string $url): bool {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY        => true,
        CURLOPT_RETURNTRANSFER=> true,
        CURLOPT_FOLLOWLOCATION=> true,
        CURLOPT_CONNECTTIMEOUT=> 3,
        CURLOPT_TIMEOUT       => 5,
    ]);
    curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $err = curl_errno($ch);
    curl_close($ch);
    return $err === 0 && $code === 200;
}

// 使用
if (isSiteUp('https://api.example.com/health')) {
    echo "Service UP";
} else {
    echo "Service DOWN";
}

2. 替代 file_get_contents(支援 HTTPS、超時、重定向)

function fetchUrl(string $url): ?string {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER         => false,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $data = curl_exec($ch);
    if (curl_errno($ch)) {
        curl_close($ch);
        return null;
    }
    curl_close($ch);
    return $data;
}

3. 批量下載圖片(正則提取 + 併發保存)

function downloadImages(string $html, string $saveDir, int $concurrency = 5): void {
    if (!is_dir($saveDir)) mkdir($saveDir, 0755, true);
    preg_match_all('~https?://[^\s"\'<>]+\.(?:jpg|jpeg|png|gif|webp)~i', $html, $m);
    $urls = array_unique($m[0]);

    $mh = curl_multi_init();
    $handles = [];
    foreach ($urls as $url) {
        $filename = basename(parse_url($url, PHP_URL_PATH));
        $fp = fopen($saveDir . '/' . $filename, 'wb');
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_FILE           => $fp,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT        => 30,
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[] = ['ch' => $ch, 'fp' => $fp];
    }

    $running = null;
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh, 0.2);
    } while ($running);

    foreach ($handles as $h) {
        curl_multi_remove_handle($mh, $h['ch']);
        fclose($h['fp']);
        curl_close($h['ch']);
    }
    curl_multi_close($mh);
}

4. FTP 文件上傳(含 ASCII/二進制模式切換)

function ftpUpload(string $ftpUrl, string $localFile, bool $ascii = false): bool {
    $fp = fopen($localFile, 'rb');
    if (!$fp) return false;

    $ch = curl_init($ftpUrl); // ftp://user:pass@host:21/path/file
    curl_setopt_array($ch, [
        CURLOPT_UPLOAD      => true,
        CURLOPT_INFILE      => $fp,
        CURLOPT_INFILESIZE  => filesize($localFile),
        CURLOPT_FTPASCII    => $ascii ? 1 : 0,
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $result = curl_exec($ch);
    $errno = curl_errno($ch);
    fclose($fp);
    curl_close($ch);
    return $errno === 0;
}

5. 發送 JSON API 請求(POST + 自定義 Header)

function postJson(string $url, array $payload, array $headers = []): ?array {
    $json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $defaultHeaders = [
        'Content-Type: application/json',
        'Content-Length: ' . strlen($json),
        'Accept: application/json',
    ];
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST => 'POST',
        CURLOPT_POSTFIELDS    => $json,
        CURLOPT_RETURNTRANSFER=> true,
        CURLOPT_HTTPHEADER    => array_merge($defaultHeaders, $headers),
        CURLOPT_CONNECTTIMEOUT=> 5,
        CURLOPT_TIMEOUT       => 20,
    ]);
    $resp = curl_exec($ch);
    $errno = curl_errno($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($errno !== 0 || $httpCode >= 400) {
        error_log("API Error: HTTP $httpCode, cURL $errno - $url");
        return null;
    }
    return json_decode($resp, true);
}

// 使用
$res = postJson('https://api.example.com/users', [
    'name' => 'Hagrid',
    'age'  => 36,
], ['Authorization: Bearer ' . $token]);

6. 斷點續傳大文件下載(Range 請求)

function downloadResume(string $url, string $destFile): bool {
    $fileSize = is_file($destFile) ? filesize($destFile) : 0;
    $fp = fopen($destFile, 'ab'); // 追加模式
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_FILE           => $fp,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_RANGE          => $fileSize . '-', // 關鍵:從已下載位置續傳
        CURLOPT_CONNECTTIMEOUT => 15,
        CURLOPT_TIMEOUT        => 0, // 不限制總時間
        CURLOPT_LOW_SPEED_LIMIT=> 1024, // 低速限制
        CURLOPT_LOW_SPEED_TIME => 30,
    ]);
    $result = curl_exec($ch);
    $errno = curl_errno($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    fclose($fp);
    curl_close($ch);
    // 206 Partial Content 或 200 OK(不支援 Range 時重新下載)
    return $errno === 0 && in_array($httpCode, [200, 206]);
}

7. 模擬瀏覽器登錄(Cookie Jar 自動管理)

function loginAndFetch(string $loginUrl, string $targetUrl, array $formData): ?string {
    $cookieFile = sys_get_temp_dir() . '/cookies_' . md5($loginUrl) . '.txt';

    // 1. 登錄
    $ch = curl_init($loginUrl);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query($formData),
        CURLOPT_COOKIEJAR      => $cookieFile, // 保存 Cookie
        CURLOPT_COOKIEFILE     => $cookieFile, // 讀取 Cookie
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
    ]);
    curl_exec($ch);
    curl_close($ch);

    // 2. 訪問受保護頁面
    $ch = curl_init($targetUrl);
    curl_setopt_array($ch, [
        CURLOPT_COOKIEFILE     => $cookieFile,
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $html = curl_exec($ch);
    curl_close($ch);
    return $html;
}

8. 代理請求(HTTP/SOCKS5 + 驗證)

function requestViaProxy(string $url, string $proxy, ?string $auth = null): ?string {
    $ch = curl_init($url);
    $opts = [
        CURLOPT_PROXY       => $proxy, // 1.2.3.4:8080 或 socks5://1.2.3.4:1080
        CURLOPT_PROXYTYPE   => strpos($proxy, 'socks5') === 0 ? CURLPROXY_SOCKS5 : CURLPROXY_HTTP,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
    ];
    if ($auth) {
        $opts[CURLOPT_PROXYUSERPWD] = $auth; // user:pass
    }
    curl_setopt_array($ch, $opts);
    $data = curl_exec($ch);
    $errno = curl_errno($ch);
    curl_close($ch);
    return $errno === 0 ? $data : null;
}

9. 上傳本地文件(multipart/form-data)

function uploadFile(string $url, string $fieldName, string $filePath, array $extraFields = []): ?array {
    if (!function_exists('curl_file_create')) { // PHP 5.5-
        $post[$fieldName] = '@' . realpath($filePath);
    } else {
        $post[$fieldName] = curl_file_create($filePath);
    }
    $post = array_merge($post, $extraFields);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $post,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
    ]);
    $resp = curl_exec($ch);
    $errno = curl_errno($ch);
    curl_close($ch);
    return $errno === 0 ? json_decode($resp, true) : null;
}

10. 並發請求池(控制併發數 + 回調處理)

function concurrentRequests(array $urls, int $maxConcurrent = 10, callable $onComplete): void {
    $mh = curl_multi_init();
    $queue = $urls;
    $active = [];

    // 初始填充
    while (count($active) < $maxConcurrent && $queue) {
        $url = array_shift($queue);
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT        => 30,
        ]);
        curl_multi_add_handle($mh, $ch);
        $active[(int)$ch] = ['url' => $url, 'ch' => $ch];
    }

    do {
        $mrc = curl_multi_exec($mh, $running);
        if ($mrc !== CURLM_OK) break;

        // 檢查完成的請求
        while ($info = curl_multi_info_read($mh)) {
            $ch = $info['handle'];
            $meta = $active[(int)$ch];
            $response = curl_multi_getcontent($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $errno = curl_errno($ch);
            $onComplete($meta['url'], $response, $httpCode, $errno);
            curl_multi_remove_handle($mh, $ch);
            curl_close($ch);
            unset($active[(int)$ch]);

            // 补充新請求
            if ($queue) {
                $url = array_shift($queue);
                $ch = curl_init($url);
                curl_setopt_array($ch, [
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_TIMEOUT        => 30,
                ]);
                curl_multi_add_handle($mh, $ch);
                $active[(int)$ch] = ['url' => $url, 'ch' => $ch];
            }
        }
        if ($running) curl_multi_select($mh, 0.1);
    } while ($running || $active);

    curl_multi_close($mh);
}

// 使用
concurrentRequests($urlList, 20, function($url, $body, $code, $err) {
    if ($err === 0 && $code === 200) {
        // 解析 $body 入庫
    } else {
        error_log("Fail: $url HTTP $code cURL $err");
    }
});

生產環境核心配置清單

選項推薦值說明
CURLOPT_SSL_VERIFYPEERtrue必須驗證證書,配合 CURLOPT_CAINFO 指定 cacert.pem
CURLOPT_CONNECTTIMEOUT3-10s防止 DNS/TCP 握手阻塞
CURLOPT_TIMEOUT15-60s總超時,防慢速攻擊
CURLOPT_USERAGENT自定義標識便於對方日誌排查,避免被 WAF 攔截
CURLOPT_FOLLOWLOCATIONtrue自動跟隨 3xx,注意 open_basedir/safe_mode 限制
CURLOPT_MAXREDIRS5-10防重定向循環
CURLOPT_LOW_SPEED_LIMIT/TIME1024/30斷開極慢連線,釋放資源

總結

掌握上述 10 大場景模板,即可應對絕大多數 PHP 網絡編程需求。建議將核心邏輯封裝為 HttpClient 服務類,統一異常處理、重試策略、日誌記錄、指標上報(Prometheus),並配合 Guzzle 或 Symfony HttpClient 等現代庫在新項目中落地,享受 PSR-18/PSR-7 標準帶來的可攜性與可測試性。

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