PHP extension manual
Native WebSocket runtime for PHP
ext-websocket keeps RFC 6455 protocol work in C and exposes a small PHP API
for callback-based WebSocket servers, synchronous PHP code, and protocol helpers that can
be reused by higher-level runtimes.
Installation
Install the extension with PIE:
pie install axcherednikov/php-websocket
Or build from source:
phpize
./configure --enable-websocket
make
make test
sudo make install
Enable the extension in PHP:
extension=websocket
Verify that PHP can load it:
php -m | grep websocket
See the project installation notes for repository-specific commands.
Quick Start
A minimal echo server:
<?php
use WebSocket\Connection;
use WebSocket\MessageType;
use WebSocket\Server;
use WebSocket\ServerOptions;
$server = new Server(new ServerOptions(
maxMessageSize: 1024 * 1024,
));
$server->listen('127.0.0.1', 8080);
$server->onOpen(static function (Connection $connection): void {
echo "open {$connection->id}\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();
A fuller runnable example is available in examples/run_server.php.
Runtime Model
The server runtime is asynchronous internally and callback-based externally. The extension
owns its event loop when WebSocket\Server::run() is called.
Server, Connection, callbacks, typed options.
Protocol helpers such as Protocol::encode() and Protocol::decode()
are stateless and can be used by AMPHP, Revolt, Workerman, or other runtimes without adopting
the built-in server loop.
Protocol Helpers
Encode and decode RFC 6455 frames directly:
<?php
use WebSocket\MessageType;
use WebSocket\Protocol;
$bytes = Protocol::encode('hello', MessageType::Text);
$frame = Protocol::decode($bytes);
echo $frame->payload; // hello
Class Reference
The reference follows the PHP manual style: each class lists its synopsis, methods, parameters, common errors, and examples.
WebSocket\Server
final class WebSocket\Server
Native callback-based WebSocket server. It binds a TCP listener, performs HTTP Upgrade, processes RFC 6455 frames, and dispatches user callbacks.
Constructor
public function __construct(WebSocket\ServerOptions|array $options = [])
| Option | Description |
|---|---|
maxMessageSize | Maximum accepted text or binary message size. Defaults to 16 MiB. |
maxQueuedBytes | Maximum queued outgoing bytes per connection. Defaults to 16 MiB. |
Methods
listen(string $host, int $port): voidBind the TCP listener used by
run().onOpen(Closure $handler): voidRegister a callback called after a successful HTTP Upgrade. Returning
false closes the accepted connection.onMessage(Closure $handler): voidRegister a callback called for complete text and binary messages.
onClose(Closure $handler): voidRegister a callback called when an upgraded connection closes.
onError(Closure $handler): voidRegister a callback for runtime errors.
run(): voidStart the accept, HTTP Upgrade, and frame processing loop.
stop(): voidRequest graceful shutdown of the running server loop.
getDriver(): stringReturn the active or best available I/O driver name.
WebSocket\ServerOptions
final class WebSocket\ServerOptions
Explicit immutable configuration for WebSocket\Server.
Synopsis
final class ServerOptions
{
public readonly int $maxMessageSize;
public readonly int $maxQueuedBytes;
public function __construct(
int $maxMessageSize = 16 * 1024 * 1024,
int $maxQueuedBytes = 16 * 1024 * 1024,
) {}
}
Errors/Exceptions
Throws ValueError if a limit is less than 1.
WebSocket\Connection
final class WebSocket\Connection
Runtime connection accepted by WebSocket\Server.
Properties
| Property | Description |
|---|---|
readonly string $id | Runtime connection identifier. |
readonly string $remoteAddress | Remote peer address. |
Methods
send(string $payload, MessageType $type = MessageType::Text): voidSend a text, binary, ping, pong, or close frame.
close(int $code = 1000, string $reason = ''): voidSend a close frame and close the connection.
isOpen(): boolCheck whether the underlying connection is still open.
WebSocket\Protocol
final class WebSocket\Protocol
Stateless RFC 6455 protocol helpers.
Methods
acceptKey(string $key): stringBuild
Sec-WebSocket-Accept from Sec-WebSocket-Key.encode(string $payload, MessageType $type = MessageType::Text, bool $masked = false): stringEncode one complete frame.
decode(string $buffer): Frame|CloseFrame|nullDecode one complete frame. Returns
null when the buffer is incomplete.pack(string|Frame|CloseFrame $data, int $opcode = Protocol::OPCODE_TEXT, int $flags = Protocol::FLAG_FIN): stringEncode a raw WebSocket frame.
unpack(string $buffer): Frame|CloseFrame|nullDecode one raw WebSocket frame.
Frames and Types
| Class | Description |
|---|---|
WebSocket\Frame | Decoded non-close frame with type, opcode, flags, payload, FIN state, and consumed byte count. |
WebSocket\CloseFrame | Decoded close frame with status code, reason, flags, and consumed byte count. |
WebSocket\MessageType | Enum cases: Continuation, Text, Binary, Ping, Pong, Close. |
Production
Terminate TLS outside the extension with nginx, Caddy, Traefik, HAProxy, or stunnel. Run multiple PHP server processes behind a load balancer or process manager when you need to use multiple CPU cores.
Always set explicit maxMessageSize and maxQueuedBytes values for
the workload. These limits protect memory under large messages and slow clients.
Read the full production guide for TLS, process management, limits, backpressure, and deployment notes.
Benchmarks
The benchmark suite covers protocol encode/decode, server accept/upgrade runtime, and
real ws:// / wss:// message runtime against AMPHP, Workerman,
and OpenSwoole.
The important distinction is layer ownership: Protocol helpers can accelerate
existing async/userland runtimes, while Server::run() is a standalone native loop.
Benchmark commands and current comparison notes live in bench/README.md.
IDE Support
Use websocket.stub.php as an IDE/static-analysis stub for PhpStorm, PHPStan,
Psalm, or similar tools. It documents callback signatures, immutable options, typed frames,
value ranges, and common exceptions.
Download or reference the stub from websocket.stub.php.
Scope
ext-websocket is not a Centrifugo replacement and does not implement Socket.IO.
It is a low-level native WebSocket runtime and codec for building custom realtime protocols
directly in PHP.
Project Resources
| Resource | Link |
|---|---|
| Source code | github.com/axcherednikov/php-websocket |
| Benchmarks | bench/README.md |
| Production guide | docs/production.md |
| IDE stub | websocket.stub.php |
| Changelog | CHANGELOG.md |