PHP curl_strerror函数

定义和用法

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

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

语法

curl_strerror ( int $error_code ) : string|null

参数

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

返回值

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

常见cURL错误代码

错误代码 常量 描述
0 CURLE_OK 操作成功
1 CURLE_UNSUPPORTED_PROTOCOL 不支持的协议
2 CURLE_FAILED_INIT 初始化失败
3 CURLE_URL_MALFORMAT URL格式错误
6 CURLE_COULDNT_RESOLVE_HOST 无法解析主机
7 CURLE_COULDNT_CONNECT 无法连接到主机
28 CURLE_OPERATION_TIMEDOUT 操作超时
35 CURLE_SSL_CONNECT_ERROR SSL连接错误
47 CURLE_TOO_MANY_REDIRECTS 重定向过多
56 CURLE_RECV_ERROR 接收网络数据错误
60 CURLE_SSL_CERTPROBLEM SSL证书问题

示例

示例 1:基本用法

// 初始化cURL会话
$ch = curl_init();

// 设置一个无效的URL以产生错误
curl_setopt($ch, CURLOPT_URL, "http://invalid-url-that-does-not-exist.example");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);

// 执行请求
curl_exec($ch);

// 获取错误代码和描述
if ($errno = curl_errno($ch)) {
    $error_message = curl_strerror($errno);
    echo "cURL错误代码: {$errno}\n";
    echo "错误描述: {$error_message}\n";
    echo "curl_error()返回: " . curl_error($ch) . "\n";
} else {
    echo "请求成功\n";
}

curl_close($ch);

示例 2:在函数中封装错误处理

function makeCurlRequest($url, $options = []) {
    $ch = curl_init();

    $defaultOptions = [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP cURL)'
    ];

    curl_setopt_array($ch, array_merge($defaultOptions, $options));

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if ($errno = curl_errno($ch)) {
        $errorStr = curl_strerror($errno);
        $errorMsg = curl_error($ch);

        // 记录详细错误信息
        error_log("cURL请求失败 - URL: {$url}, 错误代码: {$errno}, 错误描述: {$errorStr}, 详细: {$errorMsg}");

        $response = [
            'success' => false,
            'error' => [
                'code' => $errno,
                'message' => $errorStr,
                'detail' => $errorMsg,
                'http_code' => $httpCode
            ],
            'data' => null
        ];
    } else {
        $response = [
            'success' => true,
            'error' => null,
            'data' => $response,
            'http_code' => $httpCode,
            'info' => curl_getinfo($ch)
        ];
    }

    curl_close($ch);
    return $response;
}

// 使用示例
$result = makeCurlRequest('https://httpbin.org/delay/10', [CURLOPT_TIMEOUT => 3]);

if (!$result['success']) {
    echo "请求失败:\n";
    echo "错误代码: " . $result['error']['code'] . "\n";
    echo "错误描述: " . $result['error']['message'] . "\n";
    echo "详细错误: " . $result['error']['detail'] . "\n";
    echo "HTTP状态码: " . $result['error']['http_code'] . "\n";
} else {
    echo "请求成功,HTTP状态码: " . $result['http_code'] . "\n";
}

示例 3:创建详细的错误报告

class CurlErrorHandler {
    private static $commonErrors = [
        0 => '成功',
        1 => '不支持的协议',
        2 => '初始化失败',
        3 => 'URL格式错误',
        5 => '无法解析代理',
        6 => '无法解析主机',
        7 => '无法连接到主机',
        8 => 'FTP错误',
        9 => 'FTP访问被拒绝',
        28 => '操作超时',
        35 => 'SSL/TLS握手失败',
        47 => '重定向过多',
        52 => '服务器无返回内容',
        56 => '接收网络数据失败',
        60 => 'SSL证书问题',
        61 => '无法解码内容',
        77 => 'SSL CA证书问题'
    ];

    public static function getErrorInfo($errno) {
        $errorStr = curl_strerror($errno);

        $info = [
            'code' => $errno,
            'message' => $errorStr,
            'category' => self::getErrorCategory($errno),
            'suggestion' => self::getErrorSuggestion($errno),
            'is_common' => isset(self::$commonErrors[$errno])
        ];

        if (isset(self::$commonErrors[$errno])) {
            $info['common_name'] = self::$commonErrors[$errno];
        }

        return $info;
    }

    private static function getErrorCategory($errno) {
        $categories = [
            'network' => [6, 7, 28, 56],
            'ssl' => [35, 60, 77],
            'protocol' => [1, 3, 47],
            'configuration' => [2, 5, 9],
            'server' => [52, 61]
        ];

        foreach ($categories as $category => $codes) {
            if (in_array($errno, $codes)) {
                return $category;
            }
        }

        return 'unknown';
    }

    private static function getErrorSuggestion($errno) {
        $suggestions = [
            6 => '检查主机名是否正确,DNS解析是否正常',
            7 => '检查主机是否可达,端口是否开放,防火墙设置',
            28 => '增加超时时间或检查网络连接',
            35 => '检查SSL证书配置,尝试关闭SSL验证(仅测试环境)',
            47 => '检查重定向循环,或增加CURLOPT_MAXREDIRS',
            60 => '下载正确的CA证书包,或设置CURLOPT_CAINFO',
            77 => '设置正确的证书路径,或禁用证书验证(仅测试环境)'
        ];

        return $suggestions[$errno] ?? '请检查cURL配置和网络连接';
    }

    public static function formatErrorReport($errno, $url = '') {
        $info = self::getErrorInfo($errno);

        $report = "cURL错误报告\n";
        $report .= "==============\n";
        if ($url) {
            $report .= "URL: {$url}\n";
        }
        $report .= "错误代码: {$info['code']}\n";
        $report .= "错误描述: {$info['message']}\n";

        if (isset($info['common_name'])) {
            $report .= "常见名称: {$info['common_name']}\n";
        }

        $report .= "错误类别: " . ucfirst($info['category']) . "\n";
        $report .= "建议解决方案: {$info['suggestion']}\n";

        return $report;
    }
}

// 使用示例
$testErrors = [6, 7, 28, 35, 47, 60, 99];

foreach ($testErrors as $errno) {
    echo CurlErrorHandler::formatErrorReport($errno, 'https://example.com');
    echo "---\n";
}

// 在实际请求中使用
$ch = curl_init('https://invalid-host.example');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);

if ($errno = curl_errno($ch)) {
    echo CurlErrorHandler::formatErrorReport($errno, 'https://invalid-host.example');

    $errorInfo = CurlErrorHandler::getErrorInfo($errno);
    echo "\nJSON格式错误信息:\n";
    echo json_encode($errorInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}

curl_close($ch);

示例 4:在生产环境中的错误监控

class CurlMonitor {
    private static $errorLogs = [];
    private static $successCount = 0;
    private static $errorCount = 0;

    public static function makeRequest($url, $options = []) {
        $ch = curl_init();

        // 添加请求ID用于跟踪
        $requestId = uniqid('curl_', true);
        $startTime = microtime(true);

        $defaultOptions = [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HEADER => true
        ];

        curl_setopt_array($ch, array_merge($defaultOptions, $options));

        $response = curl_exec($ch);
        $endTime = microtime(true);

        $info = curl_getinfo($ch);
        $errno = curl_errno($ch);

        $logEntry = [
            'request_id' => $requestId,
            'url' => $url,
            'start_time' => $startTime,
            'end_time' => $endTime,
            'duration' => $endTime - $startTime,
            'http_code' => $info['http_code'] ?? 0,
            'total_time' => $info['total_time'] ?? 0,
            'connect_time' => $info['connect_time'] ?? 0,
            'namelookup_time' => $info['namelookup_time'] ?? 0
        ];

        if ($errno) {
            $errorStr = curl_strerror($errno);
            $errorMsg = curl_error($ch);

            $logEntry['error'] = [
                'code' => $errno,
                'message' => $errorStr,
                'detail' => $errorMsg
            ];

            self::$errorLogs[] = $logEntry;
            self::$errorCount++;

            // 发送错误报警(这里只是模拟)
            self::sendAlert($logEntry);
        } else {
            $logEntry['success'] = true;
            self::$successCount++;
        }

        curl_close($ch);

        // 记录到监控日志
        self::logToFile($logEntry);

        return [
            'request_id' => $requestId,
            'success' => !$errno,
            'error' => $errno ? [
                'code' => $errno,
                'message' => $errorStr,
                'detail' => $errorMsg
            ] : null,
            'response' => $response,
            'info' => $info
        ];
    }

    private static function sendAlert($logEntry) {
        // 在实际应用中,这里可以发送邮件、Slack消息等
        $error = $logEntry['error'];
        $message = "cURL错误报警\n";
        $message .= "请求ID: {$logEntry['request_id']}\n";
        $message .= "URL: {$logEntry['url']}\n";
        $message .= "错误代码: {$error['code']}\n";
        $message .= "错误描述: " . curl_strerror($error['code']) . "\n";
        $message .= "详细错误: {$error['detail']}\n";
        $message .= "发生时间: " . date('Y-m-d H:i:s') . "\n";

        error_log($message);

        // 如果是严重错误,可以发送额外的通知
        if (in_array($error['code'], [6, 7, 28, 35])) {
            // 发送到监控系统
            error_log("严重cURL错误: {$error['code']} - {$logEntry['url']}");
        }
    }

    private static function logToFile($logEntry) {
        $logFile = __DIR__ . '/curl_monitor.log';
        $logLine = json_encode($logEntry, JSON_UNESCAPED_UNICODE) . PHP_EOL;

        // 在实际应用中,可以使用更专业的日志库
        file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
    }

    public static function getStats() {
        return [
            'success_count' => self::$successCount,
            'error_count' => self::$errorCount,
            'success_rate' => self::$successCount + self::$errorCount > 0
                ? round(self::$successCount / (self::$successCount + self::$errorCount) * 100, 2)
                : 0,
            'recent_errors' => array_slice(self::$errorLogs, -10) // 最近10个错误
        ];
    }

    public static function getErrorSummary() {
        $errorSummary = [];

        foreach (self::$errorLogs as $log) {
            $code = $log['error']['code'];
            if (!isset($errorSummary[$code])) {
                $errorSummary[$code] = [
                    'count' => 0,
                    'description' => curl_strerror($code),
                    'last_occurrence' => '',
                    'urls' => []
                ];
            }

            $errorSummary[$code]['count']++;
            $errorSummary[$code]['last_occurrence'] = date('Y-m-d H:i:s', (int)$log['start_time']);

            $url = $log['url'];
            if (!in_array($url, $errorSummary[$code]['urls'])) {
                $errorSummary[$code]['urls'][] = $url;
            }
        }

        // 按错误数量排序
        uasort($errorSummary, function($a, $b) {
            return $b['count'] <=> $a['count'];
        });

        return $errorSummary;
    }
}

// 使用示例
$urls = [
    'https://httpbin.org/get',
    'https://httpbin.org/status/200',
    'https://invalid-url.example',  // 会失败
    'https://httpbin.org/delay/2',
    'https://httpbin.org/status/404'
];

foreach ($urls as $url) {
    $result = CurlMonitor::makeRequest($url, [CURLOPT_TIMEOUT => 5]);

    if (!$result['success']) {
        echo "请求失败: {$url}\n";
        echo "错误: " . curl_strerror($result['error']['code']) . "\n";
    }
}

// 获取统计信息
$stats = CurlMonitor::getStats();
echo "\n=== 请求统计 ===\n";
echo "成功请求: {$stats['success_count']}\n";
echo "失败请求: {$stats['error_count']}\n";
echo "成功率: {$stats['success_rate']}%\n";

// 获取错误摘要
$errorSummary = CurlMonitor::getErrorSummary();
echo "\n=== 错误摘要 ===\n";
foreach ($errorSummary as $code => $summary) {
    echo "错误代码 {$code} ({$summary['description']}):\n";
    echo "  发生次数: {$summary['count']}\n";
    echo "  最后发生: {$summary['last_occurrence']}\n";
    echo "  涉及URL: " . implode(', ', array_slice($summary['urls'], 0, 3)) . "\n";
    if (count($summary['urls']) > 3) {
        echo "  等{$summary['count']}个URL\n";
    }
    echo "\n";
}

curl_strerror vs curl_error vs curl_errno

函数 返回类型 描述 示例返回值
curl_strerror() string|null 根据错误代码返回标准错误描述 "Couldn't resolve host name"
curl_error() string 返回最后一次cURL操作的详细错误信息 "Couldn't resolve host 'invalid-host'"
curl_errno() int 返回最后一次cURL操作的错误代码 6

注意事项

版本要求:curl_strerror() 函数需要PHP 5.5.0或更高版本。
使用建议:
  • 使用 curl_strerror() 获取人类可读的错误描述
  • 使用 curl_errno() 获取错误代码用于程序逻辑判断
  • 使用 curl_error() 获取详细的错误信息用于调试
  • 在生产环境中,建议将错误代码和描述都记录到日志中
最佳实践:
  • 始终检查cURL操作的返回值
  • 使用 curl_strerror() 为用户提供友好的错误信息
  • 记录详细的错误信息以便问题排查
  • 根据错误类型采取不同的恢复策略

常见问题

Q: curl_strerror() 和 curl_error() 有什么区别?

A: curl_strerror() 根据错误代码返回标准的错误描述,而 curl_error() 返回最后一次cURL操作的详细错误信息。前者更通用,后者更具体。

Q: curl_strerror() 会返回所有可能的错误代码描述吗?

A: 大多数常见的cURL错误代码都有对应的描述,但某些特定的或新版本的错误代码可能返回 null。建议在使用前检查返回值。

Q: 在生产环境中如何正确处理cURL错误?

A: 建议: 1. 记录错误代码和描述到日志系统 2. 根据错误类型实现重试机制 3. 为用户提供友好的错误信息 4. 监控错误率并设置报警 5. 定期分析错误模式以改进系统

相关函数