Introduction
Webchat is now the most used medium of communication on the internet since the death of the Messengers (or are Yahoo! Messenger and Google Talk still alive?). Various social networks, customer care websites and forums have used this technology to grow, enhance, and increase the efficiency and productivity of their sites and products.
Implementing a webchat from scratch can be very tricky (some don’t even know where and how to start). This article however show how simple a webchat can be built from scratch using PHP and MySQL. This includes
- A signup and login platform
- A real time chat platform
- Offline messaging and retrieval
Minimum Requirements
The basic requirement for this illustration is a HTML5 browser and of course a webserver running PHP and MySQL
The setup (and assumptions)
In favour of brevity and clarity of code, some assumptions were made
- The connection to your webserver and the MySQL server will never fail so no error handler was built into the code
- Just a basic form verification that has to do with the smooth running of the code was included
- The chat time may be +1 hour ahead of time during Daylight saving time because of the use of strtotime() of PHP. Nothing was done to make this return local time
IMPORTANT: And also the codes were written in such a way that the database and tables are generated by the code. All you have to do is to simply supply your MySQL credentials and path to "frame.php" (this is very important else the code might not work) in the "ext.inc" file.
If the project files are in the www directory of your webserver, $iframe_url in "ext.inc" file should be set to "/frame.php". But if the project files are in a folder say, "webchat" inside the www directory, $iframe_url should be set to "/webchat/frame.php"
Database and Tables
The code creates a database "webchat" (if you left the $sql_database_name variable in file "ext.inc" as-is) on your MySQL server and create four tables alongside; "chat", "online", "reg_info", and "archive".
Table: chat and archive
Both tables "chat" and "archive" are identical and consist of seven columns to hold chat information. Table chat holds unread chat while table archive holds old chat which can be retrieved at a future time.
The structure of the table is presented below
chat_id: every message has an id. This enhance easy location in future time.
sender_id: user id of the person sending out the chat
receiver_id: user id of the person receiving the chat
content: the content of the chat
time: the time of the chat
status: if the chat has been received or not. Default to ‘Not Read’. This help in knowing chats to archive.
mime: say you want to enable picture, voice, smiley, etc in your chat, this can server as the MIME for the content of the chat.
(Structure of the table chat)
Table: online
Table online consist of 2 columns to monitor who is online; "id" and "time". You can read my article Getting numbers of users online and other functionalities to have a deeper knowledge of how online users are monitored. Basically, this table gets updated at an interval of time from the client side so as to know who is online.
id: user id of registered user
time: the last time the user was seen (basically the last time the row was updated from the client side)
Table: reg_info
Table reg_info contains four columns which holds registration information about the user.
id: user id of the user. Automatically generated by the MySQL server (auto_increment)
username: the username of the user. Most be unique.
displayname: the name to display during chat session
password: password. crypt()’ed, remember crypt() your password don’t md5() them.
(Structure of the reg_info table)
The code and explanation
The signup and login platform
Both signup and login platform is just a normal form submission, no big deal. But remember, it was only a little form verification that was built in so this should not be used in real time. The user id is automatically generated at signup using AUTO_INCREMENT of MySQL.
The Real Time Chat platform
Chat literally require the sending to and fetching of messages from a server. Various new technology was considered for this but old AJAX won the battle.
Why SSE (Server Sent Event) was not used
SSE is a new push technology that comes with HTML5. It was best suited for the job only that IE does not support it (at least not yet). You can use this if you are certain none of your client will be using IE.
Why Websocket was not used
Websocket maybe the most powerful of all push technology but remember you must have a server that support the websocket protocol (ws://) before you can use it. And besides it is just on the prototype level in IE10 (just a plugin).
AJAX was chosen because you don’t have to reconfigure your server (which you may not even have access to) and it is supported by all browsers (at least the ones I know).
The chat algorithm
List of online users
The list of online users is generated by using the algorithm discussed in the article Getting numbers of users online and other functionalities which is basically letting the client-side (browser) update a database table (in this case table "online") on the server at an interval of time and getting the last instance of time a row was updated to know if the user that owns the row is online or not.
(List of online user)
iframes were used to hold each chat sessions. The iframes are generated on the fly by function addNew() when any of these events occur; clicking on an online user, receiving an offline message or when an online user (whose iframe as not been created) send you a message.
.
.
.
function addNew(oid)
{
if(!document.getElementById("iPan" + oid ))
{
var r = document.createElement('div');
r.id = "c" + oid;
r.className = "iFrmPad";
r.draggable = "true";
r.innerHTML = "<div style="background: rgb(0, 0, 255); padding: 3px; height: 20px; color: rgb(255, 255, 255); font-size: 20px;">" + arguments[1] + " </div>";
r.innerHTML += "<iframe class='iFrm' src='?oid=" + oid + "' id='iPan" + oid + "' style='border:0'></iframe>";
r.innerHTML += "<input class=input placeholder='Gotta say that' type=text id='chatInput" + oid + "'>";
r.innerHTML += "<input title='Say It' type=button value='Go' onclick=sendMsg('" + oid + "'); >";
anchor = document.getElementById("anchor");
document.body.insertBefore(r, anchor);
}
}
.
.
.
The parent document (mpage.php) and the iframe communicate using the postMessage() and addEventListener() of HTML5. The user id of the other party is embedded in the id of the iframe, the input field and the send button (Go button).
The send algorithm
On pressing of the send button (Go button)
- The sendMsg() function is called with the user id of the client to receive the chat as it parameter.
- sendMsg() simply grab the chat from the input field using the user id the send the chat to the server alongside the sender and receiver user id (your id and the other party’s id) using AJAX
- The server stores the chat in table chat and notifies AJAX it got the message by sending back a JSON containing the user id of the sender, the displayname, the content of the chat, and the time of the chat
- sendMsg() evaluate the JSON and forward the necessary data to revMsg() setting the input field of the chat to empty
- revMsg() wrap the received information into HTML and send it to the appropriate ifarme (using the sender id received in the argument to locate the iframe, remember the user id is embedded in the id of the iframes) using pstMessage() of HTML5.
- The iframe receive the message via addEventListener() also of HTML5, check to ascertain the origin of the message (very important to prevent unauthorized access to your site) and display the message
.
.
.
function sendMsg(id)
{
msg = document.getElementById("chatInput" + id).value;
i = new XMLHttpRequest();
urli = "backend.php?send&uid=" + document.getElementById('uid').value + "&oid=" + id + "&msg=" + msg;
i.open("POST", urli, true);
i.onreadystatechange=function()
{
if(i.readyState==4 && i.status==200)
{
rex = eval("(" + i.responseText + ")");
revMsg(rex.id, rex.displayname, rex.content, rex.time);
document.getElementById("chatInput" + id).value = "";
}
}
i.send();
}
function revMsg(oid, displayname, content, time)
{
o = document.getElementById('iPan' + oid);
sty = "background:#aabb00; width:95%; float:right; margin-top:3px;";
if(arguments[4] == 1)sty = "background:#ffcc00; width:95%; float:left; margin-top:3px;";
details = "<div>" + displayname + " " + content + " " + time + "</div>";
if(o == null)
{
addNew(oid, displayname);
return;
}
o.contentWindow.document.getElementById("chatPan");
o.contentWindow.postMessage(details,'');
}
.
.
.
The receiving algorithm
From the iframe, AJAX is used to ping the server every 5 seconds for new message
- pingServer() send the user id to the server
- The server scans for chats in table chat with receiver_id equal to the user id and status equal to ‘Not Read’
- The server respond with found results in JSON
- Server marks all results as ‘Read’ i.e. change status colum from ‘Not Read’ to ‘Read’ and move all the results to table ‘archive’
- pingServer receive the JSON, evaluate it and send the necessary data to revMsg()
- Step 5 – step 6 of “the sending algorithm” is performed.
pingServer() was made to run from the iframe rather than from the parent document so as to ensure the DOM of the iframe is fully loaded before trying to access it.
.
.
.
function pingServer()
{
j = new XMLHttpRequest();
urlj = "backend.php?ping&uid=" + + "&oid=" + ;
j.open("POST", urlj, true);
j.onreadystatechange=function()
{
if(j.readyState==4 && j.status==200)
{
var er = eval("(" + j.responseText + ")");
counter = er.a0;
while(counter > 0)
{
x = er['a' + counter];
parent.revMsg(x.id, x.displayname, x.content, x.time, 1);
counter--;
}
}
}
j.send();
}
setInterval(pingServer, 5000);
.
.
.
(Chat Session)
Offline messaging and retrieval
Offline messaging has no extra code or concept. You can message anyone weather online or not. Offline message retrieval is made possible by function scanner which signal to the server to scan for chats with ‘Not Read’ status in the table ‘chat’. The server respond with list of user id, scanner() call addNew() to create their iframe and “The receiving algorithm” kicks off. This works for offline messages and messages initiated by the other party
.
.
.
function scanner()
{
x = new XMLHttpRequest();
urlx = "backend.php?scan&uid=" + ;
x.open("POST", urlx, true);
x.onreadystatechange=function()
{
if(x.readyState==4 && x.status==200)
{
erx = eval( "(" + x.responseText + ")" );
counter = erx.a0;
while(counter > 0)
{
r = erx['a' + counter];
addNew(r.id, r.displayname);
counter--;
}
}
}
x.send();
}
setInterval(scanner, 5000);
.
.
.
Further Development
This can further be developed to encompass
- Indication when other party is typing
- Alert on retrieval of new message when user is away from browser
- Change status of user to away mode where user has been long away from browser
- Loading of earlier messages from archive
- Smiley