{"id":50699424,"url":"https://github.com/micilini/php-websockets","last_synced_at":"2026-06-09T08:04:35.702Z","repository":{"id":166888170,"uuid":"49508487","full_name":"micilini/php-websockets","owner":"micilini","description":"Native PHP WebSocket and realtime chat foundation built from scratch with PHP sockets. Includes chat examples, private rooms, bot hooks, storage adapters and optional Laravel integration.","archived":false,"fork":false,"pushed_at":"2026-05-10T00:53:39.000Z","size":1025,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-10T02:34:27.029Z","etag":null,"topics":["chat","chat-application","laravel","laravel-package","php","php-socket","php-websocket","private-chat","realtime","realtime-chat","sockets","websocket","websocket-server","websockets"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micilini.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-01-12T15:18:18.000Z","updated_at":"2026-05-10T00:53:43.000Z","dependencies_parsed_at":"2023-05-21T03:45:38.320Z","dependency_job_id":null,"html_url":"https://github.com/micilini/php-websockets","commit_stats":null,"previous_names":["micilini/phpsockets-with-websockets","micilini/php-websockets"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/micilini/php-websockets","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micilini%2Fphp-websockets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micilini%2Fphp-websockets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micilini%2Fphp-websockets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micilini%2Fphp-websockets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micilini","download_url":"https://codeload.github.com/micilini/php-websockets/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micilini%2Fphp-websockets/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34096955,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chat","chat-application","laravel","laravel-package","php","php-socket","php-websocket","private-chat","realtime","realtime-chat","sockets","websocket","websocket-server","websockets"],"created_at":"2026-06-09T08:04:34.904Z","updated_at":"2026-06-09T08:04:35.696Z","avatar_url":"https://github.com/micilini.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHPSockets\n\nNative PHP WebSocket and realtime chat foundation built from scratch with PHP sockets. Works standalone with plain PHP or inside Laravel applications.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.php.net/\"\u003e\u003cimg src=\"https://img.shields.io/badge/PHP-8.2%2B-777BB4?style=for-the-badge\u0026logo=php\u0026logoColor=white\" alt=\"PHP 8.2+\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://laravel.com/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Laravel-10%2F11%2F12%2F13-FF2D20?style=for-the-badge\u0026logo=laravel\u0026logoColor=white\" alt=\"Laravel 10/11/12/13\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/micilini/php-websockets/blob/master/LICENSE.txt\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-green?style=for-the-badge\" alt=\"MIT License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/micilini/php-websockets/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/micilini/php-websockets/tests.yml?branch=master\u0026style=for-the-badge\u0026label=Tests\" alt=\"Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://packagist.org/packages/micilini/php-websockets\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/micilini/php-websockets?style=for-the-badge\u0026label=Packagist\" alt=\"Packagist\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003ePure PHP WebSockets. Realtime chat. Private rooms. Bots. Laravel-ready.\u003c/strong\u003e\n\u003c/p\u003e\n\n---\n\n## Application Images\n\n\u003cdiv style=\"display:flex;flex-wrap:wrap;gap:10px;justify-content:center;\"\u003e\n  \u003cdiv style=\"flex:1 1 220px;max-width:32%;aspect-ratio:16/9;overflow:hidden;border-radius:8px;\"\u003e\n    \u003cimg src=\"./images/screen-1.png\" alt=\"Image 1\" style=\"width:100%;height:100%;object-fit:cover;display:block;\"\u003e\n  \u003c/div\u003e\n  \u003cdiv style=\"flex:1 1 220px;max-width:32%;aspect-ratio:16/9;overflow:hidden;border-radius:8px;\"\u003e\n    \u003cimg src=\"./images/screen-2.png\" alt=\"Image 2\" style=\"width:100%;height:100%;object-fit:cover;display:block;\"\u003e\n  \u003c/div\u003e\n  \u003cdiv style=\"flex:1 1 220px;max-width:32%;aspect-ratio:16/9;overflow:hidden;border-radius:8px;\"\u003e\n    \u003cimg src=\"./images/screen-3.png\" alt=\"Image 3\" style=\"width:100%;height:100%;object-fit:cover;display:block;\"\u003e\n  \u003c/div\u003e\n  \u003cdiv style=\"flex:1 1 220px;max-width:32%;aspect-ratio:16/9;overflow:hidden;border-radius:8px;\"\u003e\n    \u003cimg src=\"./images/screen-4.png\" alt=\"Image 4\" style=\"width:100%;height:100%;object-fit:cover;display:block;\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n---\n\n## Overview\n\n**PHPSockets** started in 2016 as an educational experiment demonstrating how to build a WebSocket server directly with PHP sockets, without Node.js, without socket.io, and without a third-party realtime runtime.\n\nThe project has now been rebuilt as a modern Composer package for PHP 8.2+, with a clean architecture, WebSocket protocol primitives, a realtime server runtime, a chat kit, private conversations, private group rooms, small attachments, emoji-safe payloads, bot hooks, optional storage adapters, and Laravel integration.\n\nThe goal is not only to provide a chat example.\n\nThe goal is to provide a **native PHP realtime foundation** that developers can use to build:\n\n- realtime chat widgets;\n- support chat systems;\n- private rooms;\n- collaborative dashboards;\n- notification servers;\n- internal realtime tools;\n- chatbot-ready messaging flows;\n- Laravel-powered realtime applications.\n\n---\n\n## Features\n\n- **Native WebSocket core** — handshake, frames, opcodes, close codes, ping/pong and payload validation.\n- **Pure PHP socket runtime** — no socket.io, Ratchet, ReactPHP, Swoole, Workerman or Node.js required.\n- **Realtime server layer** — connection registry, lifecycle events, message dispatching and safe closing.\n- **Chat Kit** — sessions, unique display names, presence, global messages, direct messages and rooms.\n- **EasyChat example** — simple global chat for beginners.\n- **MediumChat example** — callback/event-driven chat for customization.\n- **PrivateChat example** — global room, direct 1:1 conversations, private group rooms and unread badges.\n- **Private group rooms** — create a room with selected online users only.\n- **Typing indicators** — user feedback for active conversations.\n- **Message receipts** — simple sent/received/read states in examples.\n- **Emoji support** — safe UTF-8 text payloads with a built-in emoji picker in examples.\n- **Small attachments** — images, PDFs and text files up to the configured limit.\n- **Downloadable file messages** — delivered attachments include a download action.\n- **Fragmented text frame support** — large JSON text messages can be reassembled safely.\n- **Storage adapters** — in-memory, file JSONL messages and PDO-based SQL storage.\n- **Database migrations** — SQLite, MySQL and PostgreSQL schemas through the migration runner.\n- **Bot hooks** — register lightweight bots that can respond in global, direct and private group contexts.\n- **Laravel integration** — Service Provider, Facade, publishable config and Artisan commands.\n- **Quality tooling** — PHPUnit, PHPStan, PHP CS Fixer and GitHub Actions.\n- **Legacy preserved** — the original 2016 EasyChat and MediumChat implementations are kept for historical reference.\n\n---\n\n## Installation\n\nInstall through Composer:\n\n```bash\ncomposer require micilini/php-websockets\n```\n\nFor local development:\n\n```bash\ngit clone https://github.com/micilini/php-websockets.git\ncd php-websockets\ncomposer install\n```\n\n---\n\n## Requirements\n\nRequired:\n\n- PHP 8.2 or higher;\n- `ext-sockets`;\n- `ext-json`;\n- Composer.\n\nOptional:\n\n- `ext-pdo` for SQL storage adapters;\n- `ext-pdo_sqlite` for SQLite storage and tests;\n- Laravel 10, 11, 12 or 13 for Laravel integration.\n\n---\n\n## Quick Start\n\n### Standalone PHP server\n\nCreate a simple WebSocket chat server:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse Micilini\\PhpSockets\\Chat\\ChatServer;\nuse Micilini\\PhpSockets\\Config\\ChatConfig;\nuse Micilini\\PhpSockets\\Config\\ServerConfig;\n\n$server = ChatServer::create(\n    ServerConfig::new(\n        host: '127.0.0.1',\n        port: 8080,\n        maxPayloadBytes: 4 * 1024 * 1024,\n        enableDebugLogs: true,\n    ),\n    ChatConfig::new(\n        maxAttachmentBytes: 2 * 1024 * 1024,\n    ),\n);\n\n$server-\u003erun();\n```\n\nRun it:\n\n```bash\nphp server.php\n```\n\nThe WebSocket server will listen on:\n\n```txt\nws://127.0.0.1:8080\n```\n\n---\n\n## Running the Examples\n\n\u003e The example servers can be executed both from a cloned repository and from a project where the package was installed through Composer. The examples use `examples/bootstrap.php` to locate the correct Composer autoload file automatically.\n\nEach example has two parts:\n\n1. a WebSocket server process;\n2. a browser UI served by PHP's built-in HTTP server.\n\n### EasyChat\n\nStart the WebSocket server:\n\n```bash\nphp examples/easy-chat/server.php\n```\n\nOpen another terminal and serve the UI:\n\n```bash\nphp -S 127.0.0.1:8000 -t examples/easy-chat/public\n```\n\nIf you installed the package inside another project with Composer, run:\n\n```bash\nphp vendor/micilini/php-websockets/examples/easy-chat/server.php\nphp -S 127.0.0.1:8000 -t vendor/micilini/php-websockets/examples/easy-chat/public\n```\n\nOpen:\n\n```txt\nhttp://127.0.0.1:8000\n```\n\nEasyChat demonstrates:\n\n- global chat;\n- unique display names;\n- presence;\n- typing indicators;\n- emoji picker;\n- small attachments;\n- safe message rendering.\n\n---\n\n### MediumChat\n\nStart the WebSocket server:\n\n```bash\nphp examples/medium-chat/server.php\n```\n\nOpen another terminal and serve the UI:\n\n```bash\nphp -S 127.0.0.1:8001 -t examples/medium-chat/public\n```\n\nIf you installed the package inside another project with Composer, run:\n\n```bash\nphp vendor/micilini/php-websockets/examples/medium-chat/server.php\nphp -S 127.0.0.1:8001 -t vendor/micilini/php-websockets/examples/medium-chat/public\n```\n\nOpen:\n\n```txt\nhttp://127.0.0.1:8001\n```\n\nMediumChat demonstrates everything from EasyChat plus:\n\n- server-side callbacks;\n- low-level socket events;\n- chat lifecycle logs;\n- event panel in the browser;\n- extensibility points for custom behavior.\n\n---\n\n### PrivateChat\n\nStart the WebSocket server:\n\n```bash\nphp examples/private-chat/server.php\n```\n\nOpen another terminal and serve the UI:\n\n```bash\nphp -S 127.0.0.1:8002 -t examples/private-chat/public\n```\n\nIf you installed the package inside another project with Composer, run:\n\n```bash\nphp vendor/micilini/php-websockets/examples/private-chat/server.php\nphp -S 127.0.0.1:8002 -t vendor/micilini/php-websockets/examples/private-chat/public\n```\n\nOpen:\n\n```txt\nhttp://127.0.0.1:8002\n```\n\nPrivateChat demonstrates:\n\n- global room;\n- direct 1:1 conversations;\n- private group rooms;\n- selected participants;\n- unread badges;\n- attachments;\n- emoji picker;\n- message receipts;\n- bot commands.\n\nTry the bot commands:\n\n```txt\n/help\n/echo Hello PHPSockets\n```\n\n---\n\n## Example Matrix\n\n| Example | Global Chat | Direct 1:1 | Private Groups | Attachments | Bots | Best For |\n|---|---:|---:|---:|---:|---:|---|\n| EasyChat | ✅ | ❌ | ❌ | ✅ | ❌ | First contact and learning |\n| MediumChat | ✅ | ❌ | ❌ | ✅ | ❌ | Events and callbacks |\n| PrivateChat | ✅ | ✅ | ✅ | ✅ | ✅ | Advanced realtime chat |\n\n---\n\n## Laravel Integration\n\nPHPSockets can be used inside Laravel applications through Composer package discovery.\n\nInstall the package:\n\n```bash\ncomposer require micilini/php-websockets\n```\n\nPublish the configuration:\n\n```bash\nphp artisan vendor:publish --tag=phpsockets-config\n```\n\nCheck the package status:\n\n```bash\nphp artisan phpsockets:status\n```\n\nStart the WebSocket chat server from Laravel:\n\n```bash\nphp artisan phpsockets:serve\n```\n\nRun SQL migrations when using a persistent storage driver:\n\n```bash\nphp artisan phpsockets:migrate --driver=sqlite\n```\n\nThe package registers:\n\n- `Micilini\\PhpSockets\\Laravel\\PhpSocketsServiceProvider`\n- `Micilini\\PhpSockets\\Laravel\\PhpSocketsFacade`\n- `phpsockets:serve`\n- `phpsockets:migrate`\n- `phpsockets:status`\n\nExample usage:\n\n```php\nuse Micilini\\PhpSockets\\Laravel\\PhpSocketsFacade as PhpSockets;\n\nPhpSockets::bots();\n```\n\nLaravel is optional. The native PHP core continues to work standalone.\n\n---\n\n## Running PHPSockets in a Laravel Project\n\nA Laravel app usually has two running processes:\n\n```txt\nLaravel HTTP server\n  http://127.0.0.1:8000\n\nPHPSockets WebSocket server\n  ws://127.0.0.1:8080\n```\n\nRun the WebSocket server:\n\n```bash\nphp artisan phpsockets:serve\n```\n\nIn another terminal:\n\n```bash\nphp artisan serve\n```\n\nThen your Laravel pages can connect to:\n\n```txt\nws://127.0.0.1:8080\n```\n\n---\n\n## Hosting the Examples Through Laravel Routes\n\nFor a Laravel demo app, you can keep PHPSockets as the engine and let Laravel serve the example screens.\n\nRecommended local package structure while developing PHPSockets inside a Laravel app:\n\n```txt\nlaravel-app/\n  packages/\n    micilini/\n      php-websockets/\n  public/\n    phpsockets/\n      easy/\n      medium/\n      private/\n  routes/\n    web.php\n```\n\nAfter installing from Packagist, the package will live under:\n\n```txt\nlaravel-app/\n  vendor/\n    micilini/\n      php-websockets/\n```\n\nThe idea is:\n\n```txt\nhttp://127.0.0.1:8000/\n  Dashboard with Easy, Medium and Private options\n\nhttp://127.0.0.1:8000/easy\n  EasyChat hosted by Laravel\n\nhttp://127.0.0.1:8000/medium\n  MediumChat hosted by Laravel\n\nhttp://127.0.0.1:8000/private\n  PrivateChat hosted by Laravel\n```\n\nThe WebSocket server still runs in a separate process, which is the correct model for realtime applications.\n\n---\n\n## Configuration\n\nAfter publishing the Laravel config, `config/phpsockets.php` contains:\n\n```php\nreturn [\n    'server' =\u003e [\n        'host' =\u003e env('PHPSOCKETS_HOST', '127.0.0.1'),\n        'port' =\u003e (int) env('PHPSOCKETS_PORT', 8080),\n        'max_payload_bytes' =\u003e (int) env('PHPSOCKETS_MAX_PAYLOAD_BYTES', 4 * 1024 * 1024),\n        'tick_microseconds' =\u003e (int) env('PHPSOCKETS_TICK_MICROSECONDS', 10000),\n        'connection_limit' =\u003e (int) env('PHPSOCKETS_CONNECTION_LIMIT', 100),\n        'debug' =\u003e (bool) env('PHPSOCKETS_DEBUG', false),\n    ],\n\n    'chat' =\u003e [\n        'max_display_name_length' =\u003e (int) env('PHPSOCKETS_MAX_DISPLAY_NAME_LENGTH', 40),\n        'max_room_name_length' =\u003e (int) env('PHPSOCKETS_MAX_ROOM_NAME_LENGTH', 80),\n        'max_private_group_members' =\u003e (int) env('PHPSOCKETS_MAX_PRIVATE_GROUP_MEMBERS', 20),\n        'history_limit' =\u003e (int) env('PHPSOCKETS_HISTORY_LIMIT', 50),\n        'max_attachment_bytes' =\u003e (int) env('PHPSOCKETS_MAX_ATTACHMENT_BYTES', 2 * 1024 * 1024),\n    ],\n\n    'storage' =\u003e [\n        'driver' =\u003e env('PHPSOCKETS_STORAGE', 'memory'),\n        'database' =\u003e env('PHPSOCKETS_DATABASE'),\n        'dsn' =\u003e env('PHPSOCKETS_DSN'),\n        'username' =\u003e env('PHPSOCKETS_DB_USERNAME'),\n        'password' =\u003e env('PHPSOCKETS_DB_PASSWORD'),\n    ],\n];\n```\n\nExample `.env`:\n\n```env\nPHPSOCKETS_HOST=127.0.0.1\nPHPSOCKETS_PORT=8080\nPHPSOCKETS_MAX_PAYLOAD_BYTES=4194304\nPHPSOCKETS_MAX_ATTACHMENT_BYTES=2097152\nPHPSOCKETS_ATTACHMENT_DIR=.phpsockets/attachments\nPHPSOCKETS_STORAGE=memory\nPHPSOCKETS_DEBUG=true\n```\n\n---\n\n## API Overview\n\n### Main server\n\n```php\nuse Micilini\\PhpSockets\\Chat\\ChatServer;\nuse Micilini\\PhpSockets\\Config\\ChatConfig;\nuse Micilini\\PhpSockets\\Config\\ServerConfig;\n\n$server = ChatServer::create(\n    ServerConfig::new(host: '127.0.0.1', port: 8080),\n    ChatConfig::new(),\n);\n\n$server-\u003erun();\n```\n\n### Server events\n\n```php\n$server-\u003eon('user.joined', function (array $event): void {\n    // User joined the chat.\n});\n\n$server-\u003eon('user.left', function (array $event): void {\n    // User left the chat.\n});\n\n$server-\u003eon('message.received', function (array $event): void {\n    // A chat message was received.\n});\n\n$server-\u003eon('room.created', function (array $event): void {\n    // A private room was created.\n});\n\n$server-\u003eon('bot.responded', function (array $event): void {\n    // A bot generated a response.\n});\n```\n\n### Available high-level events\n\n- `user.joined`\n- `user.left`\n- `message.received`\n- `message.sent`\n- `room.created`\n- `bot.responded`\n\n### Available low-level socket events\n\n- `open`\n- `close`\n- `error`\n\n---\n\n## Storage\n\nPHPSockets uses in-memory storage by default. This is perfect for examples, demos and development.\n\nAvailable storage options:\n\n```txt\nmemory\nfile JSONL messages\npdo sqlite\npdo mysql\npdo pgsql\n```\n\n### SQLite migration example\n\n```php\nuse Micilini\\PhpSockets\\Database\\MigrationRunner;\nuse Micilini\\PhpSockets\\Storage\\Pdo\\PdoConnectionFactory;\n\n$pdo = PdoConnectionFactory::sqlite(__DIR__ . '/storage/phpsockets.sqlite');\n\n(new MigrationRunner($pdo))-\u003erun('sqlite');\n```\n\n### Laravel migration command\n\n```bash\nphp artisan phpsockets:migrate --driver=sqlite --database=database/phpsockets.sqlite\n```\n\n---\n\n## Attachments\n\nThe examples support small file messages.\n\n### Attachment runtime directory\n\nBy default, PHPSockets stores temporary example attachments in a project-local directory:\n\n```txt\n.phpsockets/attachments\n```\n\nYou can override this location with:\n\n```env\nPHPSOCKETS_ATTACHMENT_DIR=/absolute/path/to/attachments\n```\n\nThis is especially useful for production deployments, Laravel apps, containers and Windows environments.\n\nSupported MIME types:\n\n```txt\nimage/png\nimage/jpeg\nimage/gif\napplication/pdf\ntext/plain\n```\n\nDefault max file size:\n\n```txt\n2 MB\n```\n\nAttachment behavior:\n\n- selecting a file does not send it immediately;\n- the selected file appears as a pending attachment;\n- the user can add a text caption;\n- the file is sent only when the user clicks `Send`;\n- delivered files include a download button;\n- unsafe MIME types are rejected;\n- files above the configured limit are rejected.\n\nThe initial transport uses JSON text-frame envelopes with base64 payloads over WebSocket. Larger uploads should use a future HTTP upload flow with WebSocket metadata messages.\n\n---\n\n## Bot Hooks\n\nPHPSockets includes a lightweight bot layer.\n\nBots can listen to text messages and return a response in the same conversation context.\n\nSupported contexts:\n\n- Global Room;\n- Direct conversations;\n- Private group rooms.\n\nExample:\n\n```php\nuse Micilini\\PhpSockets\\Contracts\\BotInterface;\nuse Micilini\\PhpSockets\\Chat\\Bot\\BotContext;\nuse Micilini\\PhpSockets\\Chat\\Bot\\BotResponse;\n\nfinal class EchoBot implements BotInterface\n{\n    public function name(): string\n    {\n        return 'EchoBot';\n    }\n\n    public function handle(BotContext $context): ?BotResponse\n    {\n        $text = trim($context-\u003etext());\n\n        if (!str_starts_with($text, '/echo ')) {\n            return null;\n        }\n\n        return BotResponse::text(substr($text, 6));\n    }\n}\n```\n\nRegister the bot:\n\n```php\n$server-\u003ebots()-\u003eregister(new EchoBot());\n```\n\nBots are intentionally simple in v1. They do not require any external AI API.\n\n---\n\n## Protocol Notes\n\nPHPSockets uses JSON text frames for chat messages.\n\nExample client message:\n\n```json\n{\n  \"type\": \"message.global\",\n  \"payload\": {\n    \"text\": \"Hello world 🚀\"\n  }\n}\n```\n\nExample server message:\n\n```json\n{\n  \"type\": \"message.received\",\n  \"payload\": {\n    \"message\": {\n      \"id\": \"msg_01\",\n      \"roomId\": \"global\",\n      \"fromUserId\": \"usr_01\",\n      \"kind\": \"text\",\n      \"body\": \"Hello world 🚀\"\n    }\n  }\n}\n```\n\nBinary WebSocket frames are not accepted by the chat core in this version. File messages are transported as validated JSON text-frame envelopes.\n\n---\n\n## Security Model\n\nPHPSockets includes a practical safety baseline for examples and local-first applications:\n\n- messages are rendered safely in the examples;\n- user-provided text should not be rendered with unsafe `innerHTML`;\n- display names are normalized and must be unique while online;\n- payload size is limited;\n- attachment size is limited;\n- attachment MIME type is validated;\n- users cannot send messages to rooms they do not belong to;\n- private group messages are delivered only to room members;\n- bot messages do not trigger infinite bot loops;\n- malformed frames can be rejected with WebSocket close codes.\n\nThis package is a realtime foundation. Production applications should still add authentication, authorization, HTTPS/WSS, monitoring, rate limiting, persistent storage and infrastructure hardening.\n\n---\n\n## Project Structure\n\n```txt\nsrc/\n  WebSocket.php\n  Config/\n    ServerConfig.php\n    ChatConfig.php\n  Protocol/\n    Handshake.php\n    Frame.php\n    FrameCodec.php\n    Opcode.php\n    CloseCode.php\n  Server/\n    WebSocketServer.php\n    ServerRuntime.php\n    SocketServer.php\n    Loop.php\n  Connection/\n    Connection.php\n    ConnectionRegistry.php\n  Events/\n    CallbackEventDispatcher.php\n    EventDispatcher.php\n  Contracts/\n    BotInterface.php\n    SessionStoreInterface.php\n    MessageStoreInterface.php\n    RoomStoreInterface.php\n    AttachmentStoreInterface.php\n  Chat/\n    ChatServer.php\n    ChatKernel.php\n    ChatMessage.php\n    Room.php\n    RoomManager.php\n    PresenceManager.php\n    Bot/\n      BotManager.php\n      BotContext.php\n      BotResponse.php\n  Storage/\n    InMemory/\n    File/\n    Pdo/\n  Database/\n    MigrationRunner.php\n    Schema/\n  Laravel/\n    PhpSocketsServiceProvider.php\n    PhpSocketsFacade.php\n    PhpSocketsManager.php\n    Commands/\n      ServeCommand.php\n      MigrateCommand.php\n      StatusCommand.php\n\nexamples/\n  easy-chat/\n  medium-chat/\n  private-chat/\n\nlegacy/\n  EasyChat/\n  MediumChat/\n```\n\n---\n\n## Testing and Quality\n\nInstall development dependencies:\n\n```bash\ncomposer install\n```\n\nValidate the package:\n\n```bash\ncomposer validate --strict\n```\n\nRun tests:\n\n```bash\ncomposer test\n```\n\nRun static analysis:\n\n```bash\ncomposer analyse\n```\n\nCheck code style:\n\n```bash\ncomposer cs:check\n```\n\nFix code style:\n\n```bash\ncomposer cs:fix\n```\n\nRun the full quality pipeline:\n\n```bash\ncomposer quality\n```\n\n---\n\n## Legacy Code\n\nThe original 2016 implementation is preserved under:\n\n```txt\nlegacy/EasyChat\nlegacy/MediumChat\nlegacy/README-2016.md\nlegacy/NOTES.md\n```\n\nThe legacy code is kept for historical and educational purposes only. The modern Composer package lives in `src/` and does not depend on the old structure.\n\n---\n\n## Roadmap\n\nCurrent v1 focus:\n\n- native WebSocket core;\n- realtime server runtime;\n- chat kit;\n- EasyChat, MediumChat and PrivateChat;\n- private groups;\n- storage adapters;\n- small attachments;\n- bot hooks;\n- Laravel integration;\n- documentation and Packagist release.\n\nFuture ideas:\n\n- standalone CLI binary;\n- WSS/TLS helper documentation;\n- Redis adapter;\n- multi-process scaling;\n- chunked binary file transfer;\n- HTTP upload + WebSocket metadata;\n- JWT/auth adapters;\n- Laravel dashboard;\n- official Docker image;\n- benchmarks.\n\n---\n\n## Packagist Release Checklist\n\nBefore tagging a stable release:\n\n```bash\ncomposer validate --strict\ncomposer quality\n```\n\nThen:\n\n```bash\ngit tag v1.0.0\ngit push origin v1.0.0\n```\n\nSubmit the repository to Packagist:\n\n```txt\nhttps://packagist.org/packages/submit\n```\n\nAfter Packagist detects the package, users can install it with:\n\n```bash\ncomposer require micilini/php-websockets\n```\n\nRepository:\n\n```txt\nhttps://github.com/micilini/php-websockets\n```\n\n---\n\n## License\n\nPHPSockets is open-sourced software licensed under the [MIT license](LICENSE.txt).\n\n---\n\n## Credits\n\nCreated and maintained by [Micilini](https://github.com/micilini).\n\nOriginally created in 2016 and rebuilt as a modern native PHP realtime foundation in 2026.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicilini%2Fphp-websockets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicilini%2Fphp-websockets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicilini%2Fphp-websockets/lists"}