简体   繁体   English

在PHP中检测cURL超时

[英]Detect cURL timeout in PHP

I'm trying to detect when a cURL request times out. 我正试图检测cURL请求何时超时。 I'm using curl_multi_exec if this makes a difference? 如果这有所不同,我正在使用curl_multi_exec?

The output of curl_errno() is 0 which suggests it was a success. curl_errno()的输出为0表示它是成功的。 However the output of curl_error() is: 但是curl_error()的输出是:

Operation timed out after 1435 milliseconds with 0 out of -1 bytes received 操作在1435毫秒后超时,接收到0个-1字节

Any ideas why the error code is good, but the error message exists? 任何想法为什么错误代码是好的,但错误信息存在? I would expect an error code of 28 for a timeout. 我希望超时的错误代码为28。

Also, is there anything I can check in curl_getinfo() for a timeout? 另外,有什么我可以在curl_getinfo()中检查超时吗?

I'm using PHP 5.4.4 / cURL 7.24.0. 我使用的是PHP 5.4.4 / cURL 7.24.0。

Edit 1 - Sample code: 编辑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);
}

When using curl_multi_exec() , you'll need to use curl_multi_info_read() to get the error code for specific handles. 使用curl_multi_exec() ,您需要使用curl_multi_info_read()来获取特定句柄的错误代码。 This is due to the way PHP interfaces with cURL in its easy and multiple interfaces, and how error codes are fetched on individual handles from cURL's curl_multi_info_read() function (see explanation below). 这是由于PHP在简单和多个接口中与cURL接口的方式,以及如何从cURL的curl_multi_info_read()函数在各个句柄上获取错误代码(请参阅下面的说明)。

Basically, if you are using multi handles, calling curl_errno() and curl_error() are not reliable or accurate. 基本上,如果您使用多个句柄,则调用curl_errno()curl_error()不可靠或不准确。

See this modified example from the manual : 请参阅手册中的此修改示例:

<?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]);
}

Output: 输出:

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

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

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

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

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

Explanation: 说明:

Specifically, this is due to how PHP's curl_exec() calls cURL's curl_easy_perform which returns a CURLcode (error code) and PHP specifies the cURL option CURLOPT_ERRORBUFFER which causes a buffer to automatically get filled with an error message if one occurs. 具体来说,这是由于PHP的curl_exec()调用cURL的curl_easy_perform返回CURLcode(错误代码),PHP指定了cURL选项CURLOPT_ERRORBUFFER ,这会导致缓冲区自动填充错误消息(如果发生)。

But when using PHP's curl_multi_exec() , PHP calls cURL's curl_multi_perform which returns immediately and doesn't return error codes for the multi handles. 但是当使用PHP的curl_multi_exec() ,PHP会调用cURL的curl_multi_perform ,它会立即返回并且不会返回多句柄的错误代码。 You must call cURL's curl_multi_info_read function to get error codes for the individual handles. 您必须调用cURL的curl_multi_info_read函数来获取各个句柄的错误代码。

PHP 5.5.0 provides a wrapper to cURL's curl_easy_strerror() which returns a string corresponding to a curl error code. PHP 5.5.0为cURL的curl_easy_strerror()提供了一个包装器,它返回一个对应于curl错误代码的字符串。

This can be really frustrating to debug as the documentation and examples on php.net are really poor relating to async curl. 这可能是非常令人沮丧的调试,因为php.net上的文档和示例与async curl相关性很差。

Here is some example code to help demonstrate what DOES work when it comes to curl_multi_exec: 下面是一些示例代码,以帮助演示curl_multi_exec中的DOES工作原理:

// 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");

        }
    }
}

With a main work loop like the above, you can then call it as many times as you need to. 通过上面的主要工作循环,您可以根据需要多次调用它。 Something like 就像是

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

I'm not going to print out the entire class. 我不打算打印全班。 You can make it do what you want. 你可以做它你想做的。

The important part is to check $status['result'] to determine if there was an error. 重要的是检查$status['result']以确定是否有错误。 Never rely on curl_getinfo($ch) as it is wrong in a multi_curl environment. 永远不要依赖curl_getinfo($ch)因为它在multi_curl环境中是错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM