【问题标题】:php curl multi error handlerphp curl 多错误处理程序
【发布时间】:2018-01-30 10:22:24
【问题描述】:

我想在我的错误处理程序中捕获 curl 错误和警告,这样它们就不会得到echoed 给用户。为了证明所有错误都已被捕获,我将$err_start 字符串添加到错误中。目前这里是我的代码的工作(但简化)sn-p(在浏览器中运行,而不是 cli):

<?php
set_error_handler('handle_errors');
test_curl();
function handle_errors($error_num, $error_str, $error_file, $error_line)
{           
    $err_start = 'caught error'; //to prove that the error has been properly caught
    die("$err_start $error_num, $error_str, $error_file, $error_line<br>");
}           
function test_curl()
{   
    $curl_multi_handle = curl_multi_init();
    $curl_handle1 = curl_init('iamdooooooooooown.com');
    curl_setopt($curl_handle1, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($curl_multi_handle, $curl_handle1);
    $still_running = 1;
    while($still_running > 0) $multi_errors = curl_multi_exec($curl_multi_handle, $still_running);
    if($multi_errors != CURLM_OK) trigger_error("curl error [$multi_errors]: ".curl_error($curl_multi_handle), E_USER_ERROR);
    if(strlen(curl_error($curl_handle1))) trigger_error("curl error: [".curl_error($curl_handle1)."]", E_USER_ERROR);
    $curl_info = curl_getinfo($curl_handle1); //info for individual requests
    $content = curl_multi_getcontent($curl_handle1);
    curl_multi_remove_handle($curl_multi_handle, $curl_handle1);
    curl_close($curl_handle1);
    curl_multi_close($curl_multi_handle);
}
?>

请注意,我的完整代码有多个并行请求,但问题仍然表现为单个请求,如此处所示。另请注意,此代码 sn-p 中显示的错误处理程序非常基本 - 我的实际错误处理程序不会因警告或通知而死,因此无需在这方面对我进行培训。

现在,如果我尝试卷曲当前已关闭的主机,那么我成功捕获了卷曲错误并且我的脚本因以下原因而死:

caught error 256, curl error: [Couldn't resolve host 'iamdooooooooooown.com'], /var/www/proj/test_curl.php, 18

但是我的错误处理函数没有捕获到以下警告,并且正在被echoed 到页面:

Warning: (null)(): 3 is not a valid cURL handle resource in Unknown on line 0

我想在我的错误处理程序中捕获此警告,以便我可以记录它以供以后检查。

我注意到的一件事是,警告仅在 curl 代码位于函数内部时才会出现 - 当代码处于最高范围级别时不会发生。是否有可能在 test_curl() 函数的范围内无法访问 curl 全局变量之一(例如 CURLM_OK)?

我正在使用 PHP 版本 5.3.2-1ubuntu4.19

修改

  • 更新了代码 sn-p 以充分展示错误
  • 未捕获的警告仅在函数或类方法中出现

【问题讨论】:

  • 你有启用xdebug.scream设置的Xdebug吗?
  • 我不这么认为。这是否比set_error_handler() 捕获更多错误?
  • 看看this answer。它可能会有所帮助。
  • @Jack 感谢您的测试。我已经更新了代码 sn-p - 令我惊讶的是,只有当代码在函数或方法中时才会出现警告!
  • 现在它只显示caught error 256, curl error: [Couldn't resolve host 'iamdooooooooooown.com'], /home/xxx/curl.php, 18&lt;br&gt;,没有其他错误。

标签: php curl error-handling curl-multi


【解决方案1】:

我认为我不同意您捕获错误的方式...您可以尝试

$nodes = array(
        "http://google.com",
        "http://iamdooooooooooown.com",
        "https://gokillyourself.com"
);

echo "<pre>";
print_r(multiplePost($nodes));

输出

Array
(
    [google.com] => #HTTP-OK 48.52 kb returned
    [iamdooooooooooown.com] => #HTTP-ERROR 0  for : http://iamdooooooooooown.com
    [gokillyourself.com] => #HTTP-ERROR 0  for : https://gokillyourself.com
)

使用的功能

function multiplePost($nodes) {
    $mh = curl_multi_init();
    $curl_array = array();
    foreach ( $nodes as $i => $url ) {
        $url = trim($url);
        $curl_array[$i] = curl_init($url);
        curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl_array[$i], CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)');
        curl_setopt($curl_array[$i], CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($curl_array[$i], CURLOPT_TIMEOUT, 15);
        curl_setopt($curl_array[$i], CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($curl_array[$i], CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($curl_array[$i], CURLOPT_SSL_VERIFYPEER, 0);
        curl_multi_add_handle($mh, $curl_array[$i]);
    }
    $running = NULL;
    do {
        usleep(10000);
        curl_multi_exec($mh, $running);
    } while ( $running > 0 );
    $res = array();

    foreach ( $nodes as $i => $url ) {
        $domain = parse_url($url, PHP_URL_HOST);
        $curlErrorCode = curl_errno($curl_array[$i]);
        if ($curlErrorCode === 0) {
            $info = curl_getinfo($curl_array[$i]);
            $info['url'] = trim($info['url']);
            if ($info['http_code'] == 200) {
                $content = curl_multi_getcontent($curl_array[$i]);
                $res[$domain] = sprintf("#HTTP-OK %0.2f kb returned", strlen($content) / 1024);
            } else {
                $res[$domain] = "#HTTP-ERROR {$info['http_code'] }  for : {$info['url']}";
            }
        } else {
            $res[$domain] = sprintf("#CURL-ERROR %d: %s ", $curlErrorCode, curl_error($curl_array[$i]));
        }
        curl_multi_remove_handle($mh, $curl_array[$i]);
        curl_close($curl_array[$i]);
        flush();
        ob_flush();
    }
    curl_multi_close($mh);
    return $res;
}

【讨论】:

  • 谢谢!我显然希望主机返回 curl 错误,但正如您的代码所示,有一个 http 错误,但没有 curl 错误。根据您的代码,只有在curl_errno() 不返回0 时才应调用curl_error()。否则curl_error() 似乎会打印出无法抑制的警告。奇怪的是,curl_errno() 在主机关闭时不返回 52 (CURLE_GOT_NOTHING)。干杯!
【解决方案2】:

这可能是 php-curl 的一个错误。删除以下行后,一切正常:

if(strlen(curl_error($curl_handle1))) trigger_error("curl error: [".curl_error($curl_handle1)."]", E_USER_ERROR);

据我所知,curl 关闭的主机正在以某种方式破坏 $curl_handle1,而 curl_error() 函数还没有准备好。要解决这个问题(直到修复错误),只需测试curl_getinfo() 返回的http_code 是否为0。如果是0,则不要使用curl_error函数:

if($multi_errors != CURLM_OK) trigger_error("curl error [$multi_errors]: ".curl_error($curl_multi_handle), E_USER_ERROR);
$curl_info = curl_getinfo($curl_handle1); //info for individual requests
$is_up = ($curl_info['http_code'] == 0) ? 0 : 1;
if($is_up && strlen(curl_error($curl_handle1))) trigger_error("curl error: [".curl_error($curl_handle1)."]", E_USER_ERROR);

这不是一个非常优雅的解决方案,但现在可能不得不这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 2010-12-26
    • 1970-01-01
    相关资源
    最近更新 更多