How to send data from Client to Server with Laravel Echo

David Toth
4 min readOct 10, 2021

--

Laravel comes with a good implementation of WebSocket. It’s easy to broadcast information to the users and between clients. You could simply write a good real-time web application using these features.

The Problem

Originally the WebSocket protocol is based on full-duplex communication channels. Laravel only implements message delivery from server-to-client. There is no way to send data from client-to-server through the WebSocket Server. Nevertheless, this featureless makes the framework more secure: if the code written on client-side is not well accomplished some security and server-balance issues could come up. That’s why you should be very careful when you work on client-to-server data sending.

What we have

When we are broadcasting the data is published to a Redis Channel, the Socket server subscribed to that and listening for any changes. If something happens the Socker server will send the data to the client-side.

Simple broadcasting from the server

The Concept

In the first view, it seems like Laravel only implements the server-to-client communication, but this is half true. There is the whispering function, which is used for client-to-client message sending. The Socket server processes the data and sends it to the other client, who is also joined to the channel.

Client communication between clients

We can grab this function and extend it with our solution. When the Socket server emits the data for the clients, it is also published to the Redis channel. Later, we should write a CLI command that is subscribed to the specific channel and correctly process.

Client communication to the server

The Implementation

We will use the Laravel Echo & Redis & Laravel-Echo-Server trio. Although we will use a fork of Laravel-Echo-Server that is capable to publish data to the Redis channel: when the Echo whispering method is called, the Socket Server not just forwarding the message to other clients the data will be also published to the specific Redis channel (same as which it’s reading).

After you downloaded and configured the server start it:

node bin/server.js start

On the client side we should implement the whispering

Echo.join('orderTable.' + orderId).whisper(
'OrderUpdated',
{
message: 'This message will be available from the server.'
}
);

Don’t forget: the channel should be a presence or private channel, so you will be able to use the whisper function.

Now, we should write the command, which is subscribed to our channel. First of all, make the class:

php artisan make:command RedisSubscriber

Change the signature for something else:

protected $signature = 'redis:subscribe';

According to the Laravel documentation, we could subscribe to channels using wildcard. This is useful in this situation because Laravel and Socket server are using prefixes in the channel’s name for better isolation and recognition when multiple apps use the same Redis server. And also we adding postfixes to separate our channels from each other (based on the app’s business logic). Knowing this information in the handle() method we could subscribe to the channel:

Redis::psubscribe(['*orderTable.*'], function ($message, $channel) {
// do something
});

When you run your command after some time you could run into this error:

read error on connection to 127.0.0.1:6379

This error will be thrown by PHP after 60 seconds and closing the connection with the Redis server. You could manually change the default timeout:

ini_set("default_socket_timeout", -1); //-1 is not set

Finally, this is how our Redis Subscriber should look like:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class RedisSubscriber extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'redis:subscribe';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
ini_set("default_socket_timeout", -1);

Redis::psubscribe(['*orderTable.*'], function ($message, $channel) {
echo $channel;
echo PHP_EOL;
echo $message;
echo PHP_EOL;
});
}
}

⭐️ Do you want to support my work or are you just an amazing person? Well, if you are, you could buy me a coffee!

--

--