PHP Live Chat With Websockets – Free Code Download

Welcome to a tutorial on how to create a PHP live chat application with WebSockets. Looking to add live chat features to your website or portal?

Well, the simplified mechanics of a PHP WebSockets live chat application are as follow:

  1. Create a command-line PHP script that will run and manage a WebSocket chat server.
  2. Use the Javascript WebSocket API to connect clients to the PHP chat server.
  3. Lastly, the chat mechanism is simple. When a client sends a chat message to the server, the server simply forwards the message to all connected clients.

But just how exactly is it done? Let us walk through an example in this guide – Read on to find out!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Notes PHP Chat Server Chat Client
Useful Bits & Links The End

 

DOWNLOAD & NOTES

First, here is the download link to the source code as promised.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

QUICK NOTES

  • A copy of PHP Ratchet is required, but not included in the zip file. The easiest way is to use Composer to pull the latest version – composer require cboden/ratchet
  • Change the port number in section D of 2-chat-server.php and the host in section B of 3c-chat-client.js. Make sure that the address is correct, and the port is not blocked.
  • Run 2-chat-server.php in the command line.
  • Access 3a-chat-client.html in your web browser.

If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

 

PHP CHAT SERVER

All right, let us now get started with creating the WebSocket server, by using a library called Ratchet.

 

DOWNLOAD RATCHET

  • If you want, you can get Ratchet from GitHub.
  • Or the easier way is to use Composer to pull the latest version. Simply navigate to your project folder in the command line and run composer require cboden/ratchet.

 

ENABLE THE PHP SOCKET EXTENSION

php.ini
extension=sockets

Also, please enable the sockets extension in your php.ini file.

 

PHP WEBSOCKET CHAT SERVER

2-chat-server.php
<?php
// (A) COMMAND LINE ONLY!
if (php_sapi_name() != "cli") { die("Please run this in the command line"); }

// (B) REQUIRE RATCHET
require "vendor/autoload.php";
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;

// (C) CHAT CLASS
class Chat implements MessageComponentInterface {
  // (C1) PROPERTIES
  private $debug = true; // Debug mode
  protected $clients; // Connect clients
  
  // (C2) CONSTRUCTOR - INIT LIST OF CLIENTS
  public function __construct () {
    $this->clients = new \SplObjectStorage;
    if ($this->debug) { echo "Chat server started.\r\n"; }
  }

  // (C3) ON CLIENT CONNECT - STORE INTO $THIS->CLIENTS
  public function onOpen (ConnectionInterface $conn) {
    $this->clients->attach($conn);
    if ($this->debug) { echo "Client connected: {$conn->resourceId}\r\n";  }
  }

  // (C4) ON CLIENT DISCONNECT - REMOVE FROM $THIS->CLIENTS
  public function onClose (ConnectionInterface $conn) {
    $this->clients->detach($conn);
    if ($this->debug) { echo "Client disconnected: {$conn->resourceId}\r\n";  }
  }

  // (C5) ON ERROR
  public function onError (ConnectionInterface $conn, \Exception $e) {
    $conn->close();
    if ($this->debug) { echo "Client error: {$conn->resourceId} | {$e->getMessage()}\r\n";  } 
  }

  // (C6) ON RECEIVING MESSAGE FROM CLIENT - SEND TO EVERYONE
  public function onMessage (ConnectionInterface $from, $msg) {
    if ($this->debug) { echo "Received message from {$from->resourceId}: {$msg}\r\n"; }
    foreach ($this->clients as $client) { $client->send($msg); }
  }
}

// (D) WEBSOCKET SERVER START!
$server = IoServer::factory(new HttpServer(new WsServer(new Chat())), 8080);
$server->run();

Not going to explain this line-by-line, but in essence:

  • Part A: Just a “safety check” to make sure the script is run from the command line.
  • Part B: Load and use the Ratchet library.
  • Part C: The chat class runs the mechanics behind the entire application. Basically:
    • We store all clients into $clients when they connect to the WebSocket server.
    • Captain Obvious, remove the clients from $clients when they disconnect.
    • On receiving a message from any client, we loop through $clients and forward the message to everyone.
  • Part D: Start running the server.

Yep. That’s all for the “complicated chat server”.

 

 

CHAT CLIENT

Now that we have the server-side ready, it’s time to build the chat clients – Which we can easily use the Javascript WebSocket API.

 

THE HTML PAGE

3a-chat-client.html
<!-- (A) CSS + JS -->
<link rel="stylesheet" href="3b-chat-client.css"/>
<script src="3c-chat-client.js"></script>

<!-- (B) CHAT DOCKET -->
<div id="chat-wrap">
  <!-- (B1) CHAT MESSAGES -->
  <div id="chat-messages"></div>
 
  <!-- (B2) SET NAME -->
  <form id="chat-name" onsubmit="return chat.start()">
    <input type="text" id="chat-name-set" placeholder="What is your name?" value="John Doe" required/>
    <input type="submit" id="chat-name-go" value="Start"/>
  </form>
 
  <!-- (B3) SEND MESSAGE -->
  <form id="chat-send" onsubmit="return chat.send()">
    <input type="text" id="chat-send-text" placeholder="Enter message" required/>
    <input type="submit" id="chat-send-go" value="Send"/>
  </form>
</div>

This should be straightforward, there are 3 parts to the HTML page:

  • <div id="chat-messages"> is where we will show all the chat messages.
  • <form id="chat-name"> is where we ask the user for a name before launching the chat.
  • Lastly, <form id="chat-send"> is the “send a message” box. This is hidden at first, will only show after the user enters a name and successfully connects to the WebSocket server.

 

 

COSMETIC CSS

3b-chat-client.css
/* (A) WRAPPER + SHARED */
#chat-wrap {
  border: 1px solid #aaa;
  max-width: 600px;
}
#chat-messages, #chat-name, #chat-send { padding: 10px; }

/* (B) CHAT MESSAGES */
#chat-messages {
  height: 300px;
  overflow: auto;
}
.ch-row {
  display: flex;
  margin-bottom: 5px;
}
.ch-name, .ch-msg {
  padding: 10px;
}
.ch-name {
  width: 150px;
  background: #d63737;
  color: #fff;
  font-weight: bold;
}
.ch-msg {
  width: 100%;
  background: #ffe9e9;
}

/* (C) NAME + SEND MESSAGE */
#chat-wrap input {
  padding: 10px;
  border: 0;
}
#chat-wrap input[type=submit] {
  background: #5c63c1;
  color: #fff;
  cursor: pointer;
}
#chat-wrap input[type=submit]:disabled { background: #b9b9b9; }
#chat-name { display: grid; }
#chat-send { display: none; }
#chat-name, #chat-send {
  grid-template-columns: 80% 20%;
  background: #e2e2e2;
}

Just some cosmetics to make things look better. Feel free to change to fit the theme of your own project.

 

 

LIVE CHAT JAVASCRIPT

3c-chat-client.js
var chat = {
  // (A) HELPER FUNCTION - SWAP BETWEEN SET NAME/SEND MESSAGE
  swapform : function (direction) {
    // (A1) SHOW SEND MESSAGE FORM
    if (direction) {
      document.getElementById("chat-name").style.display = "none";
      document.getElementById("chat-send").style.display = "grid";
    }

    // (A2) SHOW SET NAME FORM
    else {
      document.getElementById("chat-send").style.display = "none";
      document.getElementById("chat-name").style.display = "grid";
      document.getElementById("chat-name-go").disabled = false;
    }
  },

  // (B) START CHAT
  host : "ws://192.168.0.100:8080/", // Change to your own!
  name : "", // Current user name
  socket : null, // Websocket object
  htmltxt : null, // HTML send text field
  start : function () {
    // (B1) CREATE WEB SOCKET
    document.getElementById("chat-name-go").disabled = true;
    if (chat.htmltxt==null) { chat.htmltxt = document.getElementById("chat-send-text"); }
    chat.socket = new WebSocket(chat.host);

    // (B2) READY - CONNECTED TO SERVER
    chat.socket.onopen = function (e) {
      chat.name = document.getElementById("chat-name-set").value;
      chat.swapform(1);
    };

    // (B3) ON CONNECTION CLOSE
    chat.socket.onclose = function (e) {
      chat.swapform(0);
    };

    // (B4) ON RECEIVING DATA FROM SEREVER - UPDATE CHAT MESsAGES
    chat.socket.onmessage = function (e) {
      let msg = JSON.parse(e.data),
          row = document.createElement("div");
      row.innerHTML = `<div class="ch-name">${msg.n}</div><div class="ch-msg">${msg.m}</div>`;
      row.className = "ch-row";
      document.getElementById("chat-messages").appendChild(row);
    };
 
    // (B5) ON ERROR
    chat.socket.onerror = function (e) {
      chat.swapform(0);
      console.log(e);
      alert(`Failed to connect to ${chat.host}`);
    };
 
    return false;
  },

  // (C) SEND MESSAGE
  send : function () {
    let message = JSON.stringify({
      n: chat.name,
      m: chat.htmltxt.value
    });
    chat.htmltxt.value = "";
    chat.socket.send(message);
    return false;
  }
};

This is yet another “massive script”, but keep calm and look carefully.

  • The var chat object literally contains all the mechanics to run the live chat on the client-side.
  • Part A: Remember that the “send message” docket will show after the user enters a name? swapform() is the helper function that does the switcheroo thing.
  • Part B: A whole bunch of stuff that happens after the user enters the name and click on “start”. Long story short, start() creates a WebSocket object, connects to the server, and handles the HTML chat update on receiving messages from the server.
  • Part C: Self-explanatory, send() will send a chat message to the server.

 

 

USEFUL BITS & LINKS

That’s all for this guide, and here is a small section on some extras that may be useful to you.

 

LINKS & REFERENCES

If you want to learn more about sockets, here are the official links:

 

THE END

Thank you for reading, and we have come to the end of this guide. That took quite a lot of research, work, and I can easily see why some people are charging money for it… But I hope that this has helped you in your project, and if you want to share anything, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *