Why does curl_errno() return 0 when there was errors in combination with curl_multi_init()?

1k Views Asked by At

I have a list of domains which i want to check if they are active or not. I can check each one separately but I'm having hard time getting the batch to work.

  $c200= array();
  $c301= array();
  $c302= array();

$urls=array();
  foreach (new SplFileObject("oList.txt") as $line) {
    $urls[]=$line;

}
//print_r($urls);

$mh = curl_multi_init();
foreach ($urls as $key => $value) {
  $ch[$key] =curl_init($value);
  curl_setopt($ch[$key], CURLOPT_HEADER, true);
  curl_setopt($ch[$key], CURLOPT_TIMEOUT, 10);
  curl_multi_add_handle($mh, $ch[$key]);

}

do{
  curl_multi_exec($mh, $running);
  curl_multi_select($mh);
}while ($running > 0);

foreach (array_keys($ch) as $key) {

  echo curl_getinfo($ch[$key], CURLINFO_HTTP_CODE);
  echo "\n";

  curl_multi_remove_handle($mh, $ch[$key]);
}
curl_multi_close($mh)

I wrote the above code but it gives me zeros as output. any help would be appreciated.

1

There are 1 best solutions below

8
Christoph On

curl_errno() does not return the resulting code if it's used inside curl_multi.

It seems it is undocumented but if an error occures inside a curl_multi() then the resources will not have resulting error-code until curl_multi_info_read() is called. There is a referencing bug/documentation request: https://bugs.php.net/bug.php?id=79318&thanks=4

Original answer

Usually when I interfere with a 0 as response code then I have a local issue (dns, network, ssl, url..).

In order to dig further you can check if curl had an error with the execution. This can be checked by curl_errno() which returns an curl error number and curl_error() which will return an descriptive error string.

The error-code and error-message will be perhaps one of those you can find here: https://curl.haxx.se/libcurl/c/libcurl-errors.html

EDIT #2

If you work with curl_multi you need to call curl_multi_info_read() once to get the resulting codes. Below is an example how you can fetch the relevant result entry.

// your code...

do {
    curl_multi_exec($mh, $running);
    curl_multi_select($mh);
} while ($running > 0);

while ($result = curl_multi_info_read($mh)) {
    if ($result['result'] == CURLM_OK) {
        echo 'Success: ' . curl_getinfo($result['handle'], CURLINFO_HTTP_CODE) . "\n";
    } else {
        echo 'Error: ' . curl_strerror($result['result']) . "\n";
    }
}

A real test will now result the following:

$ php test.php 
Error: Couldn't resolve host name
Success: 200
Success: 200

EDIT #3

Additionally it seems that calling curl_multi_info_read($mh) does the trick as well and populates internally the information into your existing handles/resources.

In my opinion this is a bit misleading. I will create a bug/documentation report to the php as I can't find anything about it. I just stumbled upon as I checked how guzzle did the low-level implementation of it.

// your code...

do {
    curl_multi_exec($mh, $running);
    curl_multi_select($mh);
} while ($running > 0);

while ($result = curl_multi_info_read($mh)) {}

foreach($ch as $handle) {
    echo "Handle: " . curl_errno($handle) . PHP_EOL;
}