obray/web-socket-server

PHP based WebSocket server.

Maintainers

Package info

github.com/nateobray/webSocketServer

Homepage

pkg:composer/obray/web-socket-server

Statistics

Installs: 89

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-06-05 13:53 UTC

This package is auto-updated.

Last update: 2026-06-05 13:54:28 UTC


README

Small PHP WebSocket server library built on obray/socket-server.

This package handles the WebSocket upgrade, frame parsing, protocol close responses, and dispatches messages to an application handler. Application behavior such as chat rooms, alert routing, authentication, presence, and connection metadata should live in the handler that implements the library interface.

Install

composer require obray/web-socket-server

For local development with this checkout next to SocketServer, the example in examples/broadcast.php includes a small fallback autoloader.

Start An Echo Server

<?php

require __DIR__ . '/vendor/autoload.php';

$server = (new \obray\WebSocketServer())->create('127.0.0.1', 8080);
$server->start();

The default handler echoes text and binary messages, replies to ping frames with pong frames, and closes when the client sends a close frame. It is quiet by default. Pass a logger to see lifecycle messages:

$handler = new \obray\base\WebSocketBaseHandler(function ($message) {
    error_log($message);
});

$server = (new \obray\WebSocketServer())->create('127.0.0.1', 8080, null, $handler);
$server->start();

Custom Handler

Implement obray\interfaces\WebSocketServerHandlerInterface or extend obray\base\WebSocketBaseHandler and override only the callbacks you need.

class AlertsHandler extends \obray\base\WebSocketBaseHandler
{
    private $connections = [];

    public function onUpgraded($data, \obray\interfaces\SocketConnectionInterface $connection): void
    {
        $this->connections[spl_object_hash($connection)] = $connection;
    }

    public function onText(string $data, \obray\interfaces\SocketConnectionInterface $connection): void
    {
        foreach($this->connections as $client){
            if($client->isConnected()){
                \obray\WebSocket::sendText($client, $data);
            }
        }
    }

    public function onDisconnect(\obray\interfaces\SocketConnectionInterface $connection): void
    {
        unset($this->connections[spl_object_hash($connection)]);
    }
}

Sending Messages

Handlers can use the helper methods on obray\WebSocket instead of encoding frames directly:

\obray\WebSocket::sendText($connection, 'hello');
\obray\WebSocket::sendBinary($connection, $bytes);
\obray\WebSocket::sendPing($connection);
\obray\WebSocket::sendPong($connection);
\obray\WebSocket::sendClose($connection);
\obray\WebSocket::sendCloseWithCode($connection, 1000, 'done');

If your handler defines onStart(\obray\SocketServer $server), the WebSocket adapter will call it when the lower socket server starts. This is intentionally optional so application-specific concerns can stay outside the library.

public function onStart(\obray\SocketServer $server): void
{
    $server->watchTimer(5, 30, function () {
        // Application-owned recurring work, such as publishing alerts.
    });
}

Protocol Behavior

  • Client frames must be masked.
  • Reserved bits are rejected unless future extensions add support.
  • Invalid opcodes close only the offending connection.
  • Control frames cannot be fragmented and cannot exceed 125 bytes.
  • Frame and message payloads are limited to 1 MiB by default.
  • Protocol errors close with WebSocket close code 1002.
  • Oversized payloads close with WebSocket close code 1009.

Configure payload limits before creating or starting the server:

$webSocketServer = (new \obray\WebSocketServer())
    ->setMaximumFramePayloadLength(262144)
    ->setMaximumMessageLength(524288);

$server = $webSocketServer->create('127.0.0.1', 8080, null, $handler);
$server->start();

The smoke test exercises handshake, echo, ping/pong, partial reads, fragmented messages, clean close, unmasked frames, invalid opcodes, and oversized frames:

php tools/websocket_smoke.php

Production Notes

  • Run the process under a supervisor such as systemd, Supervisor, or another process manager.
  • Terminate TLS at a proxy or configure a secure StreamContext.
  • Keep authentication, authorization, rooms, routing, and persistence in your application handler.
  • Track application connection state in the handler, not in the library.
  • Use SocketServer::setLogger() for lower-level server logs if you need them.