Search by

squirtle / websocket

squirtle

PHP 8.2+ WebSocket server and client built on stream_select(), RFC 6455 compliant

Package info

github.com/gulmzugur/websocket

pkg:composer/squirtle/websocket

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-09-06 21:08 UTC

This package is auto-updated.

Last update: 2026-09-06 21:08:38 UTC


README

WebSocket, PHP 8.2 ve üzeri için bağımlılıksız bir WebSocket sunucu ve istemci kütüphanesidir. RFC 6455 handshake ve frame kurallarını uygular; tek iş parçacıklı stream_select() event loop'u üzerinde çalışır. Kanal aboneliği, handshake kimlik doğrulaması, kanal yetkisi, akış kontrolü, hız sınırlama ve ayrı backend süreçleri için token korumalı Management IPC içerir.

Kurulum

  • PHP 8.2 veya üzeri CLI gerekir.
  • wss:// istemci bağlantıları için OpenSSL eklentisi gerekir.

Uygulamanıza paketi Composer ile ekleyin:

composer require squirtle/websocket

Kütüphane deposunu kaynak koddan çalıştırmak için kökte composer install çalıştırın. Sunucuyu PHP-FPM istek döngüsünde değil; ayrı CLI süreci, supervisor veya container giriş noktası olarak çalıştırın.

Temel kullanım

<?php

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

use WebSocket\Connection;
use WebSocket\Message;
use WebSocket\Server;

$server = new Server(['listen' => ['host' => '127.0.0.1', 'port' => 9501]]);

$server->on('message', static function (Connection $connection, Message $message) use ($server): void {
    $server->send($message->payload);
});

$server->run();

Composer, WebSocket\ ad alanını otomatik olarak src/ dizinine eşler.

Uygulamaya entegrasyon

WebSocket sunucusu HTTP uygulamasından ayrı bir süreçtir. Mevcut JWT, session veya API token doğrulamanızı authenticator() callback'ine bağlayın. Callback bir Identity döndürdüğünde bağlantı o kullanıcıyla otomatik indekslenir; Server::user($id)->send() o kullanıcının bütün canlı bağlantılarına mesaj gönderir.

Kanal yetkisi ayrı bir uygulama kuralıdır. Authenticated bir kullanıcının her kanala abone olmasını engellemek için channels()->authorizer() kullanın. Tarayıcı yayını gerekmiyorsa channel.publish: false bırakın. Aynı süreçte uygulama olayı Server::publish() ile, ayrı HTTP controller veya queue worker sürecinde ise Management IPC ile yayınlanır.

examples/integration.php, token doğrulama, Identity, kullanıcıya ait kanal yetkisi, düz mesaj callback'i ve uygulama olayı yayınının tek bir server giriş noktasında nasıl birleştiğini gösterir. Örnek içindeki findUserByToken() fonksiyonunu mevcut kullanıcı doğrulama katmanınıza bağlayın.

İstemci -> handshake + Bearer / query token -> authenticator() -> Identity
       -> channel authorizer -> user.{id} aboneliği
Backend olayı -> Server::publish() veya Management::publish() -> aboneler

Olay ve kanal modeli

Olay Callback Kullanım
open fn(Connection $connection) Bağlantı açıldığında kayıt veya başlangıç durumu
message fn(Connection $connection, Message $message) Kanal zarfı olmayan uygulama mesajları
close fn(Connection $connection, Reason $reason) Bağlantı temizliği
error fn(Throwable $error, ?Connection $connection) Hata kaydı ve gözlemlenebilirlik

Kanal katmanı etkin olduğunda istemci normal WebSocket metni içinde şu zarfları gönderir:

{"type":"subscribe","channel":"user.42"}
{"type":"unsubscribe","channel":"user.42"}
{"type":"publish","channel":"user.42","data":{"type":"invoice.ready"}}

Server::publish('user.42', $data) abonelere aşağıdaki biçimde olay gönderir:

{"type":"event","channel":"user.42","data":{"type":"invoice.ready"}}

Kanal zarfları message callback'ine düşmez. Bu callback uygulamanın kendi ham WebSocket mesajları içindir; zarf işlemesi Channel\Registry tarafından yapılır.

Mimari

TCP stream
  -> Runtime\Loop
  -> Socket\Server / Socket\Client
  -> Socket\Connection
  -> Protocol\Handshake + Decoder + Assembler
  -> Connection
  -> Server veya Client
  -> Channel\Registry (isteğe bağlı)

Ayrı PHP backend süreci
  -> Management\Client
  -> Unix socket veya 127.0.0.1 TCP
  -> Management\Endpoint
  -> çalışan Server / Channel\Registry
Katman Kaynak Sorumluluk
Runtime src/Runtime stream_select() watcher'ları, timer'lar ve future-tick kuyruğu
Socket src/Socket Non-blocking TCP ve sınırlı yazma tamponu
Protocol src/Protocol RFC 6455 handshake, frame doğrulama, kodlama/çözme, parçalı mesaj birleştirme
Connection src/Connection.php Bağlantı durumu, ping/pong, close handshake ve öznitelikler
Server / Client src/Server.php, src/Client.php Uygulama API'si ve yaşam döngüsü callback'leri
Channel src/Channel Abonelik, yetki, seçici yayın ve olay zarfları
Management src/Management Ayrı backend süreçleri için token korumalı IPC
Security src/Security Origin, hız sınırı ve güvenilir proxy çözümleme

Runtime\Loop, her turda future-tick'leri ve zamanı gelen timer'ları çalıştırır; ardından okunabilir/yazılabilir stream'leri stream_select() ile işler. Callback hatası bir error callback'ine iletilir; ayarlanmamışsa run() çağrısından yükselir.

Yazma önce doğrudan stream'e denenir. Tam yazılamayan veri tamponlanır; yumuşak sınırda o bağlantının okuması durur, tampon boşalınca devam eder. Sert sınır aşıldığında bağlantı kapatılır. Böylece yavaş okuyucular tüm süreç belleğini tüketemez.

Management IPC

Management, genel ağa açılan bir WebSocket API'si değildir. HTTP controller, queue worker veya cron gibi ayrı PHP süreçlerinden çalışan WebSocket sunucusuna send, hedefli client/user mesajı, disconnect ve publish komutları iletir. Producer her işlemde kısa bir yerel bağlantı açar, token ile doğrulanır, komutu yollar ve kapanır; event loop çalıştırması gerekmez.

examples/management/server.php, yönetim uç noktasını sunucuya ekler. examples/management/producer.php ayrı süreçte Management\Client::publish() çağırır. Unix'te mutlak yollu Unix socket ve 0600 izinleri kullanın. Windows'ta transport yalnızca 127.0.0.1 TCP'ye bağlanabilir. Token'ı kodda tutmayın; ortam değişkeni veya gizli değer deposundan alın.

Güvenlik

WebSocket; hatalı HTTP Upgrade isteklerini, geçersiz frame'leri, büyük veya parçalı payload'ları, ping selini, yavaş okuyucuları, başarısız handshake'leri ve yetkisiz kanal işlemlerini sınırlamak için aşağıdaki kontrolleri uygular.

Alan Yerleşik koruma
Handshake Geçerli Upgrade isteği zorunludur; header boyutu ve sayısı sınırlıdır.
Frame ve mesaj Mask yönü, opcode, RSV bitleri, kontrol frame kuralları, UTF-8 ve boyutlar doğrulanır.
Kaynak Handshake, frame, mesaj ve yazma tamponu için ayrı üst sınırlar bulunur.
Akış kontrolü Yazma tamponu yumuşak sınırda okumayı durdurur; sert sınırda bağlantıyı kapatır.
Zaman aşımı Handshake, boşta bağlantı, ping/pong ve close handshake süreleri izlenir.
Hız sınırı Bağlantı başına mesaj ve byte tabanlı token bucket uygulanabilir; kontrol frame'leri de sınırlanır.
Hata yalıtımı Bir bağlantının callback hatası diğer bağlantıları durdurmaz.

Üretim için dinleme adresini, origin listesini ve kaynak sınırlarını açıkça tanımlayın:

$server = new \WebSocket\Server([
    'listen' => ['host' => '127.0.0.1', 'port' => 9501, 'connections' => 1000],
    'origins' => ['app.example.com', '*.partner.example'],
    'limit' => ['frame' => 2 * 1024 * 1024, 'message' => 10 * 1024 * 1024, 'handshake' => 8192],
    'buffer' => ['soft' => 65536, 'hard' => 2 * 1024 * 1024],
    'rate' => ['messages' => 100.0, 'bytes' => 262144.0],
    'channel' => ['publish' => false],
    'proxies' => ['127.0.0.1'],
]);

Varsayılan frame sınırı 2 MiB, mesaj sınırı 10 MiB, header bloğu 8 KiB, header sayısı 64 ve sert yazma tamponu 2 MiB'dir. Boş origins listesi tüm origin'leri kabul eden geliştirme varsayılanıdır. Üretimde izinli alan adlarını açıkça yazın. *.example.com kök alan adını kapsamaz; gerekirse example.com satırını da ekleyin.

Origin kontrolü kimlik doğrulama değildir. Origin başlığı olmayan native istemciler kabul edilir; kullanıcı veya servis kimliği için authenticator kullanın. Token Authorization: Bearer ... veya ?token= üzerinden alınır. Authenticator null döndürürse handshake 401 ile reddedilir. auth.anonymous: true, token göndermeyen bağlantıyı anonim kabul eder; geçersiz token yine reddedilir.

X-Forwarded-For ve Forwarded başlıklarına varsayılan olarak güvenilmez. Yalnızca doğrudan TCP peer adresi proxies listesinde tam IP olarak varsa istemci IP'si çözülür. Reverse proxy'nin bu başlıkları temizlediğinden veya güvenli biçimde yeniden yazdığından emin olun.

Sunucu TLS dinleyicisi sağlamaz. WSS/TLS'yi Nginx, Caddy veya benzeri bir reverse proxy'de sonlandırın; PHP sürecini sadece proxy'nin erişebildiği loopback veya özel ağ adresinde dinletin.

Çalışma ve ölçekleme

Event loop tek iş parçacıklıdır. CPU yoğun işlem, bloklayan veritabanı sorgusu, dosya işlemi veya uzak HTTP çağrısını callback içinde çalıştırmayın. Bu işleri queue worker'a devredin; sonucu Management IPC veya harici broker üzerinden yayınlayın. Bağlantılar ve kanal üyelikleri süreç belleğindedir. Birden çok sunucu süreci arasında yayın veya yatay ölçekleme için Redis, NATS, RabbitMQ veya uygulamanızın seçtiği başka bir dağıtım katmanı gerekir.

İleri seviye: sipariş bildirim akışı

examples/advanced/server.php, paketin birlikte kullanılabilen uçlarını üretime yakın bir akışta gösterir: token ile kimlik doğrulama, kullanıcı ve sipariş bazlı kanal yetkisi, tarayıcıdan yayını kapatma, rate ve bellek sınırları, yapılandırılabilir logger, anlık metrikler ve ayrı backend süreçleri için Management IPC. examples/advanced/producer.php ise bir queue worker veya HTTP controller'ın sipariş olayını nasıl ileteceğini gösterir. examples/advanced/client.php, üye istemcinin doğrudan bildirim ve yetkili sipariş kanalı olayını almasını gösterir.

İki ayrı terminal kullanın:

$env:WEBSOCKET_DEMO_TOKEN = 'change-this'
php examples/advanced/server.php
$env:WEBSOCKET_DEMO_TOKEN = 'change-this'
php examples/advanced/client.php
$env:WEBSOCKET_DEMO_TOKEN = 'change-this'
php examples/advanced/producer.php 1001 shipped

İstemci ws://127.0.0.1:9503/?token=member-42 adresine bağlanıp önce order.1001 kanalına abone olur. Producer çalıştığında kanal olayı ile Management\Client::user(42)->send() üzerinden doğrudan bildirim aynı canlı bağlantıya ulaşır. Örnek tokenları yalnızca gösterim içindir; üretimde tokenı güvenli ortam değişkeninden veya gizli değer deposundan verin.

Sunucu tarafında client($id), user($id) ve channel($name) seçicileri hedefli send() ve uygun olduğunda disconnect() işlemlerini sunar. metrics()->array() ise bağlantı, handshake, mesaj, kanal ve hata sayaçlarının güvenli anlık görüntüsünü verir.

Örnekler

Örneklerin çalıştırma yönergeleri dosya içi yorumlardadır.

Dosya Amaç
examples/server.php Echo ve düz mesaj yayını yapan küçük sunucu
examples/client.php Terminal istemcisi ve kanal aboneliği
examples/publish.php Kısa ömürlü backend/webhook yayıncısı
examples/channel.php Tek süreçte seçici kanal yayını
examples/integration.php Kimlik doğrulama ve kanal yetkisiyle uygulama entegrasyonu
examples/browser/client.html Tek sayfada bağlantı günlüğü, broadcast sohbeti, kanal aboneliği/yayını, periyodik olaylar, iki istemci simülasyonu ve ileri sipariş akışı
examples/management/server.php WebSocket + özel Management IPC sunucusu
examples/management/producer.php Ayrı PHP sürecinden güvenli kanal yayını
examples/advanced/server.php Kimlik, yetki, limitler, metrikler ve Management IPC ile sipariş bildirimi sunucusu
examples/advanced/client.php Üye istemciyle doğrudan bildirim ve sipariş kanalı olayını alma
examples/advanced/producer.php Ayrı backend sürecinden sipariş olayı ve hedefli kullanıcı bildirimi

Testler

Bağımlılıksız test paketini proje kökünde çalıştırın:

php tests/run.php

Lisans

MIT