PHP code example of php-websocket-rpc / rpc-server

1. Go to this page and download the library: Download php-websocket-rpc/rpc-server library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

php-websocket-rpc / rpc-server example snippets


use Amp\Http\Server\DefaultErrorHandler;
use Amp\Http\Server\Router;
use Amp\Http\Server\SocketHttpServer;
use Amp\Log\ConsoleFormatter;
use Amp\Log\StreamHandler;
use Amp\Socket\InternetAddress;
use Monolog\Logger;
use PhpWebsocketRpc\RpcServer\Adapter\AmpWebSocketServerAdapter;
use PhpWebsocketRpc\RpcServer\Server\RpcServerBuilder;

// Logger
$handler = new StreamHandler(\Amp\ByteStream\getStdout());
$handler->setFormatter(new ConsoleFormatter());
$logger = new Logger('server', [$handler]);

// HTTP server
$httpServer = SocketHttpServer::createForDirectAccess($logger);
$httpServer->expose(new InternetAddress('127.0.0.1', 9502));

$errorHandler = new DefaultErrorHandler();
$router = new Router($httpServer, $logger, $errorHandler);

// Build RPC server
$server = (new RpcServerBuilder())
    ->withLogger($logger)
    ->registerService(MathService::class, new MathServiceImpl())
    ->build();

// Mount at /rpc
AmpWebSocketServerAdapter::attach($httpServer, $router, '/rpc', $server);

// Start HTTP server
$httpServer->start($router, $errorHandler);

$math = $client->createProxy(MathService::class);
$result = $math->add(10, 5);    // 15

use PhpWebsocketRpc\Rpc\Auth\User;
use PhpWebsocketRpc\RpcServer\Auth\InMemoryUserProvider;
use PhpWebsocketRpc\RpcServer\Auth\StaticTokenAuthenticationProvider;

$server = (new RpcServerBuilder())
    ->withLogger($logger)
    ->useAuthentication(
        new StaticTokenAuthenticationProvider('tok-admin', 'bob'),
        new InMemoryUserProvider([
            'bob' => new User('bob', ['admin']),
        ]),
    )
    ->registerService(SecureDataService::class, new SecureDataServiceImpl())
    ->build();

use PhpWebsocketRpc\Rpc\Contract\Attribute\NeedAuthorization;

// Protect entire interface — all methods ect specific methods only
interface ChatService
{
    public function getPublicInfo(): string;  // open to all

    #[NeedAuthorization]
    public function getProfile(): string;     // needs auth

    #[NeedAuthorization(roles: ['admin', 'moderator'])]
    public function deleteMessage(string $id): void;  // needs specific role
}

// 1. Authenticate
$auth = $client->createProxy(AuthService::class);
$user = $auth->authenticate('tok-alice');

// 2. Access protected methods
$service = $client->createProxy(ChatService::class);
$service->getProfile();                    // ✅ works after auth
$service->deleteMessage('msg-1');          // ❌ AuthorizationException (not admin)

use PhpWebsocketRpc\Rpc\Auth\Token;
use PhpWebsocketRpc\Rpc\Auth\User;
use PhpWebsocketRpc\RpcServer\Auth\AuthenticationProvider;
use PhpWebsocketRpc\RpcServer\Auth\InMemoryUserProvider;
use PhpWebsocketRpc\RpcServer\Auth\UserProvider;

class JwtProvider implements AuthenticationProvider
{
    public function __construct(private string $secret) {}

    public function validateToken(#[\SensitiveParameter] string $token): ?Token
    {
        try {
            $payload = \Firebase\JWT\JWT::decode($token, $this->secret, ['HS256']);
            $now = \time();
            return new Token(
                id: \bin2hex(\random_bytes(16)),
                issuer: 'my-app',
                subject: $payload->sub,
                audience: 'rpc',
                expiresAt: $now + 3600,
                notBefore: $now,
                issuedAt: $now,
            );
        } catch (\Throwable) {
            return null;
        }
    }

    public function refreshToken(#[\SensitiveParameter] Token $token): Token
    {
        return new Token(
            id: $token->id,
            issuer: $token->issuer,
            subject: $token->subject,
            audience: $token->audience,
            expiresAt: \time() + 3600,
            notBefore: \time(),
            issuedAt: \time(),
        );
    }
}

// Must also provide a UserProvider to resolve user details from the token subject
$server = (new RpcServerBuilder())
    ->withLogger($logger)
    ->useAuthentication(
        new JwtProvider(),
        new InMemoryUserProvider([
            'alice' => new User('alice', ['customer']),
        ]),
    )
    ->build();

use PhpWebsocketRpc\RpcServer\Auth\AuthorizationProvider;
use PhpWebsocketRpc\RpcServer\Server\ClientSession;

class OwnershipProvider implements AuthorizationProvider
{
    public function authorize(
        ClientSession $session,
        string $service,
        string $method,
        ?array $    new OwnershipProvider(),   // third arg = optional AuthorizationProvider
    )
    ->build();

use PhpWebsocketRpc\Rpc\Contract\Attribute\RpcSubscribe;
use PhpWebsocketRpc\Rpc\Contract\Attribute\RpcStream;
use PhpWebsocketRpc\Rpc\Contract\Attribute\RpcPublish;

interface MathService
{
    public function add(int $a, int $b): int;         // call/response
    public function log(string $msg): void;            // notification

    #[RpcStream]
    public function count(int $limit): \Iterator;      // streaming

    #[RpcSubscribe('events')]
    public function onEvent(callable $cb): void;       // subscribe

    #[RpcPublish('chat')]
    public function send(string $msg): void;           // publish
}

$server = (new RpcServerBuilder())
    ->withLogger($logger)
    ->registerService(MathService::class, new MathServiceImpl())
    ->build();