<?php
$servidorSocket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($servidorSocket,SOL_SOCKET,SO_REUSEADDR,1);
socket_bind($servidorSocket,'localhost',9000);
socket_listen($servidorSocket);
$clientes=[$servidorSocket];
$null=null;
while(true){
    $nuevoClienteLector=$clientes;
    socket_select($nuevoClienteLector,$null,$null,10);
    if(in_array($servidorSocket,$nuevoClienteLector)){
        $nuevoCliente=socket_accept($servidorSocket);
        echo "Socket aceptado.\n";
        $clientes[]=$nuevoCliente;
        $encabezado=socket_read($nuevoCliente,1024);
        handshake($nuevoCliente,$encabezado);
        $nuevoClienteIndex=array_search($servidorSocket,$nuevoClienteLector);
        unset($nuevoClienteLector[$nuevoClienteIndex]);
    }
    foreach($nuevoClienteLector as $cliente){
        while(socket_recv($cliente,$datosCliente,1024,0)>=1){
            $mensaje=decodificar($datosCliente);
            enviar($clientes,$mensaje);
            echo $mensaje."\n";
            break 2;
        }
        $datosCliente=@socket_read($cliente,1024,PHP_NORMAL_READ);
        if($datosCliente===false){
            $clienteIndex=array_search($cliente,$clientes);
            unset($clientes[$clienteIndex]);
            echo "Cliente desconectado.\n";
        }
    }
}
function enviar($clientes,$mensaje){
    $mensaje=codificar($mensaje);
    foreach($clientes as $cliente){
        @socket_write($cliente,$mensaje,strlen($mensaje));
    }
}
socket_close($servidorSocket);
function codificar($socketData){
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($socketData);
    
    if($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
    elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
    return $header.$socketData;
}
function decodificar($socketData) {
    $length = ord($socketData[1]) & 127;
    if($length == 126) {
        $masks = substr($socketData, 4, 4);
        $data = substr($socketData, 8);
    }
    elseif($length == 127) {
        $masks = substr($socketData, 10, 4);
        $data = substr($socketData, 14);
    }
    else {
        $masks = substr($socketData, 2, 4);
        $data = substr($socketData, 6);
    }
    $socketData = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $socketData .= $data[$i] ^ $masks[$i%4];
    }
    return $socketData;
}
function handshake($client_socket_resource,$received_header) {
    $headers = array();
    $lines = preg_split("/\r\n/", $received_header);
    foreach($lines as $line){
        $line = chop($line);
        if(preg_match('/\A(\S+): (.*)\z/', $line, $matches)) $headers[$matches[1]] = $matches[2];
    }
    $secKey = $headers['Sec-WebSocket-Key'];
    $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
    $buffer  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
    "Upgrade: websocket\r\n" .
    "Connection: Upgrade\r\n" .
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_socket_resource,$buffer,strlen($buffer));
}