在 PHP 中检测 cURL 超时

6
我正在尝试检测cURL请求超时的情况。如果使用curl_multi_exec,则可能会有所不同?
curl_errno()的输出为0,这表明它是成功的。但是,curl_error()的输出是:
操作超时,经过1435毫秒,收到-1字节中的0个
你有什么想法,为什么错误代码是好的,但错误消息存在?我期望超时的错误代码为28。
另外,在curl_getinfo()中是否有任何可以检查超时的内容?
我使用的是PHP 5.4.4 / cURL 7.24.0。
编辑1-示例代码:
$mh = curl_multi_init();
curl_multi_add_handle($mh,$a);
curl_multi_add_handle($mh,$b);
curl_multi_add_handle($mh,...);

do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) == -1) usleep(100);
    do { $mrc = curl_multi_exec($mh, $active); }
    while ($mrc == CURLM_CALL_MULTI_PERFORM);
}

1
你能发布一下你的cURL代码吗? - Guns
当然 - 我已经在上面添加了。谢啦! - Kit
不确定为什么会发生这种情况。您可以使用 CURLOPT_CONNECTTIMEOUTCURLOPT_CONNECTTIMEOUT_MS 来指定超时时间以尝试强制产生错误。 - ThomasEllis
我强制将其设置为1秒。似乎足以获取错误消息。 CURLOPT_CONNECTTIMEOUT_MS 的结果相同。 - Kit
2个回答

4
当使用curl_multi_exec()时,您需要使用curl_multi_info_read()获取特定句柄的错误代码。这是由于PHP与cURL在其易用和多重接口中进行交互以及如何从cURL的curl_multi_info_read()函数获取单个句柄上的错误代码的方式(请参见下面的说明)。
基本上,如果您正在使用多个句柄,则调用curl_errno()curl_error()不可靠或准确。
请参阅来自手册的此修改后的示例:
<?php

$urls = array(
   "http://www.cnn.com/",
   "http://www.bbc.co.uk/",
   "http://www.yahoo.com/",
   'http://wijgeiwojgieowjg.com/',
   'http://www.example.com/',
);

$infos = array();

$mh = curl_multi_init();

foreach ($urls as $i => $url) {
    $conn[$i] = curl_init($url);
    curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1);

    if (strpos($url, 'example.com') !== false) {
        // set a really short timeout for one url
        curl_setopt($conn[$i], CURLOPT_TIMEOUT_MS, 10);
    }

    curl_multi_add_handle($mh, $conn[$i]);
}

do {
    $status = curl_multi_exec($mh, $active);

    if (($info = curl_multi_info_read($mh)) !== false) {
        $infos[$info['handle']] = $info;
    }

} while ($status === CURLM_CALL_MULTI_PERFORM || $active);

foreach ($urls as $i => $url) {
    $info = $infos[$conn[$i]];

    echo "$url returned code {$info['result']}";
    if (version_compare(PHP_VERSION, '5.5.0') >= 0) {
        echo ": " . curl_strerror($info['result']);
    }
    echo "\n";

    if ($info['result'] === 0) {
        $res[$i] = curl_multi_getcontent($conn[$i]);
    }

    curl_close($conn[$i]);
}

输出:

http://www.cnn.com/ 返回代码 0

http://www.bbc.co.uk/ 返回代码 0

http://www.yahoo.com/ 返回代码 0

http://wijgeiwojgieowjg.com/ 返回代码 6

http://www.example.com/ 返回代码 28

说明:

具体来说,这是由于PHP的curl_exec()调用cURL的curl_easy_perform返回一个CURLcode(错误代码),而PHP指定了cURL选项CURLOPT_ERRORBUFFER,如果发生错误,缓冲区会自动填充错误消息。

但是,在使用PHP的curl_multi_exec()时,PHP调用cURL的curl_multi_perform立即返回,并且不返回多个句柄的错误代码。您必须调用cURL的curl_multi_info_read函数以获取各个句柄的错误代码。

PHP 5.5.0提供了对cURL的curl_easy_strerror()的包装,它返回与curl错误代码相对应的字符串。


太棒了,谢谢。正是我需要的。然而,我目前使用curl_getinfo来检查响应HTTP代码。但这样做不安全吗?我试图检查间歇性网络问题,这会导致某些请求返回500。 - Kit
1
дҪҝз”Ёcurl_getinfoеҸҜд»Ҙд»ҺеҚ•дёӘhandleдёӯиҺ·еҸ–дҝЎжҒҜ(дҫӢеҰӮHTTPе“Қеә”д»Јз Ғ)жҳҜеҸҜиЎҢзҡ„гҖӮеҰӮжһңд»Һcurl_multi_info_readиҝ”еӣһдәҶдёҖдёӘжҲ–еӨҡдёӘй”ҷиҜҜжқЎд»¶пјҢеҲҷжқҘиҮӘcurl_getinfoзҡ„йғЁеҲҶжҲ–е…ЁйғЁдҝЎжҒҜеҸҜиғҪжІЎжңүеЎ«е……жҲ–зӣёе…ігҖӮ - drew010
有道理。谢谢! - Kit

0
这对于调试来说可能非常令人沮丧,因为 php.net 上关于异步 curl 的文档和示例真的很差。
以下是一些示例代码,以帮助说明在使用 curl_multi_exec 时可以正常工作的内容:
// Main work loop

do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while($status = curl_multi_info_read($mh)) {
    if($status['msg'] == CURLMSG_DONE) {

        $errno = $status['result'];
        $errstr = curl_strerror($errno);

        if($errno == CURLE_OK) {

            // This request completed successfully

            // Do something with the info
            $info = curl_getinfo($status['handle');

        } else {

            // There was an error handling this request,
            // like a timeout or something.
            // Note: curl_errno($ch) will probably say success
            // but it's lying to you. Ignore it.

            fwrite(STDERR, "Request failed: Error($errno): $errstr\n");

        }
    }
}

有了像上面这样的主工作循环,您可以根据需要多次调用它。就像这样

while($this->workRemaining()) {
    $this->work();
    usleep(100); // Sleep, or better yet do something productive
}

我不会打印整个类。你可以让它做你想要的事情。

重要的部分是检查$status['result']以确定是否出现错误。永远不要依赖于curl_getinfo($ch),因为在多curl环境中它是错误的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接