curl_multi_strerror() 函数用于返回cURL多句柄错误代码的字符串描述。这个函数在错误处理时非常有用,可以将数字错误代码转换为可读的错误消息。
curl_multi_strerror ( int $error_code ) : string|null
| 参数 | 描述 |
|---|---|
| error_code | cURL多句柄错误代码,由 curl_multi_exec() 或其他cURL多句柄函数返回。 |
返回错误代码的字符串描述,如果错误代码未知则返回 null。
| 错误代码 | 常量 | 描述 |
|---|---|---|
| 0 | CURLM_OK |
操作成功 |
| 1 | CURLM_BAD_HANDLE |
传递的句柄无效 |
| 2 | CURLM_BAD_EASY_HANDLE |
传递的简单句柄无效 |
| 3 | CURLM_OUT_OF_MEMORY |
内存不足 |
| 4 | CURLM_INTERNAL_ERROR |
内部错误 |
| 5 | CURLM_BAD_SOCKET |
错误的socket |
| 6 | CURLM_UNKNOWN_OPTION |
未知选项 |
| 7 | CURLM_ADDED_ALREADY |
句柄已添加 |
// 初始化cURL多句柄
$mh = curl_multi_init();
// 创建一个无效的cURL句柄(用于演示错误)
$ch = "invalid_handle";
// 尝试添加无效句柄到多句柄
$result = curl_multi_add_handle($mh, $ch);
// 检查结果并获取错误描述
if ($result !== CURLM_OK) {
$errorString = curl_multi_strerror($result);
echo "错误代码: {$result}\n";
echo "错误描述: {$errorString}\n";
// 输出: 错误代码: 2
// 输出: 错误描述: The passed-in handle is not a valid CURLM handle.
}
curl_multi_close($mh);
function robustConcurrentRequests($urls) {
$mh = curl_multi_init();
$handles = [];
$results = [];
// 创建cURL句柄
foreach ($urls as $index => $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true
]);
$addResult = curl_multi_add_handle($mh, $ch);
if ($addResult === CURLM_OK) {
$handles[$index] = $ch;
$results[$index] = ['status' => 'pending'];
} else {
$errorMsg = curl_multi_strerror($addResult);
$results[$index] = [
'status' => 'error',
'error' => "添加句柄失败: {$errorMsg} (代码: {$addResult})"
];
curl_close($ch);
}
}
// 执行并发请求
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
// 检查多句柄执行错误
if ($mrc !== CURLM_OK) {
$errorMsg = curl_multi_strerror($mrc);
echo "cURL多句柄执行错误: {$errorMsg} (代码: {$mrc})\n";
// 根据错误类型决定是否继续
if ($mrc === CURLM_OUT_OF_MEMORY || $mrc === CURLM_BAD_HANDLE) {
break; // 严重错误,停止执行
}
}
// 等待活动
if ($active) {
$selectResult = curl_multi_select($mh, 1.0);
if ($selectResult === -1) {
usleep(100000); // 100毫秒
}
}
} while ($active);
// 收集结果
foreach ($handles as $index => $ch) {
if (isset($results[$index]) && $results[$index]['status'] === 'pending') {
$error = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$results[$index] = [
'status' => $error ? 'error' : 'success',
'content' => curl_multi_getcontent($ch),
'http_code' => $httpCode,
'error' => $error
];
}
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
return $results;
}
// 使用示例
$urls = [
'http://httpbin.org/get',
'http://invalid-url-that-will-fail.com',
'http://httpbin.org/status/404',
'http://httpbin.org/status/500'
];
$results = robustConcurrentRequests($urls);
foreach ($results as $index => $result) {
echo "请求 {$index}: 状态 - {$result['status']}\n";
if ($result['status'] === 'error') {
echo " 错误: {$result['error']}\n";
} else {
echo " HTTP状态码: {$result['http_code']}\n";
}
}
class CurlMultiHandler {
private $multiHandle;
private $handles = [];
public function __construct() {
$this->multiHandle = curl_multi_init();
if (!$this->multiHandle) {
throw new RuntimeException('无法初始化cURL多句柄');
}
}
public function addRequest($url, $options = []) {
$ch = curl_init();
$defaultOptions = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true
];
curl_setopt_array($ch, array_merge($defaultOptions, $options));
$result = curl_multi_add_handle($this->multiHandle, $ch);
if ($result !== CURLM_OK) {
$errorMsg = curl_multi_strerror($result);
curl_close($ch);
throw new RuntimeException("添加请求失败: {$errorMsg}", $result);
}
$handleId = (int)$ch;
$this->handles[$handleId] = $ch;
return $handleId;
}
public function execute() {
$active = null;
$results = [];
do {
$mrc = curl_multi_exec($this->multiHandle, $active);
// 处理多句柄错误
if ($mrc !== CURLM_OK) {
$errorMsg = curl_multi_strerror($mrc);
// 记录错误但继续执行(除非是严重错误)
error_log("cURL多句柄错误: {$errorMsg} (代码: {$mrc})");
if ($mrc === CURLM_BAD_HANDLE || $mrc === CURLM_OUT_OF_MEMORY) {
throw new RuntimeException("严重的cURL多句柄错误: {$errorMsg}", $mrc);
}
}
// 等待活动
if ($active) {
$selectResult = curl_multi_select($this->multiHandle, 0.5);
if ($selectResult === -1) {
usleep(50000); // 50毫秒
}
}
} while ($active);
// 收集所有结果
foreach ($this->handles as $handleId => $ch) {
$results[$handleId] = [
'content' => curl_multi_getcontent($ch),
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
'error' => curl_error($ch),
'total_time' => curl_getinfo($ch, CURLINFO_TOTAL_TIME)
];
curl_multi_remove_handle($this->multiHandle, $ch);
curl_close($ch);
}
$this->handles = [];
return $results;
}
public function __destruct() {
if ($this->multiHandle) {
// 清理所有剩余的句柄
foreach ($this->handles as $ch) {
curl_multi_remove_handle($this->multiHandle, $ch);
curl_close($ch);
}
curl_multi_close($this->multiHandle);
}
}
}
// 使用示例
try {
$handler = new CurlMultiHandler();
// 添加多个请求
$handler->addRequest('http://httpbin.org/get');
$handler->addRequest('http://httpbin.org/post', [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => ['test' => 'data']
]);
$handler->addRequest('http://httpbin.org/status/200');
// 执行所有请求
$results = $handler->execute();
foreach ($results as $handleId => $result) {
echo "句柄 {$handleId}: HTTP {$result['http_code']}, 耗时: {$result['total_time']}秒\n";
if ($result['error']) {
echo " 错误: {$result['error']}\n";
}
}
} catch (Exception $e) {
echo "错误: {$e->getMessage()} (代码: {$e->getCode()})\n";
}
function getCurlMultiErrorInfo($errorCode) {
$errorString = curl_multi_strerror($errorCode);
$errorTypes = [
CURLM_OK => '成功',
CURLM_BAD_HANDLE => '句柄错误',
CURLM_BAD_EASY_HANDLE => '简单句柄错误',
CURLM_OUT_OF_MEMORY => '内存错误',
CURLM_INTERNAL_ERROR => '内部错误',
CURLM_BAD_SOCKET => 'Socket错误',
CURLM_UNKNOWN_OPTION => '选项错误',
CURLM_ADDED_ALREADY => '重复添加错误'
];
return [
'code' => $errorCode,
'message' => $errorString,
'type' => $errorTypes[$errorCode] ?? '未知错误类型',
'is_critical' => in_array($errorCode, [CURLM_BAD_HANDLE, CURLM_OUT_OF_MEMORY])
];
}
// 测试不同的错误情况
$testCodes = [CURLM_OK, CURLM_BAD_HANDLE, CURLM_OUT_OF_MEMORY, CURLM_INTERNAL_ERROR, 999];
foreach ($testCodes as $code) {
$errorInfo = getCurlMultiErrorInfo($code);
echo "错误代码: {$errorInfo['code']}\n";
echo "错误描述: {$errorInfo['message']}\n";
echo "错误类型: {$errorInfo['type']}\n";
echo "是否严重: " . ($errorInfo['is_critical'] ? '是' : '否') . "\n";
echo "---\n";
}
curl_multi_strerror() 函数需要PHP 5.5.0或更高版本。
curl_multi_strerror() 返回的错误信息记录到日志中,以便于问题排查。
描述:传递的句柄无效
处理建议:检查句柄是否已关闭或未正确初始化,确保使用有效的cURL多句柄。
描述:内存不足
处理建议:减少并发请求数量,增加PHP内存限制,或优化请求数据大小。