PHP cURL
Making HTTP requests, setting options, handling errors and timeouts.
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
TomForget
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
| Option | Meaning |
|---|---|
| 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 receivederrno=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.基本请求
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
TomCURLOPT_RETURNTRANSFER => true 忘了设,curl_exec 会直接把响应体打印到页面,然后你拿到的返回值是 true。这是 cURL 最常见的第一个坑。POST 与 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}传数组给 CURLOPT_POSTFIELDS 会自动编码成 multipart/form-data;传字符串则原样发送。**发 JSON 必须传字符串并显式设 Content-Type。**
常用选项
| 选项 | 含义 |
|---|---|
| CURLOPT_RETURNTRANSFER | 返回字符串而非直接输出 |
| CURLOPT_TIMEOUT | 总超时(秒) |
| CURLOPT_CONNECTTIMEOUT | 连接超时(秒) |
| CURLOPT_FOLLOWLOCATION | 自动跟随重定向 |
| CURLOPT_MAXREDIRS | 最大重定向次数 |
| CURLOPT_SSL_VERIFYPEER | 校验对端证书(必须 true) |
| CURLOPT_PROXY | 走代理 |
| CURLOPT_USERAGENT | 设置 UA |
网上大量「SSL 报错就加
CURLOPT_SSL_VERIFYPEER => false」的答案。这等于关掉 HTTPS 的信任链,中间人可以随意伪造响应。正确做法是更新 CA 证书包。并发请求
串行请求 3 个接口各 1 秒,总耗时 3 秒。curl_multi 并发只要 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 个请求错误处理
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 receivederrno=28 是 CURLE_OPERATION_TIMEDOUT。网络错误和 HTTP 错误要分开处理:curl_exec 返回 false 是网络层失败,返回字符串但状态码 500 是应用层失败。