<?php

if ( !$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) ) {
    throw new Exception('socket_create failed: ' . socket_strerror(socket_last_error()) );
}
if (!$sb = socket_bind($server, '0.0.0.0', 8081) ) {
    throw new Exception('socket_bind failed: ' . socket_strerror(socket_last_error()) );
}
if (!$sl = socket_listen($server, 128)) {
    throw new Exception('socket_listen failed: ' . socket_strerror(socket_last_error()));
}

$read = array($server);
$write = $except = $clients = $readBuffer = $writeBuffer = array();

while (true) {
    socket_select($read, $write, $except, null);
    if (in_array($server, $read)) {
        if ( ($conn = socket_accept($server)) < 0 ) {
            throw new Exception('socket_accept() failed: '
                . socket_strerror(socket_last_error()) );
        }
        socket_set_nonblock($conn);
        $clients[intval($conn)] = $conn;
        $readBuffer[intval($conn)] = "";
        $writeBuffer[intval($conn)] = 0;
    }
    foreach ($read as $r) {
        if ($r == $server) continue;
        if (false === ($data = socket_read($r, 1024)) ) {
            /*throw new Exception( 'socket_read failed: '
                . socket_strerror(socket_last_error()) );*/
            /* То ли клиент отсоединился, то ли ошибка */
            unset(
                $readBuffer[intval($r)],
                $writeBuffer[intval($r)],
                $clients[intval($r)]
            );
        } elseif (feof($r)) {
            foreach ($clients as $client) {
                if ($client === $r) continue;
                $written = socket_write($client, "user " . intval($r) . ": "
                    . substr($readBuffer[intval($r)], $writeBuffer[intval($client)]) );
                $writeBuffer[intval($client)] += $written;
            }
        } else {
            $readBuffer[intval($r)] .= $data;
        }
    }
    $read = $clients;
    $write = $clients;
    $read[] = $server;
}