curl_multi_select

(PHP 5, PHP 7, PHP 8)

curl_multi_selectWartet, bis Lesen oder Schreiben auf einer der cURL-Mehrfach-Handle-Verbindungen möglich ist

Beschreibung

curl_multi_select(CurlMultiHandle $multi_handle, float $timeout = 1.0): int

Blockiert die Ausführung des Skripts, bis ein cURL-Handle, das an das cURL-Mehrfach-Handle angehängt ist, in der Lage ist, beim nächsten Aufruf von curl_multi_exec() fortzufahren oder bis das Zeitlimit erreicht ist (je nachdem, was zuerst eintritt).

Parameter-Liste

multi_handle

Ein von curl_multi_init() zurückgegebenes cURL-Multihandle.

timeout

Zeit in Sekunden, die auf eine Antwort vom den aktiven cURL-Mehrfach-Handle-Verbindungen gewartet wird.

Rückgabewerte

Gibt bei erfolgreicher Ausführung die Anzahl der aktiven Bezeichner in der Bezeichner-Sammlung zurück. Dies kann 0 sein, wenn es bei keinem der Bezeichner eine Aktivität gab. Tritt ein Fehler auf, gibt diese Funktion -1 zurück, wenn die Auswahl (durch den zugrundeliegenden Systemaufrufs select()) fehlgeschlagen ist.

Fehler/Exceptions

Wenn timeout kleiner als 0 oder größer als PHP_INT_MAX ist, wird ein ValueError geworfen.

Changelog

Version Beschreibung
8.4.0 Wirft nun einen ValueError, wenn timeout kleiner als 0 oder größer als PHP_INT_MAX ist.
8.0.0 multi_handle erwartet nun eine CurlMultiHandle-Instanz; vorher wurde eine Ressource erwartet.

Siehe auch

add a note

User Contributed Notes 8 notes

up
41
nevil85 at gmail dot com
10 years ago
Even after so many distro releases, in PHP v5.5.9 and libcurl v7.35.0, curl_multi_select still returns -1. The only work around here is to wait and proceed like nothing ever happened. You have to determine the "wait" required here.

In my application a very small interval like usleep(1) worked. For example:

<?php
// While we're still active, execute curl
$active = null;
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);

while (
$active && $mrc == CURLM_OK) {
// Wait for activity on any curl-connection
if (curl_multi_select($multi) == -1) {
usleep(1);
}

// Continue to exec until curl is ready to
// give us more data
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);
}
?>

Internally php curl_multi_select uses libcurl curl_multi_fdset function and its libcurl documentation says :
http://curl.haxx.se/libcurl/c/curl_multi_fdset.html

"When libcurl returns -1 in max_fd, it is because libcurl currently does something that isn't possible for your application to monitor with a socket and unfortunately you can then not know exactly when the current action is completed using select(). When max_fd returns with -1, you need to wait a while and then proceed and call curl_multi_perform anyway. How long to wait? I would suggest 100 milliseconds at least, but you may want to test it out in your own particular conditions to find a suitable value.

When doing select(), you should use curl_multi_timeout to figure out how long to wait for action."

Untill PHP implements curl_multi_timeout() we have to play with our application and determine the "wait".
up
3
bishop at php dot net
5 years ago
Before PHP 7.1.23 and 7.2.11, curl_multi_select() would return -1 if cURL had no open file descriptors. Since then, assuming libcurl 7.28 or higher, curl_multi_select() will return 0 if cURL has no open file descriptors and -1 on error.

See https://bugs.php.net/bug.php?id=76480

This is a BC break. See https://bugs.php.net/bug.php?id=77030
up
16
vigo dot von dot harrach at gmx dot de
12 years ago
curl_multi_select($mh, $timeout) simply blocks for $timeout seconds while curl_multi_exec() returns CURLM_CALL_MULTI_PERFORM. Otherwise, it works as intended, and blocks until at least one connection has completed or $timeout seconds, whatever happens first.

For that reason, curl_multi_exec() should always be wrapped:

<?php
function full_curl_multi_exec($mh, &$still_running) {
do {
$rv = curl_multi_exec($mh, $still_running);
} while (
$rv == CURLM_CALL_MULTI_PERFORM);
return
$rv;
}
?>

With that, the core of "multi" processing becomes (ignoring error handling for brevity):

<?php
full_curl_multi_exec
($mh, $still_running); // start requests
do { // "wait for completion"-loop
curl_multi_select($mh); // non-busy (!) wait for state change
full_curl_multi_exec($mh, $still_running); // get new state
while ($info = curl_multi_info_read($mh)) {
// process completed request (e.g. curl_multi_getcontent($info['handle']))
}
} while (
$still_running);
?>

Note that after starting requests, retrieval is done in the background - one of the better shots at parallel processing in PHP.
up
10
public at grik dot net
16 years ago
This function blocks the calling process until there is activity on any of the connections opened by the curl_multi interface, or until the timeout period has expired.
In other words, it waits for data to be received in the opened connections.

Internally it fetches socket pointers with "curl_multi_fdset()" and runs the "select()" C function.
It returns in 3 cases:
1. Activity is detected on any socket;
2. Timeout has ended (second parameter);
3. Process received any signal (#man kill).

The function returns an integer:
* In case of activity it returns a number, usually 1.
I suppose, it returns the number of connections with activity detected.
* If timeout expires it returns 0
* In case of error it returns -1

Thanks for attention, hope this helps.
up
4
xxavalanchexx at gmail dot com
10 years ago
According to https://bugs.php.net/bug.php?id=61141:

On Windows setups using libcurl version 7.24 or later (which seems to correspond to PHP 5.3.10 or later), you may find that this always returns -1. This is, apparently, not strictly a bug: according to the libcurl documentation, you should add your own sleep if curl_multi_select returns -1.

For example:
<?php
/* setup $mh */

$active = null;
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);
}

/* close $mh */
?>
up
6
Anonymous
11 years ago
In 5.3.9+, curl_multi_select always returns -1. If this is your case, just wait a bit and then proceed like nothing ever happened:
<?php
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);

while (
$active && $mrc == CURLM_OK) {
//check for results and execute until everything is done

if (curl_multi_select($multi) == -1) {
//if it returns -1, wait a bit, but go forward anyways!
usleep(100);
}

//do something with the return values
while(($info = curl_multi_info_read($multi)) !== false){
if (
$info["result"] == CURLE_OK){
$content = curl_multi_getcontent($info["handle"]);
do_something($content);
}
}
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);
}
?>
up
1
gib-o-master
3 years ago
NOTE: current implementation of `curl_multi_select` doesn't block and doesn't respect timeout parameter (maybe will be fixed later, in this case just remove the usleep call)

here, i would like to post my working/tested example of proper usage of this function:

```
$running = 1;
while ($running)
{
# execute request
if ($a = curl_multi_exec($this->murl, $running)) {
throw BotError::text("curl_multi_exec[$a]: ".curl_multi_strerror($a));
}
# check finished
if (!$running) {
break;
}
# wait for activity
while (!$a)
{
if (($a = curl_multi_select($this->murl, $timeout)) < 0)
{
throw BotError::text(
($a = curl_multi_errno($this->murl))
? "curl_multi_select[$a]: ".curl_multi_strerror($a)
: 'system select failed'
);
}
usleep($timeout * 1000000);# should be <=1
}
}
```
up
6
Alex Palmer
12 years ago
On php 5.3.18+ be aware that curl_multi_select() may return -1 forever until you call curl_multi_exec().
See https://bugs.php.net/bug.php?id=63411 for more information.
To Top