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.(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
stream_select — Surveille la modification d'un ou plusieurs flux
&$read,&$write,&$except,$seconds,$microseconds = nullstream_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.
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,writeetexceptsont modifiés pour indiquer quels flux ont actuellement changé de statut. Les clés originales du tableau sont préservées.
seconds
       Les paramètres seconds et
       microseconds
       forment le délai d'expiration,
       seconds spécifie le nombre de secondes
       tandis que microseconds, 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 seconds et 
       microseconds 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 seconds 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).
      
        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.
microseconds
       Voyez la description de seconds.
      
   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).
  
| Version | Description | 
|---|---|
| 8.1.0 | microsecondsest désormais nullable. | 
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, $except, 0))) {
    /* Gestion d'erreur */
} elseif ($num_changed_streams > 0) {
    /* Au moins un des flux a évolué  */
}
?>Note:
À cause d'une limitation du moteur Zend actuel, il n'est pas possible de passer la valeur
nulldirectement 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, $e, 0);
?>
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, $e, 0)) {
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: Compabilité Windows
Utiliser la fonction stream_select() sur un pointeur de fichier retourné par proc_open() échouera et retournera
falsesous Windows.
STDINfdepuis une console change son statut dés que n'importe quel évenements d'entrées sont disponible, mais lire depuis un flux peut toujours être bloquant.
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.When stream_select() fails you SHOULD NOT use the results of the arrays (i.e. read, write, except) that were passed into it as parameters. While doing so anyway won't trigger undefined behaviour, you are depending on unspecified behaviour that by definition is not guaranteed.
At the time of writing the PHP 7.2 interpreter does not modify the arrays upon stream_select() failure (see the code around https://github.com/php/php-src/blob/php-7.2.14/ext/standard/streamsfuncs.c#L842) thus a PHP program that doesn't heed the advice above can deceive itself as to the state of those streams.
(Hopefully this warning can be added to the main documentation one day)Maintaining connection with multiple clients can be tricky, PHP script is single-thread process, so if you like to do more than one thing at once (like waiting for new connections and waiting for new data), you’ll have to use some sort of multiplexing. 
<?php
$socket = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
stream_set_blocking($socket, 0);
$connections = [];
$read = [];
$write = null;
$except = null;
while (1) {
    // look for new connections
    if ($c = @stream_socket_accept($socket, empty($connections) ? -1 : 0, $peer)) {
        echo $peer.' connected'.PHP_EOL;
        fwrite($c, 'Hello '.$peer.PHP_EOL);
        $connections[$peer] = $c;
    }
    // wait for any stream data
    $read = $connections;
    if (stream_select($read, $write, $except, 5)) {
        foreach ($read as $c) {
            $peer = stream_socket_get_name($c, true);
            if (feof($c)) {
                echo 'Connection closed '.$peer.PHP_EOL;
                fclose($c);
                unset($connections[$peer]);
            } else {
                $contents = fread($c, 1024);
                echo $peer.': '.trim($contents).PHP_EOL;
            }
        }
    }
}
?>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;
}
?>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;
}
?>Make sure not to pass the same variable in the 3 arguments to stream_select, or you'll only get the results from one of them and the others will be overwritten.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.)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.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.You can key on file descriptors just fine by casting them to an int or a string, which returns what you would expect.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.If you use stream_select() with a blocking stream, you are doing it wrong!
Just because this function returns something in one or more of the arrays does NOT mean that a future read or write operation will not block.
The above sentence is the most important sentence you will ever read regarding stream manipulation.  Using stream_select() with blocking streams is a very common amateur mistake and causes major headaches when tracking down usage of this and similar select() system functions.  PHP (and really the underlying OS) should verify that the supplied stream set is not blocking and throw an error/exception if any socket is set to block so that people are forced to fix their code.  The documentation for stream_select() is, at best, misleading.
If you want a non-blocking stream, then set the stream to not block.  Otherwise, live with the blocking stream.  That is, after all, the whole point of blocking - to block indefinitely until the operation completes.  select() is built for non-blocking streams ONLY.  Any other use will result in very hard to track down bugs.
I got the above lecture many years ago after encountering the very bugs I mention.  I fixed my code and now correct similar mistakes when I run into the issue elsewhere.  Writing code for non-blocking streams is simpler than trying to write hacks for blocking streams with select() functions and ending up with application bugs.