I'm trying to detect when a cURL request times out. I'm using curl_multi_exec if this makes a difference?
The output of curl_errno() is 0 which suggests it was a success. However the output of curl_error() is:
Operation timed out after 1435 milliseconds with 0 out of -1 bytes received
Any ideas why the error code is good, but the error message exists? I would expect an error code of 28 for a timeout.
Also, is there anything I can check in curl_getinfo() for a timeout?
I'm using PHP 5.4.4 / cURL 7.24.0.
Edit 1 - Sample code:
$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. 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).
Basically, if you are using multi handles, calling curl_errno()
and curl_error()
are not reliable or accurate.
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.bbc.co.uk/ returned code 0
http://www.yahoo.com/ returned code 0
http://wijgeiwojgieowjg.com/ returned code 6
http://www.example.com/ returned code 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.
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. You must call cURL's curl_multi_info_read
function to get error codes for the individual handles.
PHP 5.5.0 provides a wrapper to cURL's curl_easy_strerror()
which returns a string corresponding to a curl error code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With