Group Chat In PHP With Users’ Typing Status


I wrote a post on creating Group Chat in PHP. A comment was posted by Ravi asking if it was possible to include user’s typing status. It was a fascinating and a good idea to add user’s typing status. So, I worked on the code and knew it was possible. I’m going to tell you how to implement the display of users’ typing status on the Group Chat I created earlier.

This post is an addon of the Group Chat I mentioned earlier.

Create Table

For storing the users’ typing status, we should create a table. Here is the SQL code that creates the table typeStatus :

-- Table structure for table `typeStatus`
CREATE TABLE IF NOT EXISTS `typeStatus` (
 `name` varchar(20) NOT NULL,
 `what` varchar(20) NOT NULL,
 `inserted` varchar(20) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

typeStatus.php

Create a file named typeStatus.php and add the following code inside it :

<?
include("config.php");
if(isset($_POST['action']) && isset($_SESSION['user'])){
 $act=$_POST['action'];
 if($act=="startedTyping" || $act=="stoppedTyping"){
  $sql=$dbh->prepare("SELECT name FROM typeStatus WHERE `name`=?");
  $sql->execute(array($_SESSION['user']));
  if($sql->rowCount()==0){
   $sql2=$dbh->prepare("INSERT INTO typeStatus (`name`, `what`, `inserted`) VALUES (:name, :what, NOW())");
   $sql2->execute(array(
    ":name" => $_SESSION['user'],
    ":what" => $act
   ));
  }else{
   $query=$act=="startedTyping" ? "UPDATE typeStatus SET `what`=:what, `inserted`=NOW() WHERE name=:name":"UPDATE typeStatus SET `what`=:what WHERE name=:name";
   $sql2=$dbh->prepare($query);
   $sql2->execute(array(
    ":name" => $_SESSION['user'],
    ":what" => $act
   ));
  }
 }else{
  echo "You can't fool me.";
 }
}
?>

We send the AJAX request mentioning the type Status of the user to this file. This file process it and insert the data in to the database. This file only accepts data if the $_POST[‘action’] is “startedTyping” or “stoppedTyping”.

users.php

Replace the code in users.php to this :

<?
include("config.php");
echo "<h2>Users</h2>";
$sql=$dbh->prepare("SELECT name FROM chatters2");
$sql->execute();
while($r=$sql->fetch()){
 $name=$r['name'];
 echo "<div class='user'>$name";
 if(isset($_SESSION['user']) && $name!=$_SESSION['user']){
  $sql2=$dbh->prepare("SELECT what FROM typeStatus WHERE name=?");
  $sql2->execute(array($name));
  if($sql2->rowCount()!=0){
   $action=str_replace("startedTyping", "Typing...", str_replace("stoppedTyping", "Stopped Typing", $sql2->fetchColumn()));
   echo "<div class='status'>$action</div>";
  }
 }
 echo "</div>";
}
// Remove Old Type Statuses
$sql=$dbh->query("DELETE FROM typeStatus WHERE `inserted` < DATE_ADD(NOW(), INTERVAL -30 second) AND `what`='stoppedTyping'");
?>

We display the user’s type status in this file along with the user name. The status won’t be displayed for he current user in the list. If you want that, remove the if clause $name!=$_SESSION[‘user’]. Also, the type status of other users will only be displayed if the current user is logged in (registered) for chatting. If you want to remove this feature too, remove the if clause isset($_SESSION[‘user’]) && $name!=$_SESSION[‘user’].

We don’t need to flood the typeStatus table with logged out users’ type status. Hence every time the users.php file is executed, old records in typeStatus table will be removed if the inserted time is less than 30 seconds of the current time.**

**

chat.css

We added the new HTML element to the “Users” list. The element is of the class name “status”. So we should style it. Add the following CSS style to the end of the file :

.chat .users .user .status{
 font-size:11px;
 margin-left:5px;
}

The status should be fit in to the container. Hence we decreased the font size and to make it look like the status of user we add a margin of 15px to the left. Now, the status element will become like a sub text of the user name.

chat.js

This jQuery file has all the importance. It intelligently check whether the user is typing or not. If he /she ‘s typing, then jQuery will send a request to typeStatus.php and if not it will send another request with different data to the typeStatus.php file. Here is the changes you have to make.

Add a variable named lastKeyUp with value as integer before $(document).ready(function(){ :

lastKeyUp=0;
$(document).ready(function(){

In the $(document).ready(function(){ add the following code to listen the keyup made by the user on the message field :

$("#msg_form input[type=text]").keyup(function(){
 lastKeyUp=0;
 $.post("typeStatus.php", {action:"startedTyping"}, function(){
  lastKeyUp=0;
 });
});

When the user presses a key inside the field, jQuery will make the lastKeyUp variable to **** and will send a request to typeStatus.php with the following JSON Data :

{action:"startedTyping"}

typeStatus.php will take care of the rest.

And finally, we make a setInterval function to increment the lastKeyUp value and post data according to it. Add the code at the end of the file :

setInterval(function(){
 lastKeyUp = ++lastKeyUp % 360 + 1;
 if(lastKeyUp>5 && $("#msg_form input[type=text]").val()!=""){
  $.post("typeStatus.php", {action:"stoppedTyping"}, function(data){
   lastKeyUp=0;
  });
 }
},1000);

What Happens In The Background ?

Each second, the lastKeyUp variable will increase by 1. If the message submit field value is not null and the lastKeyUp variable is more than 5, then we can make a conclusion that user is not typing. We send our conclusion to typeStatus.php saying that user is not typing. When the response is received, we make the lastKeyUp variable back to ****.

When a keyup event is fired in the message field, jQuery will send another request saying that the user is typing to the typeStatus.php file.

If typeStatus.php got the action field with the value “startedTyping”, then PHP will insert a new row with values as below :

name     - User's Name
what     - $_POST['action']
inserted - NOW() function in MySQL

As you know already that jQuery sends a request to users.php file every 5 seconds, users’ typing status will automatically be displayed in the users table. Here is how the users.php make the text according to the data received from the database table :

$sql=$dbh->prepare("SELECT what FROM typeStatus WHERE name=?");
$sql->execute(array($name));
if($sql->rowCount()!=0){
 $action=str_replace("startedTyping", "Typing...", str_replace("stoppedTyping", "Stopped Typing", $sql2->fetchColumn()));
 echo "<div class='status'>$action</div>";
}

$name is the name of the online user. It replaces “startedTyping” to “Typing…” and “stoppedTyping” to “Stopped Typing”.

Also, records in the typeStatus table with `what` value as “stoppedTyping” will be removed if the inserted time is less than 30 seconds of the current time to prevent the overflowing of the table data.**

**

And that’s how it works ! Hope you liked it and there may be flaws in the post and if you see one, please comment out. If you have suggestions / problems, post in the comments and I’ll be happy to help.