mrow mrow - 5 months ago 59
PHP Question

PHP Real Time chat with Ratchet Websockets

I'm a beginner in PHP Websockets and I'm trying to create real-time chat with database storage. I was doing pretty good, but now I'm standing at one problem. There's problem, when user1 sends message to user2 and user2 came to the site first (reload first on localhoste), it won't be "real-time".

Let me explain it further.

Here's my server.php. It is practicly the same as ratchet tutorial:

$loop = React\EventLoop\Factory::create();
$pusher = new \Pusher();
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://'); // Binding to means the only client that can connect is itself
$pull->on('message', array($pusher, 'onBlogEntry'));
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, ''); // Binding to means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer($pusher ))), $webSock);

In pusher.php are most important these methods (I omitted other non-important stuff):

protected $subscribedTopics = array();
protected $myID = array();

public function onSubscribe(ConnectionInterface $conn, $data) {
$this->subscribedTopics[json_decode($data)->teamID] = $data;
$this->myID[json_decode($data)->userID] = $data;

public function onBlogEntry($entry) {
$entryData = json_decode($entry, true);

if ((!array_key_exists($entryData['team_id'], $this->subscribedTopics)) ||
(!array_key_exists($entryData['to_user_id'], $this->myID))
) {

$teamID = $this->subscribedTopics[$entryData['team_id']];

In my presenter Class I have simple form. When user submits this form, this code follows:

$this->chatPartner = $values['to_user_id']; //this I get from the form
$this->redrawControl('msg'); //here I redraw my layout
$this->messages_model->addMessage($values); //here I send data to database
$context = new \ZMQContext();
$socket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher');

Then, in view I have this JavaScript code:

var myJSON = '{'
+ '"teamID" : {$teamId},' //this I get from the presenter
+ '"userID" : {$userId}' //this I get from the presenter
+ '}';
var conn = new ab.Session('ws://localhost:8080',
function() {
conn.subscribe(myJSON, function(topic, data) {
if (data.from_user_id == mypartnerIdA) {
//here I edit the DOM
function() {
console.warn('WebSocket connection closed');
{'skipSubprotocolCheck': true}

So, back to my problem. I simulate 2 users. User1 reloads this page, where is javascript connection first. User2 reloads this page after him. When User1 sends a message to user2, message appers immediatly (real-time). But when user2 sends a message to user1, this message doesn't appear immediatly - it appears only after next reload of the page.

And my question is - How to fix this? How to make user2's message real-time, too? How can I fix this my code?


You probably have a misunderstanding of what the data yous end to subscribe is. It is meant to use for ID's of chat sessions.

for example:

  • A has a chat with B (chatId = 1)
  • B has a chat with C (chatId = 2)
  • C has a chat with A (chatId = 3)
  • A, B and C are in one chat (chatId = 4)

    var chatId = 2; //this chat is only between users B and C
    conn.subscribe( chatId , function(topic, data) {

The easiest way for me to understand it was by comparing it to a hashtag on twitter. Each hashtag is in your case a chatId. And for each subscription to a hashtag/chatId. You will have a WebSocket connection so that you receive all the updates for it.

This will be an easier way to do this in the long run then by having subdivided connections for a userId parameter. It can also easily be stored in a database so that you know whom to send the messages to and who not.