PHP curl_multi_strerror函数

定义和用法

curl_multi_strerror() 函数用于返回cURL多句柄错误代码的字符串描述。这个函数在错误处理时非常有用,可以将数字错误代码转换为可读的错误消息。

注意:此函数在PHP 5.5.0及以上版本可用。

语法

curl_multi_strerror ( int $error_code ) : string|null

参数

参数 描述
error_code cURL多句柄错误代码,由 curl_multi_exec() 或其他cURL多句柄函数返回。

返回值

返回错误代码的字符串描述,如果错误代码未知则返回 null

cURL多句柄错误代码

错误代码 常量 描述
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 句柄已添加

示例

示例 1:基本用法

// 初始化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);

示例 2:在并发请求中进行错误处理

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";
    }
}

示例 3:完整的错误处理包装器

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";
}

示例 4:错误代码映射和自定义处理

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() 返回的错误信息记录到日志中,以便于问题排查。

常见错误代码及处理建议

CURLM_BAD_HANDLE (代码: 1)

描述:传递的句柄无效

处理建议:检查句柄是否已关闭或未正确初始化,确保使用有效的cURL多句柄。

CURLM_OUT_OF_MEMORY (代码: 3)

描述:内存不足

处理建议:减少并发请求数量,增加PHP内存限制,或优化请求数据大小。

相关函数