How To Make Real-time Chat Application Using PHP

PHP Real-time Chat Application Project

Real-time communication has become a fundamental aspect of modern web applications. In this tutorial, you will learn how to create a real-time chat application using PHP for the backend logic and WebSocket protocol, coupled with HTML, CSS, and JavaScript for the frontend user interface.

By the end of this tutorial, you’ll have a solid understanding of how to implement a basic real-time chat application from scratch.

Prerequisites before proceeding:

  • Basic understanding of PHP, HTML, CSS, and JavaScript.
  • Composer installed for managing PHP dependencies.
  • Understanding of WebSockets and its implementation with PHP.

Technologies used in this app:

  • PHP: Backend logic and WebSocket server implementation.
  • WebSocket: Protocol for real-time bidirectional communication between clients and the server.
  • HTML: Structure of the web page.
  • CSS: Styling the user interface.
  • JavaScript: Client-side scripting for WebSocket communication and UI interactions.

Follow The Steps To Build Real-time Chat Application Using PHP

Steps #

Step 1: Create the Project Folder (php-chat-app)

Create a new directory for this project called php-chat-app, then go inside the folder and Install the Ratchet via composer:

composer require cboden/ratchet

PHP Chat App Folder Structure:

PHP Chat App Folder Structure

Step 2: Implement the WebSocket Server using PHP Ratchet

Create a new PHP file for the WebSocket server, e.g., socket.php. Now we will use the Ratchet library to create a WebSocket server. Here is code:

<?php

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

require __DIR__ . '/vendor/autoload.php';

// Define a class named MyChat that implements the MessageComponentInterface
class MyChat implements MessageComponentInterface
{
    protected $clients;

    // Constructor initializing SplObjectStorage to store connected clients
    public function __construct()
    {
        $this->clients = new \SplObjectStorage;
    }

    // Method triggered when a new connection is opened
    public function onOpen(ConnectionInterface $conn)
    {
        // Attach the new connection to the list of clients
        $this->clients->attach($conn);
    }

    // Method triggered when a message is received from a client
    public function onMessage(ConnectionInterface $from, $msg)
    {
        // Send the received message to all clients except the sender
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                $client->send($msg);
            }
        }
    }

    // Method triggered when a connection is closed
    public function onClose(ConnectionInterface $conn)
    {
        // Detach the closed connection from the list of clients
        $this->clients->detach($conn);
    }

    // Method triggered when an error occurs on a connection
    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        // Close the connection in case of error
        $conn->close();
    }
}

// Create a new Ratchet application listening on localhost:8080
$app = new Ratchet\App('localhost', 8080);
// Define a route '/chat' for the MyChat class
$app->route('/chat', new MyChat, array('*'));
// Run the Ratchet application
$app->run();

Step 3: Create the Frontend UI for the Chat-App

Create an HTML file (e.g., index.html) for the chat layout, including message display area, input field, and send button. Here is the index.html code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>PHP Realtime Chat Application</title>
        <!-- Link to external stylesheet -->
        <link rel="stylesheet" href="./styles.css" />
    </head>
    <body>
        <div class="chat-container">
            <!-- Container for displaying chat messages -->
            <div class="chat-box" id="chat-box"></div>
            <!-- Input field for user messages -->
            <input
                type="text"
                id="user-input"
                placeholder="Type a message..."
                onkeydown="submitOnEnter(this)"
            />
            <!-- Button to send message -->
            <button onclick="sendMessage()">Send</button>
        </div>

        <!-- Link to external JavaScript file -->
        <script src="./script.js"></script>
    </body>
</html>

Now style the above chat interface using CSS to make it visually appealing. Here is styles.css code:

* {
    scroll-behavior: smooth;
    box-sizing: border-box;
}
body {
    font-family: Arial, sans-serif;
}

.chat-container {
    width: 350px;
    margin: 50px auto;
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 10px;
}

.chat-box {
    height: 350px;
    overflow-y: scroll;
    margin-bottom: 10px;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

input[type="text"] {
    width: 200px;
    padding: 5px;
    margin-right: 5px;
}

button {
    padding: 5px 10px;
    cursor: pointer;
}

.incoming,
.outgoing {
    display: flex;
}

.outgoing {
    justify-content: right;
}

.incoming {
    justify-content: left;
}

.wrapper .name,
.wrapper .message {
    padding: 0;
    margin: 0;
    font-size: 14px;
}
.wrapper .name {
    font-size: 12px;
}

.wrapper .message {
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 3px;
    padding: 3px;
    background: #fbf3d4;
}

.incoming .message {
    background: #ec1982;
    color: white;
}

After that we need to write JavaScript code to establish a WebSocket connection with the server and handle message sending/receiving. Here is the script.js code:

// Establish a WebSocket connection to the server
var socket = new WebSocket("ws://localhost:8080/chat");

// Initialize variables to store user name and connection status
let userName = null;
let socketIsOn = false;

// Select DOM elements
const userInput = document.querySelector("#user-input");
const chatBox = document.querySelector("#chat-box");

// Event handler triggered when the WebSocket connection is established
socket.onopen = function (e) {
    socketIsOn = true;
};

// Immediately Invoked Function Expression (IIFE) to handle user name
(function () {
    const name = localStorage.getItem("name");
    if (name !== null) {
        // Retrieve user name from localStorage if available
        userName = name;
        return;
    }
    if (name === null) {
        // Prompt user to enter their name if not stored in localStorage
        let person = prompt("Please enter your name");
        if (person === null || !person.match(/^[A-Za-z0-9 ]+$/)) {
            // Validate the entered name
            alert("Invalid Name (Use only letters and numbers)");
            handleUserName();
        } else {
            // Store the user name in localStorage
            localStorage.setItem("name", person);
            userName = person;
        }
    }
})();

// Function to create a new DOM element with attributes
const createEl = (type, attr = {}) => {
    const el = document.createElement(type);
    for (i in attr) {
        el.setAttribute(i, attr[i]);
    }
    return el;
};

// Function to generate a message DOM structure
function generateMessage(userName, msg) {
    const wrapper = createEl("div", {
        class: "wrapper",
    });

    const name = createEl("span", {
        class: "name",
    });
    name.innerText = userName;

    const message = createEl("p", {
        class: "message",
    });
    message.innerText = msg;

    wrapper.appendChild(name);
    wrapper.appendChild(message);

    return wrapper;
}

// Function to send a message
function sendMessage() {
    const message = userInput.value.trim();
    if (userName == null || !socketIsOn || message == "") return;
    const msg = generateMessage(userName, message);
    const outgoingMsg = createEl("div", { class: "outgoing" });
    outgoingMsg.appendChild(msg);
    chatBox.appendChild(outgoingMsg);
    // Send the message to the server
    socket.send(JSON.stringify({ name: userName, message }));
    userInput.value = "";
}

// Event handler triggered when a message is received from the server
socket.onmessage = function ({ data }) {
    const { name, message } = JSON.parse(data);
    const msg = generateMessage(name, message);
    const incomingMsg = createEl("div", { class: "incoming" });
    incomingMsg.appendChild(msg);
    chatBox.appendChild(incomingMsg);
};

// Function to submit message on pressing Enter key
function submitOnEnter(ele) {
    if (event.key === "Enter") {
        sendMessage();
    }
}

Step 4: Test The PHP Real-Time Chat Application

Test your chat application locally by running the WebSocket server via command line, then open two web browsers (you can use incognito mode) and then open index.html in both browsers.

If you did all the steps correctly, you should see the following output:

php socket.php
Testing of the PHP real-time chat application

Congratulations, you have created a very simple real-time chat application using PHP with WebSocket. You can further enhance this application by adding features like user authentication, message persistence, and multimedia support. Happy coding!

Leave a Reply

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

We use cookies to ensure that we give you the best experience on our website. Privacy Policy