Simple Messaging System With PHP MySQL (Free Download)

Welcome to a tutorial on how to create a simple messaging system with PHP and MYSQL. Want to add a “send message” or “private message” feature to your website? There are quite a number of things we need to cover – The database, PHP library, AJAX handler, and HTML page. Let us walk through a step-by-step example in this guide – Read on!

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

EXAMPLE CODE DOWNLOAD

Source code on GitHub Gist

Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

 

PHP MYSQL MESSAGING SYSTEM

All right, let us now get into the steps of building a messaging system with PHP MYSQL.

 

 

PART 1) DATABASE

1A) USERS TABLE

database.sql
-- (A) USERS
CREATE TABLE `users` (
  `user_id` bigint(20) NOT NULL,
  `user_name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `users`
  ADD PRIMARY KEY (`user_id`);
  ALTER TABLE `users`
  MODIFY `user_id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

INSERT INTO `users` (`user_id`, `user_name`) VALUES
  (1, 'Joe Doe'),
  (2, 'Jon Doe'),
  (3, 'Joy Doe');

If you already have an existing users table, feel free to ignore this – This is only a dummy table for example.

 

 

1B) MESSAGES TABLE

1-database.sql
-- (B) MESSAGES
CREATE TABLE `messages` (
  `user_from` bigint(20) NOT NULL,
  `user_to` bigint(20) NOT NULL,
  `date_send` datetime NOT NULL DEFAULT current_timestamp(),
  `date_read` datetime DEFAULT NULL,
  `message` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
ALTER TABLE `messages`
  ADD PRIMARY KEY (`user_from`, `user_to`, `date_send`),
  ADD KEY `date_read` (`date_read`);

Yep, that’s all we need for messaging. A very straightforward messages table.

  • user_from Sent from (User ID). Partial primary key.
  • user_to Sent to (User ID). Partial primary key.
  • date_send The time when the message is sent. Partial primary key.
  • date_read The time when the message is read.
  • message The message itself.

 

PART 2) PHP MESSAGE LIBRARY

2A) INITIALIZE

2-lib-msg.php
<?php
class Message {
  // (A) CONSTRUCTOR - CONNECT TO THE DATABASE
  private $pdo = null;
  private $stmt = null;
  public $error;
  function __construct () {
    $this->pdo = new PDO(
      "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET,
      DB_USER, DB_PASSWORD, [
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]);
  }
 
  // (B) DESTRUCTOR - CLOSE DATABASE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }
 
  // (C) EXECUTE SQL QUERY
  function query ($sql, $data=null) : void {
    $this->stmt = $this->pdo->prepare($sql);
    $this->stmt->execute($data);
  }
  // ...
}
 
// (G) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHARSET", "utf8mb4");
define("DB_USER", "root");
define("DB_PASSWORD", "");
 
// (H) MESSAGE OBJECT
$_MSG = new Message();
 
// (I) ACT AS USER
session_start();
$_SESSION["user"] = ["id" => 1, "name" => "Joe Doe"];
// $_SESSION["user"] = ["id" => 2, "name" => "Jon Doe"];
// $_SESSION["user"] = ["id" => 3, "name" => "Joy Doe"];

The library looks massive at first, but keep calm and study slowly.

  • (A, B, H) When $_MSG = new Message() is created, the constructor connects to the database. The destructor closes the connection.
  • (C) query() A helper function to run an SQL query.
  • (G) The database settings, remember to change these to your own.
  • (I) To “login” and test as different users. If you don’t have a user system, I will leave some links below.

 

 

2B) MESSAGING FUNCTIONS

2-lib-msg.php
// (D) GET ALL USERS & NUMBER OF UNREAD MESSAGES
function getUsers ($for) {
  // (D1) GET USERS
  $this->query("SELECT * FROM `users` WHERE `user_id`!=?", [$for]);
  $users = [];
  while ($r = $this->stmt->fetch()) { $users[$r["user_id"]] = $r; }
 
  // (D2) COUNT UNREAD MESSAGES
  $this->query(
    "SELECT `user_from`, COUNT(*) `ur`
      FROM `messages` WHERE `user_to`=? AND `date_read` IS NULL
      GROUP BY `user_from`", [$for]);
  while ($r = $this->stmt->fetch()) { $users[$r["user_from"]]["unread"] = $r["ur"]; }

  // (D3) RESULTS
  return $users;
}

// (E) GET MESSAGES
function getMsg ($from, $to, $limit=30) {
  // (E1) MARK ALL AS "READ"
  $this->query(
    "UPDATE `messages` SET `date_read`=NOW()
      WHERE `user_from`=? AND `user_to`=? AND `date_read` IS NULL", [$from, $to]);

  // (E2) GET MESSAGES
  $this->query(
    "SELECT m.*, u.`user_name` FROM `messages` m
      JOIN `users` u ON (m.`user_from`=u.`user_id`)
      WHERE `user_from` IN (?,?) AND `user_to` IN (?,?)
      ORDER BY `date_send` DESC
      LIMIT 0, $limit", [$from, $to, $from, $to]);
  return $this->stmt->fetchAll();
}

// (F) SEND MESSAGE
function send ($from, $to, $msg) {
  $this->query(
    "INSERT INTO `messages` (`user_from`, `user_to`, `message`) VALUES (?,?,?)",
    [$from, $to, strip_tags($msg)]
  );
  return true;
}

There are only “3 actual messaging functions” in this library.

  • (D) getUsers($for) Takes the perspective of user $for. Get all other users and the number of unread messages.
  • (E) getMsg($from, $to, $limit) Get the messages between $from and $to. Use $limit to limit the number of messages, or build your own pagination.
  • (F) send($from, $to, $msg) Send a message.

 

PART 3) MESSAGING AJAX HANDLER

3-ajax-msg.php
<?php
if (isset($_POST["req"])) {
  require "2-lib-msg.php";
  switch ($_POST["req"]) {
    // (A) SHOW MESSAGES
    case "show":
      $msg = $_MSG->getMsg($_POST["uid"], $_SESSION["user"]["id"]);
      if (count($msg)>0) { foreach ($msg as $m) {
        $out = $m["user_from"] == $_SESSION["user"]["id"]; ?>
        <div class="mRow <?=$out?"mOut":"mIn"?>">
          <div class="mDate"><?=$m["date_send"]?></div>
        </div>
        <div class="mRow <?=$out?"mOut":"mIn"?>"><div class="mRowMsg">
          <div class="mSender"><?=$m["user_name"]?></div>
          <div class="mTxt"><?=$m["message"]?></div>
        </div></div>
      <?php }}
      break;
 
    // (B) SEND MESSAGE
    case "send":
      echo $MSG->send($_SESSION["user"]["id"], $_POST["to"], $_POST["msg"])
        ? "OK" : $MSG->error ;
      break;
}}

A small “AJAX endpoint” which we will use to drive the HTML page later. How it works is very simple, just send $_POST["req"] along with the required parameters. For example, to send a message:

  • $_POST["req"] = "send";
  • $_POST["to"] = 123
  • $_POST["msg"] = "Some message."

 

 

PART 4) MESSAGING PAGE

4-demo-msg.php
<?php
// (A) GET USERS
require "2-lib-msg.php";
$users = $_ MSG->getUsers($_SESSION["user"]["id"]); ?>
 
<!-- (B) LEFT : USER LIST -->
<div id="uLeft">
  <!-- (B1) CURRENT USER -->
  <div id="uNow">
    <div><img src="x-girl.png"></div>
    <div><?=$_SESSION["user"]["name"]?></div>
  </div>
 
  <!-- (B2) USER LIST -->
  <?php foreach ($users as $uid=>$u) { ?>
  <div class="uRow" id="usr<?=$uid?>" onclick="msg.show(<?=$uid?>)">
    <div class="uName"><?=$u["user_name"]?></div>
    <div class="uUnread"><?=isset($u["unread"])?$u["unread"]:0?></div>
  </div>
  <?php } ?>
</div>
 
 <!-- (C) RIGHT : MESSAGES LIST -->
<div id="uRight">
  <!-- (C1) SEND MESSAGE -->
  <form id="uSend" onsubmit="return msg.send()">
    <input type="text" id="mTxt" required>
    <input type="submit" value="Send">
  </form>
 
  <!-- (C2) MESSAGES -->
  <div id="uMsg"></div>
</div>

The HTML page is in a 2 columns layout.

  • (B) <div id="uLeft"> A user list is on the left side.
  • (C) <div id="uRight"> On selecting a user, show the “send message” form and messages.

 

PART 5) MESSAGING JAVASCRIPT

5-demo-msg.js
var msg = {
  // (A) HELPER - AJAX FETCH
  ajax : (data, after) => {
    // (A1) FORM DATA
    let form = new FormData();
    for (const [k,v] of Object.entries(data)) { form.append(k, v); }
 
    // (A2) FETCH
    fetch("3-ajax-msg.php", { method:"POST", body:form })
    .then(res => res.text())
    .then(txt => after(txt))
    .catch(err => console.error(err));
  },
 
  // (B) SHOW MESSAGES
  uid : null, // current selected user
  show : uid => {
    // (B1) SET SELECTED USER ID
    msg.uid = uid;
 
    // (B2) GET HTML ELEMENTS
    let hForm = document.getElementById("uSend"),
    hTxt = document.getElementById("mTxt"),
    hUnread = document.querySelector(`#usr${uid} .uUnread`),
    hMsg = document.getElementById("uMsg");

    // (B3) SET SELECTED USER
    for (let r of document.querySelectorAll(".uRow")) {
      if (r.id=="usr"+uid) { r.classList.add("now"); }
      else { r.classList.remove("now"); }
    }
  
    // (B4) SHOW MESSAGE FORM
    hForm.style.display = "flex";
    hTxt.value = "";
    hTxt.focus();

    // (B5) AJAX LOAD MESSAGES
    hMsg.innerHTML = "";
    msg.ajax({
      req : "show",
      uid : uid
    }, txt => {
      hMsg.innerHTML = txt;
      hUnread.innerHTML = 0;
    });
  },
 
  // (C) SEND MESSAGE
  send : () => {
    let hTxt = document.getElementById("mTxt");
    msg.ajax({
      req : "send",
      to : msg.uid,
      msg : hTxt.value
    }, txt => {
      if (txt == "OK") {
        msg.show(msg.uid);
        hTxt.value = "";
      } else { alert(txt); }
    });
    return false;
  }
};

Finally, the Javascript. Yep, the messaging is heavily driven via AJAX. Don’t need to sweat, this is long-winded, but there are actually only 3 functions here.

  1. ajax() A support function, does an AJAX call to 3-ajax-msg.php.
  2. show() Fired when a user is selected. AJAX fetch the messages and show them.
  3. send() Self-explanatory. Send a message.

 

 

EXTRAS

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

 

IMPROVEMENT IDEAS

Before the trolls start to sing their broken tunes, this is only a simple example.

  • Not real time – For the lost souls, you need to refresh the page to show new messages. This is a “private messaging system”, not a “live chat system”. Big difference. Although it is possible to turn this into a live chat with WebSockets.
  • Anti-Spam – In your project, add anti-spam and anti-harassing features. Give users the ability to block another user and ignore messages.
  • User Login – Once again, check out the links below if you don’t have a user system.

 

MESSAGE TO MULTIPLE USERS

If you want a “chat group” or “message group”, it is not entirely impossible… But quite a number of changes need to be done.

  • Introduce new database tables.
    • message_group The main “message group” table with a running message_group_id.
    • message_group_users Pretty much ties user_id to message_group_id.
  • Add new functions to the PHP library.
    • createGroup() Add a new chat group.
    • sendGroup() Send a message to the group.
    • getGroup() Get all messages within the group.
  • Change the HTML interface.

Of course, you will also have to deal with a lot more spam and rules – What happens when a user wants to leave the group? What happens to groups that have no users left? Should there be an “admin” for the group? How to prevent people from harassing and adding people who already left the group? How to stop people from creating too many groups?

 

COMPATIBILITY CHECKS

This example will work on most modern browsers.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

4 thoughts on “Simple Messaging System With PHP MySQL (Free Download)”

    1. Well, this is a private messaging system. Although it is possible to:
      1) Add a “chat room” table (room_id, user_id).
      2) Add a “chat room messages” table (room_id, user_from, date_send, message).
      3) Add “send to chat room” and “get chat room messages” library functions.
      4) Modify the HTML/JS interface accordingly.

      Good luck.

Leave a Comment

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