<?php
$address = '0.0.0.0';
$port = 12345;

$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($server, $address, $port);
socket_listen($server);

$clients = [];
while (true) {
  $read = array_merge([$server], $clients);
  $write = null;
  $except = null;
  socket_select($read, $write, $except, null);
 
  if (in_array($server, $read)) {
    $clients[] = connect($server);
  }
  foreach ($clients as $key => $client) {
    if (!in_array($client, $read)) {
      continue;
    }
    $request = socket_read($client, 65536);
    if ($request === '' || $request === false) {
      socket_close($client);
      unset($clients[$key]);
      continue;
    }
    $message = decode($request);

    switch($message){
      case "hello":
        socket_write($client, encode("Hello human."));
        break;
      case "name":
        socket_write($client, encode("I don't have a name."));
        break;
      case "thanks":
        socket_write($client, encode("You're welcome."));
        break;
      case "bye":
        socket_write($client, encode("Have a nice day."));
        break;
      case "close":
        socket_close($client);
        unset($clients[$key]);
        break;
      default:
        socket_write($client, encode($message));
        break;
    }
  }
}
function connect($server) {
  $client = socket_accept($server);
  $request = socket_read($client, 5000);
  preg_match('#Sec-WebSocket-Key: (.*)\r\n#', $request, $matches);
  $key = base64_encode(pack(
    'H*',
    sha1($matches[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
  ));
  $headers = "HTTP/1.1 101 Switching Protocols\r\n";
  $headers .= "Upgrade: websocket\r\n";
  $headers .= "Connection: Upgrade\r\n";
  $headers .= "Sec-WebSocket-Version: 13\r\n";
  $headers .= "Sec-WebSocket-Accept: $key\r\n\r\n";
  socket_write($client, $headers, strlen($headers));
  return $client;
}
function decode($data) {
  $length = ord($data[1]) & 127;
  if ($length == 126) {
    $length = unpack('n', substr($data, 2, 2))[1];
    $masks = substr($data, 4, 4);
    $data = substr($data, 8, $length);
  } elseif ($length == 127) {
    $length = unpack('J', substr($data, 2, 8))[1];
    $masks = substr($data, 10, 4);
    $data = substr($data, 14, $length);
  } else {
    $masks = substr($data, 2, 4);
    $data = substr($data, 6, $length);
  }
  $text = '';
  for ($i = 0; $i < strlen($data); ++$i) {
    $text .= $data[$i] ^ $masks[$i % 4];
  }
  return $text;
}
function encode($message) {
  $length = strlen($message);
  if ($length <= 125) {
    $header = chr(129) . chr($length);
  } else {
    $header = chr(129) . chr(126) . pack('n', $length);
  }
  return $header . $message;
}