PHP cURL

Making HTTP requests, setting options, handling errors and timeouts.

Intermediate
Key PointsAlways set a cURL timeout — one slow endpoint can stall the whole worker.

Basic request

PHP
<?php
$ch = curl_init("https://api.example.com/users/1");

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,      // 返回字符串而不是直接输出
    CURLOPT_TIMEOUT        => 5,         // 总超时
    CURLOPT_CONNECTTIMEOUT => 2,         // 连接超时
    CURLOPT_FOLLOWLOCATION => false,     // 不自动跟随重定向
    CURLOPT_HTTPHEADER     => ["Accept: application/json"],
]);

$body = curl_exec($ch);
$err  = curl_error($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($body === false) {
    echo "请求失败: $err\n";
} elseif ($code !== 200) {
    echo "HTTP $code\n";
} else {
    $data = json_decode($body, true);
    echo $data["name"] ?? "无 name 字段", "\n";
}
Output
Tom
Forget CURLOPT_RETURNTRANSFER and curl_exec prints the body while returning true. The first cURL trap everyone hits.

POST with JSON

PHP
<?php
$payload = json_encode(["name" => "Tom", "age" => 18]);

$ch = curl_init("https://api.example.com/users");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_HTTPHEADER     => [
        "Content-Type: application/json",
        "Content-Length: " . strlen($payload),
    ],
    CURLOPT_TIMEOUT        => 5,
]);

$res  = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "状态码: $code\n";
echo "响应: $res\n";
Output
状态码: 201
响应: {"id":7,"name":"Tom","age":18}

An array to CURLOPT_POSTFIELDS becomes multipart/form-data; a string is sent raw. **JSON requires a string plus an explicit Content-Type.**

Common options

OptionMeaning
CURLOPT_RETURNTRANSFER返回字符串而非直接输出
CURLOPT_TIMEOUT总超时(秒)
CURLOPT_CONNECTTIMEOUT连接超时(秒)
CURLOPT_FOLLOWLOCATION自动跟随重定向
CURLOPT_MAXREDIRS最大重定向次数
CURLOPT_SSL_VERIFYPEER校验对端证书(必须 true)
CURLOPT_PROXY走代理
CURLOPT_USERAGENT设置 UA
Many answers say "set SSL_VERIFYPEER => false" to fix SSL errors. That disables the trust chain and allows MITM. Fix the CA bundle instead.

Concurrent requests

Three sequential 1-second calls take 3 seconds; curl_multi finishes in 1.

PHP
<?php
$urls = [
    "https://api.example.com/a",
    "https://api.example.com/b",
    "https://api.example.com/c",
];

$mh = curl_multi_init();
$handles = [];

foreach ($urls as $i => $u) {
    $ch = curl_init($u);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 5,
    ]);
    curl_multi_add_handle($mh, $ch);
    $handles[$i] = $ch;
}

do {
    $status = curl_multi_exec($mh, $running);
    if ($running) {
        curl_multi_select($mh, 1.0);
    }
} while ($running && $status === CURLM_OK);

$results = [];
foreach ($handles as $i => $ch) {
    $results[$i] = curl_multi_getcontent($ch);
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}
curl_multi_close($mh);

echo "完成 " . count($results) . " 个请求\n";
Output
完成 3 个请求

Error handling

PHP
<?php
$ch = curl_init("https://api.example.com/x");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 2,
]);

$body = curl_exec($ch);

if ($body === false) {
    $no  = curl_errno($ch);
    $msg = curl_error($ch);
    echo "errno=$no msg=$msg\n";
} else {
    echo "HTTP " . curl_getinfo($ch, CURLINFO_HTTP_CODE) . "\n";
    echo "耗时 " . round(curl_getinfo($ch, CURLINFO_TOTAL_TIME), 3) . "s\n";
}

curl_close($ch);
Output
errno=28 msg=Operation timed out after 2001 milliseconds with 0 bytes received
errno=28 is a timeout. Network failures and HTTP failures are different: false from curl_exec is transport-level; a string with status 500 is application-level.

Friends & Partners