Fantastic, we’re here to help!
Implementing WebSockets on a typical Node stack is easy. WebSockets with PHP… less easy. The way PHP executes is from the top down (or bottom up if you are in Australia), and once it reaches the bottom it stops. Unlike Node, it’s not a constantly running process. This requires us to create a process that can stay alive and listen to the front end.
If you’re developing a website with WordPress and want to push real time updates to the client, you might want to use WebSockets with PHP. We’re going to take a look at one way you could implement WebSockets on a WordPress / Nginx / Ubuntu stack.
High Level Overview
Here’s what were going to do:
- Create a server script responsible for starting the backend socket server – using the ZeroMQ messaging library and the Thruway router – synergizing together.
- Expose an endpoint from the server script which Nginx then proxies to a url that is accessible to the web client
- A web client will open a Websocket connection to the proxied url
- PHP code is triggered, and calls to ZeroMQ, which tells the socket library to send the message
Assumptions (lots of ’em)
For this quick tutorial, we’ll assume that:
- You have a WordPress site running on Nginx and Ubuntu
- You can access the Ubuntu server or environment that it runs on
- Your PHP version is >= 7.X.X,
- You know how to use Composer
- You can navigate on a server, configure server processes, understand client and server communication patterns.
Libraries we’ll be using
We are going to use some trusted and well known libraries to help us get this done quickly.
- Thruway – PHP Client and Router Library for Autobahn and WAMP (Web Application Messaging Protocol) for Real-Time Application Messaging
- ZMQ – An open-source universal messaging library
- Autobahn – WAMP in JavaScript for Browsers and NodeJS (client)
Installing Dependencies
Installing the ZeroMQ PHP extension
ZeroMQ is going to allow our socket connections to stay alive, whether they like it or not. To install the ZeroMQ PHP extension, so you can use it with PHP, use the following bash commands:
Note: Replace phpX.Y with your actual version
sudo apt-get -y install libzmq3-dev
sudo bash -c "echo extension=zmq.so > /etc/phpX.Y-sp/conf.d/zmq.ini"
sudo service phpX.Y-fpm-sp restart
Installing Thruway
Thruway is going to give us the WAMP 2.0 protocol which the Autobahn library also uses. To install Thruway with composer use the following:
php composer.phar require voryx/thruway
Installing Autobahn
Autobahn is the library we will be using to establish the client side connections to our Websocket enabled endpoint. You can install Autobahn with NPM . To do this use the following bash command:
npm install autobahn
Proxying with Nginx
We have to expose a way for our clients to easily open a Websocket connection with our server. So to do that we are going to use Nginx to proxy wss:example.com/socket to our socket router on the back end.
Edit your Nginx config file (most likely in /etc/nginx/sites-enabled/yours.conf) and add the following location block:
location /socket/ {
proxy_pass http://localhost:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
Reloading is safer than restarting, since configuration files are checked for syntax errors before changes are made. You will want to reload Nginx to safely apply the change by using the following bash command:
sudo nginx -s reload
The socket server script (socket-server.php)
We need to start up a socket server with a few configuration options before we can send messages.
Start by creating the file socket-server.php – I chose to create this script in the root directory of my WordPress installation because that’s just the way I am. Add the following to the socket-server.php file:
on('open', function ($session) use ($loop) {
// Bind to ZMQ so we can use it to send messages through socket server
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('message', function ($entry) use ($session) {
$entryData = json_decode($entry, true);
// $entryData['category'] will be whatever key you use from your php code
if (isset($entryData['category'])) {
$session->publish($entryData['category'], [$entryData]);
}
});
});
$router = new Thruway\Peer\Router($loop);
$router->addInternalClient($pusher);
// Make sure you use the same value here as you did in the Nginx config (port 8888)
$router->addTransportProvider(new Thruway\Transport\RatchetTransportProvider("0.0.0.0", 8888));
// Start'er up
$router->start();
To run the script, navigate to it and use the following bash command:
php socket-server.php
We now have a socket server instance running on our web server. Before publishing a message from the WordPress back end, we need to open a client connection. Let’s jump over to the front-end.
Establishing the client side connection
Ok! Now we have a socket server running, we’re proxying it with Nginx to a url, and now we can start listening for messages. Look at us go!
In your front-end javascript code you will at least need to:
- Open a socket connection to a url
- Perform an action upon receiving the socket message
To do this add the following lines to your front-end JavaScript:
setupSocketListeners() {
// Create a new autobahn connection
let connection = new autobahn.Connection({
url:”wss://example.com/socket/”, // <- wss:// is https only while ws:// can do http, all depends on your nginx config
realm: "SuperCoolRealmName" // <- Matches realm name in server code }); connection.onopen = session => {
// Subscribe to an incoming message event and bind to onSocketMessage
session.subscribe("message", this.onSocketMessage);
};
// Open the connection
connection.open();
}
onSocketMessage(args) {
let msg = args[0];
if (msg.category && msg.category == "message") {
// console.log(msg);
// do something with the received message!
}
}
// Don't forget to call your code, dude!
setupSocketListeners();
If you updated your Nginx config with the proxy location and reloaded Nginx you should have no issues establishing this connection.
Now that the client can receive messages, it’s time to send it one from your WordPress or general PHP code. Locate the file or class you want to use to send a message, and cast the following spell:
getSocket(ZMQ::SOCKET_PUSH);
// Connect to localhost:5555 which is the port you bound your instance to
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode(['message'=> 'Magical socket message!']));
If that code runs – it should publish a message to your client instance listening at .com/socket/
Final Thoughts
This tutorial is a great starting place for implementing some form of WebSockets on a WordPress site or really any PHP site. You may need to dive into the library documentation to do more than just broadcast messages to your front-end. Running the socket-server.php script can be a pain, and I recommend you turn it into a system service on your server, so that restarting and running the script is simple and reliable. While you’re doing that you may also want to check out our Security Tips We LOVE to Keep Your WordPress Site Safe.
With that being said, and like my friend Peter always says, “There’s more than one way to skin a cat, Cooper.”