Wednesday, August 20, 2008

Creating a chat script with PHP and Ajax

Introduction

In this multi-part tutorial series I will show you how to create your own chat script with PHP and Ajax. You've probably heard of Ajax before, and what it exactly is, but in case you haven't, read the following two tutorials to learn more about Ajax: "Mastering Ajax, Part 1: Introduction to Ajax" and "Getting started with Ajax".


Another JavaScript library we'll be using is the Prototype library, which includes many useful JavaScript functions and comes with inbuilt Ajax support. If you want to know more about this library, have a look at the following tutorial: "Using prototype.js v1.3.1".


In this first part of the series I will show you how to create a really basic chat script, and nothing more. In the next parts we'll be adding more features, eventually creating a really robust and powerful chat script.


How it works


Our chat script will consist of two parts: a server and a client.


The client is used by your visitors, and doesn't contain any PHP at all. The client must do all the data sending. Every time the user wants to send a new message, the client must send this data (using Ajax) to the server. The client must also check for new messages on the server, again using an Ajax request.


The server only has to add a new message or send a list of messages to the client, and it doesn't have to use any HTML or JavaScript at all. It's strictly PHP. I've added a simple diagram below to show what I've just







Creating the server


Let's start by creating the server, but first, create a new datebase to hold the messages of your chat script, with the following database scheme:



CREATE TABLE `message` (

`messageid` int(5) NOT NULL AUTO_INCREMENT,

`user` varchar(255) NOT NULL DEFAULT '',

`message` text NOT NULL,

`datetimestamp` int(11) NOT NULL DEFAULT '0',

PRIMARY KEY (`messageid`)

) TYPE=MyISAM AUTO_INCREMENT=1 ;



The first thing the server must do is check what the client wants: adding a new message or requesting latest messages? The following code does what we want:



if (!isset($_GET['action'])) {

die('This chat server can only be used by the chat client.');

}

$action = $_GET['action'];

if ($action != 'get' AND $action != 'add') { $action = 'get'; }


// Do we want to get chat messages or add a new message?

if ($action == 'get') {

// Get messages

send_messages();

} else {

// Add a new message

add_message();

}



As you can see we're going to use two different functions: send_messages() to return all the latest messages and add_message() to add a new message.


Adding a new message is quite simple, and it only requires some standard database code, like this:


function add_message() {

global $db;

// Everything there?

if (!isset($_GET['user'])) {

die('error:no-user');

}



if (!isset($_GET['message'])) {

die('error:no-message');

}


$user = ss(htmlentities(strip_tags($_GET['user'])));

$message = ss(htmlentities(strip_tags($_GET['message'])));

$datetimestamp = time();


// Insert message

$db->query ("INSERT INTO message (user, message, datetimestamp) VALUES ('$user', '$message', $datetimestamp)");


// Return any new message

send_messages();

}



The function first checks if both variables are there, and if they're not, it returns an error. The errors look a bit weird, but this format actually makes it easier for our client (you'll see why later). When everything is okay, the message is inserted into the database.


The send_messages() function has to send the messages that have NOT yet been received by the client. To do this, the client sends the timestamp of the last received message, from which the server can automatically select the messages that haven't been received yet, like so:


function send_messages() {

global $db;

// Is there a latest timestamp?

if (!isset($_GET['latest'])) {

$latest = false;

} else {

$latest = intval($_GET['latest']);

}


// If there isn't a latest, get the five newest messages, and return them

if ($latest == false) {

$messages = $db->sql_query ("SELECT user, message, datetimestamp FROM message ORDER BY datetimestamp DESC LIMIT 0,4");

} else {

$messages = $db->sql_query ("SELECT user, message, datetimestamp FROM message WHERE datetimestamp > $latest ORDER BY datetimestamp DESC LIMIT 0,9");

}


// Any messages?

if ($messages == false) {

die('no-messages');

}


// Get newest timestamp

$newest = $messages['0']['datetimestamp'];


// Reverse array for correct order

$messages = array_reverse($messages);


// Return response

$response = $newest;


foreach ($messages as $message) {

$response .= $message['user'] . '>' . $message['message'] . "\n";

}


$response = trim($response);


die($response);

}



This code first selects the right messages, and after that returns it in the right format (each message is separated by a newline, and the user and message are separated by >).


Creating the client




You can close your PHP editor now, and switch to your HTML/JS editor, as we'll only be using HTML and JavaScript from now on.


First of all, the client page itself. It's nothing advanced, and very simple:


<html>

<head>

<title>Ajax Chat Client</title>

<script type="text/javascript" src="../prototype.js"></script>

<script type="text/javascript" src="script.js"></script>


<link REL="stylesheet" HREF="../style.css" TYPE="text/css" media="all">


</head>


<body><div id="container">

<h1>Ajax Chat Client</h1>


<div id="login">

<p>Please enter an username: </p>

<input type="text" name="user" id="user" />

<input type="button" onclick="login();" value="Enter Chatroom" />

</div>


<div id="chatelements" style="display:none;">

<textarea id="chat" rows="20"></textarea>

<input type="text" id="message"><input type="button" onclick="send_message();" value="Send" />

</div>



<div id="debug">

</div>


<div id="copyright">

This is a demo of an article series on <a href="http://www.phpit.net">PHPit</a>.

Copyright &copy; 2006 Dennis Pallett.

</div>

</div></body>

</html>



It has three important elements: the login div, which shows a login box when first viewing the page, a textarea, which is used to show all the chat messages, and a text field which is used to enter new messages.


If you have a close look at the HTML above, you'll notice two different JS functions: login() and send_message(). These are defined in the script.js file, and are the most important of our chat script.


The login() function is used to set a user's username, and getting the initial messages. It looks like this:


var server = 'http://projects/phpit/content/creating%20an%20ajax-based%20chat/demos/1/chatserver.php';

var username = '';

var latest = '';

function login() {

// Get username

var user = $F('user');


if (user == '') {

alert('Please enter a username before entering the chat room');

return false;

}


username = user;


// Show chat

Element.hide('login');

Element.show('chatelements');


$('chat').value = '';

$('message').value = '';


// Begin getting messages

get_messages();

checker = new PeriodicalExecuter(get_messages, 2);

}



The first part of the function checks the username. If everything is okay, the chat elements are shown, and the latest messages are retrieved using the get_messages() function. The function also creates a new object, called the PeriodicalExecuter, which is used to check for new messages every 2 seconds.


The get_messages() function is used to retrieve new functions using an Ajax request, like so:


function get_messages() {

var args = 'action=get&latest=' + latest;

var do_ajax = new Ajax.Request(server, {method: 'get', parameters: args, onComplete: handle_response});

}

The above code uses the Ajax object (included with the Prototype library) to send a new GET request to the server with two arguments: action and the timestamp of the latest message received. As you can see, the onComplete parameter has been set to handle_response, which means that when the Ajax request is done, the response will be sent to a function called handle_response().


The handle_response() function actually checks the response, and decides what to do. Remember the responses that we gave in the server? We're going to use that now, like so:


function handle_response(request) {

var response = request.responseText;

// Error?

if (response == 'error:no-user') {

// No username, show login again

alert('It appears you aren\'t logged in any longer. Please login again');

Element.show('login');

Element.hide('chatelements');

return false;

}

if (response == 'error:no-message') {

// No username, show login again

alert('You didn\'t send any message. Please try again');

return false;

}

if (response == 'no-messages'){

// There are no new messages

return false;

}


// We're getting a valid response, first get the latest timestamp

latest = response.substring(0, 10);


// Now get the messages

messages = response.substring(10, response.length);


// Split messages

messages = messages.split('\n');


// Add each message

var chat = $('chat');

for (var i=0; i < messages.length; i++) {

var message = messages[i].split(">");



chat.value = chat.value + '\n';

chat.value = chat.value + message[0] + ': ' + message[1];

}

}



This function first checks whether any errors have been returned. This only happens when a message has been sent (and not when receiving messages). After that it checks whether there are any messages.


If there are new messages, it parses the new messages (using some standard string functions), and then adds the new messages to the chat area.


And that's all there is to it. We've now got an almost working chat script. All that's left is to write the send_message() function.





No comments: