{"id":18471388,"url":"https://github.com/gomoob/php-websocket-server","last_synced_at":"2025-04-08T11:32:11.561Z","repository":{"id":57002735,"uuid":"65845686","full_name":"gomoob/php-websocket-server","owner":"gomoob","description":"WebSocket server with tags management, forward your messages on the right clients with ease !","archived":false,"fork":false,"pushed_at":"2016-08-25T17:34:20.000Z","size":135,"stargazers_count":9,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-23T11:51:18.321Z","etag":null,"topics":["gomoob","php","ratchet","websocket","websocket-server"],"latest_commit_sha":null,"homepage":null,"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/gomoob.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-16T18:55:09.000Z","updated_at":"2023-11-07T12:43:05.000Z","dependencies_parsed_at":"2022-08-21T14:10:49.928Z","dependency_job_id":null,"html_url":"https://github.com/gomoob/php-websocket-server","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gomoob%2Fphp-websocket-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gomoob%2Fphp-websocket-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gomoob%2Fphp-websocket-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gomoob%2Fphp-websocket-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gomoob","download_url":"https://codeload.github.com/gomoob/php-websocket-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247833999,"owners_count":21003898,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["gomoob","php","ratchet","websocket","websocket-server"],"created_at":"2024-11-06T10:16:49.849Z","updated_at":"2025-04-08T11:32:11.015Z","avatar_url":"https://github.com/gomoob.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gomoob WebSocket server\n\n\u003e WebSocket server with tags management, forward messages on the right clients with ease !\n\n[![Total Downloads](https://img.shields.io/packagist/dt/gomoob/php-websocket-server.svg?style=flat)](https://packagist.org/packages/gomoob/php-websocket-server) \n[![Latest Stable Version](https://img.shields.io/packagist/v/gomoob/php-websocket-server.svg?style=flat)](https://packagist.org/packages/gomoob/php-websocket-server) \n[![Build Status](https://img.shields.io/travis/gomoob/php-websocket-server.svg?style=flat)](https://travis-ci.org/gomoob/php-websocket-server)\n[![Coverage](https://img.shields.io/coveralls/gomoob/php-websocket-server.svg?style=flat)](https://coveralls.io/r/gomoob/php-websocket-server?branch=master)\n[![Code Climate](https://img.shields.io/codeclimate/github/gomoob/php-websocket-server.svg?style=flat)](https://codeclimate.com/github/gomoob/php-websocket-server)\n[![License](https://img.shields.io/packagist/l/gomoob/php-websocket-server.svg?style=flat)](https://packagist.org/packages/gomoob/php-websocket-server)\n\n## Introduction\n\nThe Gomoob WebSocket server is a simple [Ratchet](http://socketo.me \"Ratchet\") server which works with custom tags \nto easily forward messages to clients depending on custom tags.\n\nAs an example let's suppose we have a Web Application with English and French users. English users should receive \nEnglish messages, French users should receive French messages.\n\nEach application opens a Web Socket with a particular `language` tag.\n\n```javascript\n// Web Application in English mode\nvar enWebSocket = new WebSocket('ws://localhost:8080?tags={\"language\":\"EN}');\n\n...\n\n// Web Application in French mode\nvar frWebSocket = new WebSocket('ws://localhost:8080?tags={\"language\":\"FR}');\n\n...\n```\n\nOn server side the Gomoob WebSocket server keeps track of the associations between tags and WebSocket connections. For \nexample this simple PHP peace of code allows to easily forward a message to all clients connected with the `language=FR` tag.\n\n```php\n// PHP Server (in most cases a Web Server) to Web Socket server client, allows to send one message which is forwared to\n// several opened WebSocket connections\n$phpClient = new WebSocketClient('ws://localhost:8080');\n$phpClient-\u003esend(WebSocketRequest::create($message, ['language' =\u003e 'FR']);\n```\n\n## Installation\n\n### Server side (run the server)\n\nRunning a server requires only one line of code.\n\n```php\nrequire __DIR__ . '/vendor/autoload.php';\n\necho \"WebSocket server started, enter Ctrl+C to stop server.\" . PHP_EOL;\n\\Gomoob\\WebSocket\\Server\\WebSocketServer::factory()-\u003erun();\n```\n\n### Client side (PHP)\n\nFirst pull the project with composer using the following dependency.\n\n```json\n{\n    \"require\": {\n        \"gomoob/php-websocket-server\": \"^1.0.0\"\n    }\n}\n```\n\nThen simply use the `\\Gomoob\\WebSocket\\Client\\WebSocketClient` class to send your messages.\n\n```php\n// Open a Server / Server WebSocket connection\n$phpClient = new WebSocketClient('ws://localhost:8080');\n\n// Forward a message to all the WebSocket client connections associated to 'tag1' and 'tag2'\n$response = $phpClient-\u003esend(\n    WebSocketRequest::create(\n        $message, \n        [\n            'tag1' =\u003e 'tag1Value',\n            'tag2' =\u003e 'tag2Value'\n        ]\n    )\n);\n```\n\nIf you want to write solid unit tests we also provide the `\\Gomoob\\WebSocket\\Client\\WebSocketClientMock` \nclass. This class is a utility mock which is very easy to use.\n\n```php\n// Somewhere in our code we use a \\Gomoob\\WebSocket\\IWebSocketClient ...\n// We suppose this code is implemented in MyPowerfulService-\u003eserviceMethod();\n$phpClient-\u003esend(WebSocketRequest::create('Message 0.')-\u003esetTags(['tag0' =\u003e 'tag0Value']));\n$phpClient-\u003esend(WebSocketRequest::create('Message 1.')-\u003esetTags(['tag1' =\u003e 'tag0Value']));\n$phpClient-\u003esend(WebSocketRequest::create('Message 2.')-\u003esetTags(['tag0' =\u003e 'tag0Value', 'tag1' =\u003e 'tag1Value']));\n\t\t\n// Then we write a test case by replacing the real WebSocket client implementation with the mock one\nclass SampleTestCase extends TestCase\n{\n    public function setUp() {\n        $this-\u003ewebSocketClient = new WebSocketClientMock();\n        $this-\u003emyPowerfulService-\u003esetWebSocketClient($this-\u003ewebSocketClient);\n    }\n\n    public function testServiceMethod() {\n    \n        // Calls the method to test\n        $this-\u003emyPowerfulService-\u003eserviceMethod();\n    \n        // Checks the right requests were sent\n        $webSocketRequests = $this-\u003ewebSocketClient-\u003efindByTags(['tag0' =\u003e 'tag0Value']);\n\t\t$this-\u003eassertCount(2, $webSocketRequests);\n\t\t$this-\u003eassertContains($webSocketRequest0, $webSocketRequests);\n\t\t$this-\u003eassertNotContains($webSocketRequest1, $webSocketRequests);\n\t\t$this-\u003eassertContains($webSocketRequest2, $webSocketRequests);\n    }\n}\n```\n\n## Advanced configuration\n\nThe default behavior of the Gomoob WebSocket server is the following !\n\n * Expose port `8080` and authorize connections from all IP addresses (i.e `0.0.0.0`) ; \n * Accept only plain string messages (exceptions are encountered if JSON messages are sent / received) ;\n * Use a default PSR logger which output messages on the terminal ; \n * Do not manage any authorization checks.\n\nIf one of those behaviors does not fit your need please read the following sub sections. You can also read the `src/test/server.php` file which shows how to start a server with custom message parsing and authorizations.\n\n### Message parser\n\nBy default the WebSocket server will accept plain string messages, if you try to send a JSON object then you'll \nencounter the following exception. \n\n```\nThe 'message' property is not a string, you must configure a message parser to parse messages !\n```\n\nThis is the expected behavior, if you want the server to manage custom PHP object messages then you have to :\n\n * Make your PHP object messages extends `\\JsonSerializable` and implement the `jsonSerialize()` method \n   correctly ; \n * Implement a custom message parser to create your custom PHP object messages when a plain JSON object is received.\n\nA sample message object is provided in the `\\Gomoob\\WebSocket\\Message\\Message` class, feel free to read the \nassociated source code to understand how it works. You'll also found a sample message parser in the `\\Gomoob\\WebSocket\\Message\\MessageParser`. \n\nTo explain how to manage custom PHP object messages let's suppose we have the following message object to send. \n\n```php\nclass MyMessage {\n    private $messageProperty1;\n    public function __construct($messageProperty1) {\n        $this-\u003emessageProperty1 = $messageProperty1; \n    }\n    public function getMessageProperty1() {\n        return $this-\u003emessageProperty1;\n    }\n}\n```\n\nSending such a message in a browser on Javascript would require the following code.\n\n```javascript\nvar socket = new WebSocket('ws://localhost:8080');\nsocket.send(\n    JSON.stringify(\n        {\n            message : {\n                messageProperty1 : \"Hello !\"\n            },\n            tags : {\n                tag1 : 'tag1Value'\n            }\n        }\n    )\n);\n```\n\nOr in PHP with the client we provide.\n\n```php\nWebSocketClient::factory('ws://localhost:8080')-\u003esend(WebSocketRequest::create(new MyMessage('Hello !')));\n```\n\nAs this this will not work because on server side the Gomoob WebSocket server will not know how to parse the messages \nand how to re-create those messages to forward them to clients who opened WebSocket connections.\n\nThe first thing to do is to implement the `\\JsonSerializable` class and the `jsonSerializeMethod()` in our \n`MyMessage` class.\n\n```php\nclass MyMessage implements \\JsonSerializable {\n   ...\n   public function jsonSerialize() {\n       return [\n           'messageProperty1' =\u003e $this-\u003emessageProperty1;\n        ];\n   }\n}\n```\n\nThen we have to implement a message parser by extending the `\\Gomoob\\WebSocket\\IMessageParser` class.\n\n```php\nuse Gomoob\\WebSocket\\IMessageParser;\n\nclass MyMessageParser implement IMessageParser {\n    public function parse(array $arrayMessage)\n    {\n        // Ensure the array contains only valid key names\n        foreach (array_keys($arrayMessage) as $key) {\n            if (!is_string($key) || !in_array($key, ['messageProperty1'])) {\n                throw new \\InvalidArgumentException('Unexpected property \\'' . $key . '\\' !');\n            }\n        }\n        \n        // The 'messageProperty1' property is mandatory\n        if (!array_key_exists('messageProperty1', $arrayMessage)) {\n            throw new \\InvalidArgumentException('No \\'messageProperty1\\' property found !');\n        }\n        \n        return new MyMessage($arrayMessage['messageProperty1']);\n    }\n}\n```\n\nFinally we have to provide our parser when we create our WebSocket server.\n\n```php\nWebSocketServer::factory(\n    [\n    \t'messageParser' =\u003e new MyMessageParser()\n    ]\n)-\u003erun();\n```\n\n### Authorization Manager\n\nBy default the WebSocket server will accept all connections and message sendings, in most cases this behavior is not \nexpected because anybody could open a WebSocket on your server and try to forward messages to all connected clients \nwithout authorization.\n\nYou can implement a custom authorization manager by implementing the `\\Gomoob\\WebSocket\\IAuthManager` \ninterface, this interface has the following signature.\n\n```php\n/**\n * Interface which defines an authorization manager. An authorization manager allows to control authorization while\n * opening Web Socket connections and sending messages over Web Sockets.\n *\n * @author Baptiste Gaillard (baptiste.gaillard@gomoob.com)\n */\ninterface IAuthManager\n{\n    /**\n     * Function used to indicate if connection opening is authorized.\n     *\n     * @param \\Ratchet\\ConnectionInterface $connection the current Ratchet connection.\n     *\n     * @return boolean `true` if the connection opening is authorized, `false` otherwise.\n     */\n    public function authorizeOpen(ConnectionInterface $connection);\n\n    /**\n     * Function used to indicate if message sending is authorized.\n     *\n     * @param \\Ratchet\\ConnectionInterface $connection the current Ratchet connection.\n     * @param \\Gomoob\\WebSocket\\IWebSocketRequest $webSocketRequest the current Gomoob WebSocket request.\n     */\n    public function authorizeSend(ConnectionInterface $connection, IWebSocketRequest $webSocketRequest);\n}\n```\n\nSo its very easy to manage authorizations, just return `true` or `false` with the `authorizeOpen(...)` or \n`authorizeSend(...)` functions.\n\n#### The `ApplicationsAuthManager`\n\nTo easier authorization we provide an authorization manager which allows to declare several applications with `key` \nand `secret` properties.\n\nThis authorization manager is available in the `\\Gomoob\\WebSocket\\Auth\\ApplicationsAuthManager` class, it \nworks with a very simple YAML configuration file.\n\nHere is a sample instanciation of the manager with a WebSocket server.\n\n```php\nWebSocketServer::factory(\n    [\n    \t'authManager' =\u003e ApplicationsAuthManager::factory(\n    \t    [\n    \t        'authorizeOpen' =\u003e false,\n    \t    \t'configurationFile' =\u003e __DIR__ . '/auth.yml'\n    \t    ]\n    \t)\n    ]\n)-\u003erun();\n```\n\nThe content of the `auth.yml` file could be the following.\n\n```yaml\napplications:\n  - \n    key: application1\n    secret: B4ajW3P7jfWEYPZsQV8mnteHg97G67uW\n    authorizeOpen: true\n  - key: application2\n    secret: 33yLWdynhaqm9tYjDFKf8gB8zmAPKdDP\n    authorizeOpen: false\n```\n\nThen the followig Javascript peace of code will apply.\n\n```javascript\n// Does not work because required 'key' and 'secret' URL parameters are not provided\nvar socket1 = new WebSocket('wss://myserver.org:8080'); \n\n// Works because the 'key' and 'secret' URL parameters provided are valid\nvar socket2 = new WebSocket('wss://myserver.ord:8080?key=application1\u0026secret=B4ajW3P7jfWEYPZsQV8mnteHg97G67uW');\n\n// Does not work because the request does not provide the 'key' and 'secret' properties\nsocket2.send(\n    JSON.stringify(\n        {\n            message : {\n                messageProperty1 : \"Hello !\"\n            }\n        }\n    )\n);\n\n// Works because the request provides valid 'key' and 'secret' properties\nsocket2.send(\n    JSON.stringify(\n        {\n            message : {\n                messageProperty1 : \"Hello !\"\n            },\n            metadata : {\n                key : 'application2',\n                secret : '33yLWdynhaqm9tYjDFKf8gB8zmAPKdDP'\n            }\n        }\n    )\n);\n```\n\nThe same rules are also applicable with the PHP client we provide.\n\n```php\nWebSocketClient::factory('ws://localhost:8080')-\u003esend(\n    WebSocketRequest::create(\n        new MyMessage('Hello !')\n    )-\u003esetMetadata(\n        [\n            'key' =\u003e 'application2',\n            'secret' =\u003e '33yLWdynhaqm9tYjDFKf8gB8zmAPKdDP'\n        ]\n    )\n);\n```\n\n## Docker container\n\nTo help you start quickly we also provide a Docker container here https://hub.docker.com/r/gomoob/php-websocket-server.\n\n## Release history\n\n### 1.2.0 (2016-08-23)\n * Moves the `TagsTree` class to `\\Gomoob\\WebSocket\\Util\\TagsTree` ; \n * Add a new `TagsTree-\u003ereset()` method ; \n * Add a new `\\Gomoob\\WebSocket\\Client\\WebSocketClientMock` class to easier unit testing ;\n * Update composer dependencies.\n\n### 1.1.0 (2016-08-18)\n * Add more PHP Documentor documentation about the goals of `metadata` in \n   the `\\Gomoob\\WebSocket\\IWebSocketRequest` interface and the \n   `\\Gomoob\\WebSocket\\Request\\WebSocketRequest` class ; \n * Add management of `defaultMetadata` in the `\\Gomoob\\WebSoscket\\IWebSocketClient` interface and the \n   `\\Gomoob\\WebSocket\\Client\\WebSocketClient` class ;\n * Add management of `defaultTags` in the `\\Gomoob\\WebSocket\\IWebSocketClient` interface and the \n   `\\Gomoob\\WebSocket\\Client\\WebSocketClient` class ; \n * Improve `\\Gomoob\\WebSocket\\Message\\Message` serialization ;\n * Improve `\\Gomoob\\WebSocket\\Request\\WebSocketRequest` serialization ;\n * Now all the factory methods can be calls with a `factory(...)` method or an alias `create(...)` method.\n\n### 1.0.3 (2016-08-17)\n * Fix `port` and `address` options problems while creating a `WebSocketServer`, the parameter were not \n   transmitted to the Ratchet server ;\n * Now the default port number is `80` which is the default Ratchet server port.\n\n### 1.0.2 (2016-08-17)\n * Add missing `symfony/yaml` composer dependency, otherwise problems was encountered while running \n   `composer update --no-dev` ;\n * Add missing `monolog/monolog` composer dependency, , otherwise problems was encountered while running \n   `composer update --no-dev`.\n\n### 1.0.1 (2016-08-17)\n * Configure specific Eclipse validator rules ;\n * Add MIT license.\n\n### 1.0.0 (2016-08-17)\n * First release.\n\n## About Gomoob\n\nAt [Gomoob](https://www.gomoob.com) we build high quality software with awesome Open Source frameworks everyday. Would \nyou like to start your next project with us? That's great! Give us a call or send us an email and we will get back to \nyou as soon as possible !\n\nYou can contact us by email at [contact@gomoob.com](mailto:contact@gomoob.com) or by phone number \n[(+33) 6 85 12 81 26](tel:+33685128126) or [(+33) 6 28 35 04 49](tel:+33685128126).\n\nVisit also http://gomoob.github.io to discover more Open Source softwares we develop.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgomoob%2Fphp-websocket-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgomoob%2Fphp-websocket-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgomoob%2Fphp-websocket-server/lists"}