Create Group Chat In PHP With MySQL, jQuery And AJAX


Read {count} times since 2020

Chatting is one of the most implemented feature on websites. Group chat makes users to share their feelings and other news easily to their friends easily. AJAX makes this chatting more beautiful, elegant, simple and comfortable. Group chats may be vulnerable to SQL injections and XSS attacks. But in this post where we’re going to make a group chat that doesn’t have these vulnerabilities which makes it more awesome. You can see a demo, or you can download the files directly.

Things To Note

Make sure the Time Zone on MySQL server is the same as on PHP server. If the time zone is different, the user’s online presence can’t be understood.

We limit the name of the user to 20 characters, because we don’t want a long name that overflows the “online users” display element. There is no error message displayed when a user submits a name of more than 20 chars. If the user submits the name of 20 chars, the first 20 chars will only be inserted in to the table. Other chars after 20 chars will be removed by MySQL.

If you need Users’ Typing Status display with the chat, see this tutorial after completing this tutorial.

tables.sql

The SQL code that creates the two tables needed for the group chat is contained in the tables.sql file :

-- Set MySQL timezone to UTC
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET GLOBAL time_zone = "+00:00";
-- Table structure for table `chatters`
CREATE TABLE IF NOT EXISTS `chatters` (
  `name` varchar(20) NOT NULL,
  `seen` varchar(20) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- Table structure for table `messages`
CREATE TABLE IF NOT EXISTS `messages` (
  `name` varchar(20) NOT NULL,
  `msg` text NOT NULL,
  `posted` varchar(20) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

When you execute the above SQL code, you will have two tables, one chatters and the other messages. In chatters table, we add the logged in users’ details where as the other one, we will add the messages sent by the users.

config.php

The database configuration is stored in this file. You should change the credentials according to your database :

<?
// ini_set("display_errors","on");
if(!isset($dbh)){
 session_start();
 date_default_timezone_set("UTC");
 $musername = "username";
 $mpassword = "password";
 $hostname  = "hostname";
 $dbname    = "dbname";
 $dbh=new PDO('mysql:dbname='.$dbname.';host='.$hostname.";port=3306",$musername, $mpassword);
 /*Change The Credentials to connect to database.*/
 include("user_online.php");
}
?>

The session is started when this file loads. There is a file named user_online.php included in the file. This file deletes the offline users and updates the time stamp of the currently logged in user. This time stamp determines the online, offline status. I explained more about it in the user_online.php heading in this post.

index.php

The main character of our chat is this file. index.php joins everything together.

<?include("config.php");include("login.php");?>
<!DOCTYPE html>
<html>
 <head>
  <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
  <script src="chat.js"></script>
  <link href="chat.css" rel="stylesheet"/>
  <title>PHP Group Chat With jQuery & AJAX</title>
 </head>
 <body>
  <div id="content" style="margin-top:10px;height:100%;">
   <center><h1>Group Chat In PHP</h1></center>
   <div class="chat">
    <div class="users">
     <?include("users.php");?>
    </div>
    <div class="chatbox">
     <?
     if(isset($_SESSION['user'])){
      include("chatbox.php");
     }else{
      $display_case=true;
      include("login.php");
     }
     ?>
    </div>
   </div>
  </div>
 </body>
</html>

When a user is not logged in, this file will load the login.php file which have the login box and others. If the user is logged in, then it will directly display the chatbox.php which contains the chatbox. Users who are currently online are shown using users.php file.

login.php

The login box and the login authentication, filtering, checking are added in this file. This file is included twice in the index.php file, one for checking and other for displaying login box.

<?
if(isset($_POST['name']) && !isset($display_case)){
 $name=htmlspecialchars($_POST['name']);
 if($name!=""){
  $sql=$dbh->prepare("SELECT name FROM chatters WHERE name=?");
  $sql->execute(array($name));
  if($sql->rowCount()!=0){
   $ermsg="<h2 class='error'>Name Taken. <a href='index.php'>Try another Name.</a></h2>";
  }else{
   $sql=$dbh->prepare("INSERT INTO chatters (name,seen) VALUES (?,NOW())");
   $sql->execute(array($name));
   $_SESSION['user']=$name;
  }
 }else{
  $ermsg="<h2 class='error'><a href='index.php'>Please Enter A Name.</a></h2>";
 }
}elseif(isset($display_case)){
 if(!isset($ermsg)){
?>
 <h2>Name Needed For Chatting</h2>
 You must provide a name for chatting. This name will be visible to other users.<br/><br/>
 <form action="index.php" method="POST">
  <div>Your Name : <input name="name" placeholder="A Name Please"/></div>
  <button>Submit & Start Chatting</button>
 </form>
<?
 }else{
  echo $ermsg;
 }
}
?>

If the user has submitted the login form, then this file will do the following :

  • Filter Name (Remove HTML entities)
  • Check If there is another user with the name

If everything is OK, then the file changes the user value of session to the name submitted. index.php and chatbox.php takes care of the rest.

chatbox.php

This file don’t have that much content. This file contains the log out link, chat messages container and chat form :

<?
include("config.php");
if(isset($_SESSION['user'])){
?>
 <h2>Room For ALL</h2>
 <a style="right: 20px;top: 20px;position: absolute;cursor: pointer;" href="logout.php">Log Out</a>
 <div class='msgs'>
  <?include("msgs.php");?>
 </div>
 <form id="msg_form">
  <input name="msg" size="30" type="text"/>
  <button>Send</button>
 </form>
<?
}
?>

The messages are displayed from msgs.php and the form is also displayed.

msgs.php

Displays the messages sent by the other users and himself/herself. A request is made to this file every 5 seconds to check new messages. When the user logs out from another page of the browser window, msgs.php will make the current page reload to make sure everything is alright.

<?
include("config.php");
$sql=$dbh->prepare("SELECT * FROM messages");
$sql->execute();
while($r=$sql->fetch()){
 echo "<div class='msg' title='{$r['posted']}'><span class='name'>{$r['name']}</span> : <span class='msgc'>{$r['msg']}</span></div>";
}
if(!isset($_SESSION['user']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest'){
 echo "<script>window.location.reload()</script>";
}
?>

send.php

When the user submits a message, the message is sent to send.php. This file handles the message, filters it and insert into database.

<?
include("config.php");
if(!isset($_SESSION['user']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest'){
 die("<script>window.location.reload()</script>");
}
if(isset($_SESSION['user']) && isset($_POST['msg'])){
 $msg=htmlspecialchars($_POST['msg']);
 if($msg!=""){
  $sql=$dbh->prepare("INSERT INTO messages (name,msg,posted) VALUES (?,?,NOW())");
  $sql->execute(array($_SESSION['user'],$msg));
 }
}
?>

users.php

Currently online users are displayed using this file. This file is also requested in every 5 seconds by jQuery.

<?
include("config.php");
echo "<h2>Users</h2>";
$sql=$dbh->prepare("SELECT name FROM chatters");
$sql->execute();
while($r=$sql->fetch()){
 echo "<div class='user'>{$r['name']}</div>";
}
?>

user_online.php

Whenever the config.php file is called, this file is also called. This file loops through the online users on table chatters and check if their time stamp is lesser that 25 seconds the current time. If it is lesser, then that user is dropped (deleted) from the table. It also updates the time stamp of the currently logged in user if there is one making it impossible for the other script to delete the current user. It is necessary to have the same time zone on **MySQL **server and the PHP server. If the currently logged in user is accidentally deleted in case of misunderstanding, the script will automatically add the user to the table chatters. What an important file !

<?
if(isset($_SESSION['user'])){
 $sqlm=$dbh->prepare("SELECT name FROM chatters WHERE name=?");
 $sqlm->execute(array($_SESSION['user']));
 if($sqlm->rowCount()!=0){
  $sql=$dbh->prepare("UPDATE chatters SET seen=NOW() WHERE name=?");
  $sql->execute(array($_SESSION['user']));
 }else{
  $sql=$dbh->prepare("INSERT INTO chatters (name,seen) VALUES (?,NOW())");
  $sql->execute(array($_SESSION['user']));
 }
}
/* Make sure the timezone on Database server and PHP server is same */
$sql=$dbh->prepare("SELECT * FROM chatters");
$sql->execute();
while($r=$sql->fetch()){
 $curtime=strtotime(date("Y-m-d H:i:s",strtotime('-25 seconds', time())));
 if(strtotime($r['seen']) < $curtime){
  $kql=$dbh->prepare("DELETE FROM chatters WHERE name=?");
  $kql->execute(array($r['name']));
 }
}
?>

logout.php

If the user can log in,.there should be a log out option. Here is the file that will destroy the session and redirects to the main page or as you call it “logout” :

<?
session_start();
include("config.php");
$sql=$dbh->prepare("DELETE FROM chatters WHERE name=?");
$sql->execute(array($_SESSION['user']));
session_destroy();
header("Location: index.php");
?>

Client Side

It’s time to move to the client side, where we will design our chatbox with CSS and add the jQuery code to make it easy.

chat.css

The chatbox, online users and other styling is in here :

.chat .users, .chat .chatbox{
 display:inline-block;
 vertical-align:top;
 height:350px;
 padding:0px 15px;
 position:relative;
}
.chat .users{
 background:#CCC;
 color:white;
 width:98px;
 overflow-y:auto;
}
.chat .chatbox{
 background:#fff;
 color:black;
 margin-left:4px;
 width:330px;
}
.chat .chatbox .msgs{
 border-top:1px solid black;
 border-bottom:1px solid black;
 overflow-y:auto;
 height:260px;
}
.chat .chatbox #msg_form{
 padding-top:1.5px;
}
.chat .error{color:red;}
.chat .success{color:green;}
.chat .msgs .msg, .chat .users .user{border-bottom:1px solid black;padding:4px 0px;white-space:pre-line;word-break:break-word;}

The elements we added are all wrapped in the .chat container, so the chat.css won’t mess up any other styles of your site.

chat.js

The jQuery code is the content of this file. Note that you should add a **script[src] **that links to the jQuery library source.

function scTop(){
 $(".msgs").animate({scrollTop:$(".msgs")[0].scrollHeight});
}
function load_new_stuff(){
 localStorage['lpid']=$(".msgs .msg:last").attr("title");
 $(".msgs").load("msgs.php",function(){
  if(localStorage['lpid']!=$(".msgs .msg:last").attr("title")){
   scTop();
  }
 });
 $(".users").load("users.php");
}
$(document).ready(function(){
 scTop();
 $("#msg_form").on("submit",function(){
  t=$(this);
  val=$(this).find("input[type=text]").val();
  if(val!=""){
   t.after("<span id='send_status'>Sending.....</span>");
   $.post("send.php",{msg:val},function(){
    load_new_stuff();
    $("#send_status").remove();
    t[0].reset();
   });
  }
  return false;
 });
});
setInterval(function(){
 load_new_stuff();
},5000);

I think that’s all the files. I made it to these much files to make the tutorial easy. Hope you like it. Be open source, share this with your developer friends. I’m sure they would love to see this. If you have any problems / suggestions, please say it out in the comments, I would love to hear it from you and I will reply if there isn’t any stupid school projects.