Categories


Loading feed
Loading feed
Loading feed

AJAX Chat Tutorial Part 3:Storage Medium, XML and the Message Process


The Storage Medium

As our chat application gathers pace we return to the server side of the application. At this point we have setup the Zend Framework with an IndexController class to handle server requests. After the initial loading of our HTML interface, we will expect all further server requests to be issued via AJAX (courtesy of Prototype and the XMLHttpRequest object) on the client side. We'll see this in Part 5.

It's important to note that using AJAX requires no additional changes to the current design of our application on the server side. As usual our server side code will receive HTTP requests containing user data which will need to be filtered and validated - just another typical request. We should keep in mind that because requests are being made automatically by Javascript code in the client browser, the data contained in such requests is still user data, i.e. it must be filtered/validated server side.

When we receive a new chat message from the user, we will need to store it. For this tutorial I've selected a file based solution using XML. With the release of PHP 5.1.3 manipulating (and not simply reading) XML documents has never been easier. The improved SimpleXML extension is no longer restricted to reading an XML document, it can now also make additions to the document without forcing a developer to resort to the complexity of the DOM extension.

Storing Messages Using XML

To handle new chat messages we will require an additional Action method on the controller. Also we'll need a way of storing these messages. To keep things simple, we'll forgo using a database and resort to storing messages in an XML file. This will keep things simple. In a more complex heavy duty implementation a database might make more sense and nothing stops readers from doing so once they've finished the tutorial :). In fact MySQL4.1+ comes with a MEMORY (formerly HEAP) storage engine which might be useful for ultra-fast temporary storage.

Handling XML with PHP has never been simpler. If you're one of those people who've always viewed XML as a complicated messy format then you're about to be pleasantly surprised. Each new chat message requires storage of three pieces of data. The message text, the author's screen name, and the timestamp. A sample XML file containing this data would be:


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<chat>
    <message>
        <timestamp>1161790302</timestamp>
        <author>Maugrim</author>
        <text>Hello World!</text>
    </message>
</chat>

What makes using SimpleXML so simple is that the XML document can be navigated in a similar way to a multidimensional array. Each new node has a numeric index, much as each element in an array does. The only difference is the object oriented access.

Save the above file to ./data/chat.xml and read the quick SimpleXML introduction below.

A Brief SimpleXML Introduction

To introduce SimpleXML we'll play around with the XML above to see how it works. If you are already familiar with SimpleXML, feel free to skip ahead. To start we read the XML file into a SimpleXMLElement object using: php


$xml = simplexml_load_file('./data/chat.xml');

This assumes the XML was stored to the chat.xml file in our chat-tutorial/data directory.

The $xml variable now holds a SimpleXMLElement object. This offers an object oriented interface (similar to an array) to the data contained in the XML file. The contents in this case includes everything enclosed within the parent root element <chat> tags. To print the first message in the form


Date: XXX Author: XXX Message: XXX
we use:


$xml = simplexml_load_file('./data/chat.xml');
 
/*
 * First element is indexed as 0, second as 1, etc.
 * Just like an array!
 */
$timestamp = $xml->message[0]->timestamp;
$author = $xml->message[0]->author;
$text = $xml->message[0]->text;
 
echo 'Date: ', date($timestamp), ' Author: ', $author, ' Message: ', $text, '
;

This will echo the first message in the format we wish. The actual timestamp, author and text values we passed to the echo construct are not actually strings. However the act of echoing them means PHP will treat them as a string - see more about the reserved __toSting() method SimpleXMLElement implements. If we need to use these values as strings without echoing them we would need to manually cast them to String first.

To print all messages we can iterate through all the message elements selecting each of the timestamp, author and text elements (and their values):


$xml = simplexml_load_file('./data/chat.xml');
 
foreach($xml->message as $message)
{
    $timestamp = $message->timestamp;
    $author = $message->author;
    $text = $message->text;
    echo 'Date: ', date($timestamp), ' Author: ', $author, ' Message: ', $text, '<br />';
}

If all we want is an array of all text elements we can use the built-in XPATH support to fetch them.


$xml = simplexml_load_file('./data/chat.xml');
 
foreach( $xml->xpath('//text') as $text)
{
    echo $text, '<br />';
}

For our purposes one query we'd like to make is to select all message elements whose timestamp value is greater than a certain "last refresh" value. As you can guess each user will refresh at a certain time. We'll need to update the chat pane in our HTML for messages posted after the this last refresh time to keep the user up to date on the ongoing chat conversation. We can do this using XPATH too! php


$xml = simplexml_load_file('./data/chat.xml');
 
$lastRefresh = '1161790302';
 
/*
* Select all message elements with a timestamp greater than 1161790302
* i.e. XPATH "/chat/message[timestamp>1161790302]"
*/
$newMessages = $xml->xpath('/chat/message[timestamp>' . $lastRefresh . ']');
 
foreach($newMessages as $message)
{
    $timestamp = $message->timestamp;
    $author = $message->author;
    $text = $message->text;
    echo 'Date: ', date($timestamp), ' Author: ', $author, ' Message: ', $text, '<br />';
}

Applying XML Storage

As you can see, XML makes for a viable alternative storage medium where we don't require a database. It's not without flaws of course. As the file grows it will take more time and memory to process, file locking may become an issue, etc. For the purposes of our lightweight chat application tutorial however, it does the job.

With SimpleXML we may have another concern. SimpleXML is currently the easiest way of both reading and writing XML documents. However prior to PHP 5.1.3, writing XML documents was far more complex and required using the DOM extension. Make sure you're using PHP 5.1.3 or above!

The New Message Process

Before we dig into the PHP and Javascript composing our chat application let's take a small step back and keep our goal in mind. What we require to occur for a user's new message can be described in a few steps:

  1. User types a new message and submits it
  2. Prototype creates an AJAX request and sends the message details to the server
  3. Zend Framework routes the request to the IndexController
  4. The IndexController validates the message and stores it to the XML storage file
  5. IndexController fetches all new messages since the user's last refresh
  6. The messages are sent back to the browser
  7. The response is handled by a Javascript function and Prototype to update the chat pane
  8. Important! The page does not reload :)

Comments