Skip to content

axcherednikov/php-websocket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ext-websocket

Native WebSocket extension for PHP.

ext-websocket keeps RFC 6455 protocol work in C and exposes a small PHP API for synchronous PHP code, async runtimes, and the native server runtime included in the extension.

Requirements

  • PHP >= 8.1
  • Linux, macOS, BSD, or another POSIX-compatible OS
  • phpize, php-config, make, and a C compiler

Installation

Via PIE

pie install axcherednikov/php-websocket

From Source

phpize
./configure --enable-websocket
make
make test
sudo make install

Enable the extension:

extension=websocket

Check that PHP can load it:

php -m | grep websocket

With Homebrew PHP:

/opt/homebrew/opt/php@8.3/bin/phpize
./configure --enable-websocket --with-php-config=/opt/homebrew/opt/php@8.3/bin/php-config
make -j"$(sysctl -n hw.ncpu)"

Quick Start

<?php

use WebSocket\Connection;
use WebSocket\MessageType;
use WebSocket\Server;

$server = new Server();
$server->listen('127.0.0.1', 8080);
$server->subprotocols('chat.v1');

$server->onOpen(static function (Connection $connection): void {
    echo "open {$connection->id}";
    echo $connection->subprotocol ? " ({$connection->subprotocol})\n" : "\n";
});

$server->onMessage(static function (Connection $connection, string $message): void {
    $connection->send($message, MessageType::Text);
});

$server->onClose(static function (Connection $connection): void {
    echo "close {$connection->id}\n";
});

$server->run();

See examples/run_server.php for a runnable example.

Protocol Helpers

<?php

use WebSocket\MessageType;
use WebSocket\Protocol;

$bytes = Protocol::encode('hello', MessageType::Text);
$frame = Protocol::decode($bytes);

echo $frame->payload; // hello

Public API

WebSocket\Server

Options:

Option Description
maxMessageSize Maximum incoming text/binary message size; defaults to 16 MiB
maxQueuedBytes Maximum outgoing queued bytes per connection; defaults to 16 MiB
maxConnections Maximum concurrently accepted TCP connections; defaults to 10000
handshakeTimeoutMs Maximum idle time before HTTP Upgrade completes; defaults to 10000 ms
idleTimeoutMs Maximum idle time after HTTP Upgrade completes; defaults to 120000 ms
pingIntervalMs Idle time before sending an automatic ping; 0 disables heartbeat pings by default
pongTimeoutMs Maximum time to wait for a pong after an automatic ping; defaults to 10000 ms

Prefer WebSocket\ServerOptions for explicit configuration. Associative arrays remain supported for compatibility.

Methods:

Method Description
__construct(ServerOptions|array $options = []) Create a server
listen(string $host, int $port): void Bind address for run()
subprotocols(string ...$protocols): void Configure supported Sec-WebSocket-Protocol tokens
onHandshake(Closure $handler): void Accept or reject valid HTTP Upgrade requests before 101 Switching Protocols
onOpen(Closure $handler): void Register upgraded connection callback
onMessage(Closure $handler): void Register text/binary message callback
onClose(Closure $handler): void Register close callback
onError(Closure $handler): void Register runtime error callback
run(): void Start accept, HTTP Upgrade, and frame processing loop
stop(): void Request shutdown
getDriver(): string Return selected I/O driver

Handshake callbacks receive a WebSocket\Request. Return normally to continue the WebSocket upgrade, or throw WebSocket\HandshakeException to reject it before 101 Switching Protocols is sent:

$server->onHandshake(static function (WebSocket\Request $request): void {
    if ($request->header('Origin') !== 'https://app.test') {
        throw new WebSocket\HandshakeException(
            new WebSocket\HandshakeResponse(403, ['X-Reject' => 'origin'])
        );
    }
});

WebSocket\Request

Method / property Description
header(string $name): ?string Return a case-insensitive request header value
readonly string $method HTTP request method
readonly string $target HTTP request target
readonly array $headers Lower-case request headers

WebSocket\HandshakeResponse

Method / property Description
__construct(int $status = 403, array $headers = [], string $body = '') Create a custom handshake rejection response
readonly int $status HTTP status code
readonly array $headers HTTP response headers
readonly string $body HTTP response body

WebSocket\HandshakeException

Method / property Description
__construct(?HandshakeResponse $response = null) Create a handshake rejection exception; defaults to 403 Forbidden
readonly HandshakeResponse $response HTTP response sent before closing the connection

WebSocket\Connection

Method / property Description
send(string $payload, MessageType $type = MessageType::Text): void Send text, binary, or control payload
close(int $code = 1000, string $reason = ''): void Send close frame and close the connection
isOpen(): bool Check connection state
readonly string $id Connection id
readonly string $remoteAddress Remote peer address
readonly ?string $subprotocol Negotiated subprotocol, or null

WebSocket\Protocol

Method Description
acceptKey(string $key): string Build Sec-WebSocket-Accept
encode(string $payload, MessageType $type = MessageType::Text, bool $masked = false): string Encode one frame
decode(string $buffer): Frame|CloseFrame|null Decode one frame
pack(string|Frame|CloseFrame $data, int $opcode = Protocol::OPCODE_TEXT, int $flags = Protocol::FLAG_FIN): string Encode with raw opcode and flags
unpack(string $buffer): Frame|CloseFrame|null Decode with raw opcode and flags

Value Objects

Class Description
Frame Non-close WebSocket frame with type, opcode, flags, payload, final, and bytesConsumed
CloseFrame Close frame with code, reason, flags, and bytesConsumed
MessageType Enum cases: Continuation, Text, Binary, Ping, Pong, Close

Benchmarks

Detailed benchmark results and commands live in the separate php-websocket-bench repository.

The benchmark suite covers protocol encode/decode, server upgrade runtime, and real ws:// / wss:// message runtime against AMPHP, Workerman, OpenSwoole, and Ratchet.

Production

See docs/production.md for deployment notes and current runtime limits.

IDE Support

Use websocket.stub.php as an IDE/static-analysis stub for PhpStorm, PHPStan, Psalm, or similar tools.

Testing

make test

To run tests against the built module directly:

TEST_PHP_ARGS="-d extension=$PWD/modules/websocket.so" php run-tests.php -q tests

Changelog

See CHANGELOG.md.

License

MIT. See LICENSE.

About

Native PHP extension (C) providing high-performance WebSocket server runtime and RFC 6455 protocol support.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors