$client, 'handshake' => false]; } continue; } $id = (int) $socket; $buffer = fread($socket, 2048); if ($buffer === '' || $buffer === false) { fclose($socket); unset($clients[$id]); continue; } if (!$clients[$id]['handshake']) { if (preg_match('/Sec-WebSocket-Key: (.*)\r\n/i', $buffer, $matches)) { $key = trim($matches[1]); $accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); fwrite($socket, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $accept\r\n\r\n"); $clients[$id]['handshake'] = true; } } } try { $db = Database::connection(); $stmt = $db->prepare('SELECT id, match_id, event_type, points_home, points_away FROM match_events WHERE id > :id ORDER BY id ASC LIMIT 50'); $stmt->execute(['id' => $lastEventId]); foreach ($stmt->fetchAll() as $event) { $lastEventId = (int) $event['id']; broadcast($clients, json_encode(['type' => 'match_event', 'data' => $event])); } } catch (Throwable $e) { usleep(300000); } } function broadcast(array &$clients, string $payload): void { $frame = frame($payload); foreach ($clients as $id => $client) { if (!$client['handshake']) { continue; } if (@fwrite($client['socket'], $frame) === false) { fclose($client['socket']); unset($clients[$id]); } } } function frame(string $payload): string { $length = strlen($payload); if ($length <= 125) { return chr(129) . chr($length) . $payload; } if ($length <= 65535) { return chr(129) . chr(126) . pack('n', $length) . $payload; } return chr(129) . chr(127) . pack('J', $length) . $payload; }