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!

ⓘ 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

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Create a database, import 1-database.sql.
  • Change the database settings in 2-lib-msg.php to your own.
  • Launch 4-demo-msg.php in the browser and test send some messages.
  • Change $_SESSION["user"] in 2-lib-msg.php to act as another user.
If you spot a bug, feel free to comment below. I try to answer short 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.

 

SCREENSHOT

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example 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.

 

 

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 () { try {
    $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
    ]);
  } catch (Exception $ex) { exit($ex->getMessage()); }}
 
  // (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) {
    $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", "utf8");
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, $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) INVALID
    default: echo "Invalid request"; break;
 
    // (B) 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;
 
    // (C) 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">
    <img src="x-potato.png">
    <?=$_SESSION["user"]["name"]?>
  </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.

 

 

EXTRA BITS & LINKS

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.
  • Security – In your project, do checks to remove <script><iframe> and other funky HTML tags from the messages. Maybe an anti-spam feature too.
  • User Login – Once again, check out the links below if you don’t have a user system.

 

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.