PHP 5.6.0RC3 is available

stream_select

(PHP 4 >= 4.3.0, PHP 5)

stream_selectSurveille la modification d'un ou plusieurs flux

Description

int stream_select ( array &$read , array &$write , array &$except , int $tv_sec [, int $tv_usec = 0 ] )

stream_select() accepte un tableau de flux et attend que l'un d'entre eux change de statut. Cette opération est équivalente à ce que fait la fonction socket_select(), hormis le fait qu'elle travaille sur un flux.

Liste de paramètres

read

Les flux qui sont listés dans le paramètre read seront surveillés en lecture, c'est-à-dire si de nouveaux octets sont disponibles en lecture (pour être précis, si une lecture ne bloquera pas, ce qui inclut aussi les flux qui sont en fin de fichier, auquel cas un appel à la fonction fread() retournera une chaîne de taille 0).

write

Les flux qui sont listés dans le paramètre write seront surveillés en écriture (pour être précis, si une écriture ne bloquera pas).

except

Les flux qui sont listés dans le paramètre except seront surveillés pour voir si une exception est levée.

Note:

Lorsque stream_select() se termine, les tableaux read, write et except sont modifiés pour indiquer quels flux ont actuellement changé de statut.

Vous n'êtes pas obligés de remplir tous les tableaux arguments de la fonction stream_select(). Vous pouvez les laisser et utiliser un tableau vide, ou encore NULL. De plus, n'oubliez pas que ces tableaux sont passés par référence et seront modifiés une fois que stream_select() s'achève.
tv_sec

Les paramètres tv_sec et tv_usec forment le délai d'expiration, tv_sec spécifie le nombre de secondes tandis que tv_usec, le nombre de microsecondes. Le paramètre timeout représente la limite supérieure du temps que stream_select() doit attendre avant de se terminer. Si tv_sec et tv_usec sont tous les deux définis à 0, , stream_select() n'attendra pas de données - à la place, elle se terminera immédiatement, indiquant le statut courant du flux.

Si tv_sec vaut NULL, stream_select() peut se bloquer indéfiniment, se terminant uniquement lorsqu'un événement sur un des flux surveillés survient (ou si un signal interrompt l'appel système).

Avertissement

Utiliser un valeur de 0 vous permet de tester instantanément le statut des flux, mais il faut savoir qu'il n'est pas recommandé d'utiliser 0 dans une boucle, car cela va faire consommer énormément de processeur à votre script.

Il est bien mieux de spécifier une valeur de quelques secondes, même si vous devez surveiller et exécuter différents codes de manière simultanée. Par exemple, utiliser une valeur d'au moins 200000 microsecondes, vous réduirez considérablement la consommation processeur de votre script.

N'oubliez pas que la valeur d'expiration est la durée maximale d'attente, si rien ne se passe : stream_select() retournera un résultat dès que l'un des flux soumis est prêt à l'utilisation.

tv_usec

Voyez la description de tv_sec.

Valeurs de retour

En cas de succès, stream_select() retourne le nombre de flux qui ont évolué, ce qui peut être 0, si le délai d'expiration a été atteint avant que les flux n'évoluent. En cas d'erreur, la fonction retournera FALSE et un avertissement sera renvoyé (cela peut apparaître si l'appel système est interrompu par un signal entrant).

Exemples

Exemple #1 Exemple avec stream_select()

Cet exemple surveille si des données arrivent pour être lues soit dans $stream1, soit dans $stream2. Si le délai d'expiration vaut 0, la fonction se termine immédiatement :

<?php
/* Preparation du tableau de flux lecture */
$read   = array($stream1$stream2);
$write  NULL;
$except NULL;
if (
false === ($num_changed_streams stream_select($read$write$except0))) {
    
/* Gestion d'erreur */
} elseif ($num_changed_streams 0) {
    
/* Au moins un des flux a évolué  */
}
?>

Notes

Note:

À cause d'une limitation du moteur Zend actuel, il n'est pas possible de passer la valeur NULL directement comme paramètre d'une fonction qui s'attend à des paramètres passés par référence. Au lieu de cela, il est recommandé d'utiliser une variable temporaire, ou une expression dont le membre de gauche est une variable temporaire. Comme ceci :

<?php
$e 
NULL;
stream_select($r$w$e0);
?>

Note:

Assurez-vous de bien utiliser l'opérateur === lorsque vous recherchez des erreurs. Comme stream_select() peut retourner 0, une comparaison effectuée à l'aide de == l'évaluerait à TRUE :

<?php
$e 
NULL;
if (
false === stream_select($r$w$e0)) {
    echo 
"stream_select() failed\n";
}
?>

Note:

Si vous avez écrit ou lu dans un flux qui est retourné dans les tableaux de flux, soyez bien conscient que ces flux n'ont peut être pas écrit ou lu la totalité des données demandées. Soyez en mesure de lire un seul octet.

Note:

Quelques flux (comme zlib) ne peuvent pas être sélectionnés par cette fonction.

Note:

Notes aux utilisateurs de Windows : stream_select() utilisé sur une pipe retournée par proc_open() peut causer la perte de données sous Windows 98.

Utiliser la fonction stream_select() sur un pointeur de fichier retourné par proc_open() échouera et retournera FALSE sous Windows.

Voir aussi

add a note add a note

User Contributed Notes 13 notes

up
2
aidan at aidans dot org
7 years ago
Note that contrary to what the previous poster said, one is not able to use a stream resource as a key for an array. Rather, if you want to know which socket you are dealing with, consider using code similar to this:

<?php
$sockets
= array("sock_1" => $sock1, "sock_2" => $sock2, "sock_3" => $sock_3);

$read = $write = $error = $sockets;
$num = stream_select($read, $write, $error, 10);
if (
$n > 0) {
    foreach (
$read as $r) {
       
$key = array_search($r, $sockets);
       
// $key will be "sock_1", "sock_2", "sock_3", etc.
   
}
}
?>

Hope that helps someone out there!
up
2
Ben
7 years ago
You can key on file descriptors just fine by casting them to an int or a string, which returns what you would expect.
up
2
maartenwolzak at gmail dot com
7 years ago
Note that you should change the calctimeout function below to divide the outcome by 1.000.000 otherwise you'll be waiting for two years instead of one minute for the socket to timeout...

<?php

// The function to calculate the timeout
function calctimeout($maxtime, $starttime)
{
   return (
$maxtime - ((microtime(true) - $starttime) * 1000000))/1000000;
}

?>
up
2
phpdoc at shemesh dot biz
9 years ago
Please note that, on return, the key of "read" will be zero based, serially numbered according to the streams for which there is read data ready only. In other words, if you want to know which of the original streams placed in "read" is ready, there is no immediate way of knowing that.

If you want to know which of the original stream is which, you can either use "==", or possibly set a reverse map array, in which the stream is the key, and the key to the original "read" array is the data.
up
2
aidan at php dot net
10 years ago
If you want to set an absolute maximum execution time for stream_select in a loop, it's important to decrement the max_time value passed to stream_select.

<?php
// The maximum time for execution in milliseconds
$maxtime = 200000;
// The time the loop started
$starttime = microtime(true);
// Original array of sockets
$r = $orig_sockets;

// The function to calculate the timeout
function calctimeout($maxtime, $starttime)
{
    return
$maxtime - ((microtime(true) - $starttime) * 1000000);
}

while (
stream_select($r, $w = null, $e = null, 0, calctimeout($maxtime, $starttime)) !== 0)
{
   
// loop through the sockets that showed activity
   
foreach ($r as $socket) {
       
// $socket talked
   
}

   
// stream_select modifies the contents of $r
    // in a loop we should replace it with the original
   
$r = $orig_sockets;
}

?>
up
1
aks at esoft dot dk
3 years ago
stream_select() looks deceptively like a simple wrapper around POSIX select(2).

But beware: while select(2) allows you to pass no file descriptors and use it as a "portable subsecond sleep", PHP will complain with "Warning: stream_select(): No stream arrays were passed in ****" if all arrays are empty or null, and it WONT sleep, it will return immediately. So... if the number of file descriptors you have isn't static, you have to deal with the special case yourself.
up
1
lynch at php dot net
4 years ago
Note: At least one of the input arrays must be non-empty, or you get an E_WARNING message:
PHP Warning:  stream_select(): unable to select [9]: Bad file descriptor (max_fd=0) in
up
1
jerrywilborn at gmail dot com
5 years ago
http://bugs.php.net/bug.php?id=42682

This function will not return the number of changed streams under certain systems with older versions, but instead it will return '0'. Be careful.
up
1
php at richardneill dot org
5 years ago
Note that reading from a regular file which is on end-of-file will *not* block. You'll get a non-blocking, zero-byte read.  However, stream_select *will* block if the input is a pipe, and there is no more data to be had.
up
1
Maxdamantus
6 years ago
Simple stream_select wrapper.. Returns the first stream in the array, and sets parameter 2 to the key (So that it is easy to identify what received data):

<?php
function select($array, &$vkey, $timeout=0){
   
$select = array();
   
$null = NULL;
    foreach(
$array as $key => $sock){
       
$x = count($select);
       
$select[$x] = $sock;
       
$keys[$x] = $key;
    }
    if(
stream_select($select, $null, $null, $timeout)){
        foreach(
$keys as $key){
            if(
$array[$key] == $select[0]){
               
$vkey = $key;
                return(
$select[0]);
            }
        }
    }
}

$streams = array("foo" => $stream_one, "bar" => $stream_two); // Create an array of two (already existant) streams.
if($new = select($streams, $key, 60)){ //Sets $new to the resource that next gets new data, and $key to either "foo", or "bar", depending which one it is.
   
echo $key.":".stream_get_line($new, 2048)."\n";
}
?>
up
1
bluej100@gmail
6 years ago
@mbaynton at gmail dot com

A handy syntactic trick:

<?php
$r
= Array($stream1, $stream2);
stream_select($r, $w = null, $x = null, 1337);
?>

I've seen it recommended elsewhere in the documentation for clarifying magic arguments so maintainers don't have to go check the function itself, but it also solves your problem here.
up
0
rob at associatedtechs dot com
13 days ago
If you try to use stream_select() with fread(), you may get bit by a combination of bugs (https://bugs.php.net/bug.php?id=52602 and https://bugs.php.net/bug.php?id=51056). As of PHP 5.5.10, fread() and stream_select() don't reliably play well together.

If you need stream_select() and you don't need an encrypted connection (e.g. TLS), use stream_socket_recvfrom() instead of fread().

I can't find a way to reliably handle an encrypted connection with blocking functions in PHP; non-blocking might be the only way to do it.
up
0
mark2xv at gmail dot com
11 months ago
If you're getting unexplainable problems with nonblocking sockets using stream_select, disable the buffers using:

stream_set_read_buffer($socket, 0);
stream_set_write_buffer($socket, 0);

For some reason when writing (in total) ~256k, sockets start returning FALSE when reading, yet always appear in the stream_select arrays. This fixed that problem. (for us.)
To Top