An Introduction to AJAX

In the first part of this series, we took a look at how PHP 5 can be used to manipulate and parse XML files. In this installment, we are going to focus on Ajax, one of the most useful and topical applications of XML.
Initially, we are going to introduce Ajax and learn how to use the XMLHTTP object provided by most modern web browsers to create a live email validation form. Then we will pick up where we left off with the theme of XML and introduce XSLT, which we will use to transform our library XML from the previous article into valid XHTML code.

What is AJAX?

There exists today a huge number of web applications that do everything from manage your photos, to mission-critical distributed systems. The majority of these applications exist in three parts.
In most web applications, the invocation of logic on the middle ware, which may or may not change the information presented to the user, requires that the user click a link or submit data via a form. This in turn requires that the entire page be refreshed and all data be resent to the user. This is OK when a large portion of the page is being refreshed, but it is very wasteful if little or no data is to be updated.

Traditional Web Application

The philosophy behind Ajax is that when a user makes a request to the server-side part of the application, only the data which is required is sent back to the user and rather than reloading the entire page, only the parts which require updating are updated.
Ajax is an acronym for Asynchronous Javascript And XML. It is the use of Javascript code in HTML pages that allows it to make independent requests to the web server. XML is by no means mandatory in an Ajax solution and, in some cases it is completely unnecessary. With Ajax, the front end is split into two parts: the HTML and CSS which deals with the page display and the Ajax engine.

Ajax Application

The Ajax engine is responsible for initiating two way communication with the server in response to user events on the page. It enables developers to enrich and enhance the usability of web applications by creating powerful event driven web front ends, similar to the kind that we are accustomed to on the desktop domain, which respond in almost real time.
You can see a more detailed definition of Ajax and how it fits into the the web design domain, by reading Chapter 1 of the Ajax in Action.
Live E-Mail Validation with AJAX
We are now going to dive into the world of AJAX by creating a simple application which validates and verifies a user's email address while they are filling out a web form. A prior knowledge of HTML and Javascript is beneficial when following this article, however there is no better way of learning than to manually copy (not copy and paste) and implement the solution yourself.
Normally, email validation and verification is carried out by the server. It often involves a syntax check and the sending of an email containing a link and verification code, which, once clicked, confirms that the email is real and active.
Our small application will do all of this before the form is submitted, or more precisely, while it is being filled out. This kind of feature is especially useful if the form takes several minutes to complete and it can also be extended to include a randomly generated image in place of a plain text code in the verification.
To assist in the creation of our small AJAX application, I have created an Email Validation class, email_validator.php which provides the tools necessary to validate and verify an email address. It uses a SqLite database to store email addresses which are to be verified and provides the necessary methods to check the syntax of the email, validate domain part of the email and sends a randomly generated verification code the email address.
The source code for this class and the documentation can be downloaded in this ZIP file.
Coding for AJAX
It is worth remembering that when introducing or including Ajax in web applications, the coding becomes more complex.

The Server-Side PHP

Our Ajax engine's partner in crime will be a small PHP script called email_validate.php. It receives the data from the Ajax engine, processes it by carrying out the required action and sends a plain text response.

Validating the Data

The data from the Ajax engine will be passed to our script in the URL query string. The three values which are sent are as follows:


PHP:
/* get the action */
$action = @$_GET['action'];

if (isset(
$_GET['id'])) {
    /* the user has already made a request and been given an email ID */
    
try {
        
$email = new EmailValidator((int)$_GET['id']);
        
        if (isset(
$_GET['email'])) {
       
    /* a new email has been sent, so we must re-validate */
       
    $email->setEmail($_GET['email']);
            
$action = 'validate';
        }
    } catch (
EmailValidatorException $e) {
        if (isset(
$_GET['email'])) {
            
/* the ID was invalid, but we have been sent an email address */
            
$email = new EmailValidator($_GET['email']);
            
$action = 'validate';
        } else {
            
/* an invalid ID was specified and no email address was given - we cannot do much */
            
$action = 'invalid';
        }
    } catch (
Exception $e) {
        
$action = 'unknownerror';
    }
} else if (isset(
$_GET['email'])) {
    try {
        
/* load the new email into the validator */
        
$email = new EmailValidator($_GET['email']);
    } catch (
Exception $e) {
        
$action = 'unknownerror';
    }
} else {
    
/* no action sent – we cannot do much */
    
$action = 'invalid';
}
 

Notice how we have overridden the action variable to re-validate the email address if an email address is sent as well as an ID (indicating that it has changed). We also override the action variable if an error occurs when attempting to create an instance of the EmailValidator object.

Processing the Data
We use a switch statement on the action variable to carry out the required action and get a true or false response. This is stored in a variable called $ret which we return to the Ajax application to indicate success or failure.
PHP:   
$data = '';
switch ($action) {
    case 'validate':    
        $ret = validate_email($email);
        $data = (string) $email->getId();
        break;
    case 'verify':
        try {
            $ret = $email->verify(@$_GET['v_code']);
        } catch (EmailValidatorException $e) {
            /* the email has not been validated - validate it now */
            $action = 'validate';
            $ret = validate_email($email);
        }
            
        $data = (string) $email->getId();
        break;
    case 'unknownerror':
        $ret = 0;
        break;
    default:
        //fail
        $action = 'invalid';
        $ret = 0;
}

function validate_email(EmailValidator $email)
{
    /* validate the email */
    if(! $email->validate()) {
        return false;
    }
        
    $email->save(); // save it to the database
    $email->sendVerificationEmail(); // send the verification email

    return true;
}

Again, notice how we modify the action variable and instead validate the email address if verification fails. If the email turns out to be valid, the sendVerificationEmail method is called. This causes the EmailValidator to generate a random 5 character verification code and send it in an email to the supplied email address.
Returning a Response
The response sent back to the Ajax engine is not like a normal response which is sent as HTML. We return the response as plain text in the form of a semi-colon delimited string containing three fields:
status;data;context

    * status – set to 1 if the request was successful and 0 if the request was unsuccessful
    * data – this contains the email ID generated by the EmailValidator class
    * context – this is set to the value of the action variable. It is usually the same as value passed by the Ajax engine but may change if the email has been revalidated or an error occurred. The context is used by the Ajax engine to decide how to respond.

We generate the response by joining the $ret, $data and $action variables together with semi-colons.

PHP:
 /* send the response as plain text */
header('Content-Type: text/plain');
echo((int) $ret . ';' . $data . ';' . $action);

The HTML Code
The HTML code itself contains only a link to the script containing the Ajax engine. This ensures that the script is only downloaded if the browser supports Javascript. The HTML code itself produces a fully functioning HTML form which does not require Ajax. If Ajax is not enabled the script receiving the form data will process and validate the email address normally.
HTML:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
            <title>Ajax Email Validation</title>
            <script src="ajax_validation_engine.js" type="text/javascript"></script>
        </head>
        <body onload="init();">
            <h1>AJAX Email Validation</h1>
                <p>The form below demonstrates how to use AJAX
                to validate an email while the user is filling out a form. Fill in
                the form below for a demo:</p>
            <div>
                <form id="formEmail" action="input.php" method="post">
                <div>
                    <div id="emailMsg" style="display:none"></div>
                    <label for="txtEmail">Email Address: </label>
                    <input type="text" id="txtEmail" name="email" />
                    <span id="verify" style="display: none"><br />
                        <span id="verifyMsg"></span><br />
                        <label for="txtVerify">Verification Code: </label>
                        <input id="txtVerify" type="text" name="v_code" />
                        <input type="hidden" name="email_id" value="" />
                        <button id="btnVerify" onclick="verifyAddress(); return false;">Verify</button>
                    </span>
                </div>
                <div>
                    <label for="txtFirstName">First Name: </label>
                    <input type="text" id="txtFirstName" name="fname" />
                </div>
                <div>
                    <label for="txtLastName">Last Name: </label>
                    <input id="txtLastName" type="text" name="sname" />
                </div>
                <p>A Little about yourself:<br /><textarea cols="20" rows="10" name="bio"></textarea></p>
                <p><input id="btnSubmit" type="submit" /></p>
            </form>
        </div>
    </body>
</html>

The Ajax Engine
The Ajax engine responds to events in the user interface and initializes communication with the server-side script. It also responds to the return data from the server-side script and takes the appropriate action based on the response.
Creating an instance of the XMLHTTP Object
The method used to create an instance of the XMLHTTP object depends on the browser being used. While Firefox and Netscape expose the XMLHttpRequest object, Internet Explorer exposes several different versions of the MSXML ActiveX control that depends on the version of Internet Explorer that is being used. The getXMLHTTP function determines which method is supported (if any) and creates an instance of the appropriate object. If it fails, it returns false.
Javascript:

function getXMLHTTP()
{
    if ((typeof XMLHttpRequest) != "undefined") {
        /* XMLHTTPRequest present, use that */
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        /*  there are several versions of IE's Active X control, use the most recent one available */
        var xmlVersions = ["MSXML2.XMLHttp.5.0",
                           "MSXML2.XMLHttp.4.0",
                           "MSXML2.XMLHttp.3.0",
                           "MSXML2.XMLHttp",
                           "Microsoft.XMLHTTP"];

        for (var x = 0; x < xmlVersions.length; x++) {
            try {
                var xmlHTTP = new ActiveXObject(xmlVersions[x]);
                return xmlHTTP;     
            } catch (e) {
                //continue looping
            }
        }
    }

    /* if none of that worked, return false, to indicate failure */
    return false;
}
Initializing the Environment
The HTML page which contains the form loads originally without any Javascript. This ensures that it is fully functional without Ajax. The init function initializes the Ajax environment by creating an instance of the XMLHTTP object and setting up all of the global variables. Most importantly, if we cannot create an XMLHTTP object, we exit the function and allow the user to continue filling out the form without Ajax. This fall back feature is very important, as the likely result of telling a user that they cannot signup to your site until they enable Javascript will be the user going elsewhere (and not returning).


Javascript:
var xmlHTTP;

var theForm;
var btnSubmit;
var txtEmail;

var verify;
var verifyMsg;
var txtVerify;
var btnVerify;

var emailMsg;

var emailValidate;

function init()
{
    /* close the document output*/
    document.close();

    xmlHTTP = getXMLHTTP();


    if (! xmlHTTP) {
        /* do not continue if XML HTTP is not available */
        return;
    }

    /* initialize global variables */
    theForm = document.getElementById('formEmail');
    btnSubmit = document.getElementById('btnSubmit');
    txtEmail =  document.getElementById('txtEmail')
    verify =  document.getElementById('verify')
    verifyMsg =  document.getElementById('verifyMsg');
    txtVerify =  document.getElementById('txtVerify');
    btnVerify = document.getElementById('btnVerify');
    emailMsg =  document.getElementById('emailMsg');
    emailValidate = 'email_validate.php?action=';
    
    /* disable the submit button */
    btnSubmit.setAttribute('disabled', 'disabled');
    
    txtEmail = document.getElementById('txtEmail');

    /* set the onchange event of the email input box to the validateAddress() function */
    txtEmail.onchange = validateAddress;
}

Sending a Request
To send an HTTP request using the XMLHTTP object, we need to first call the open function with three parameters:
XmlHTTP.open(method, uri, async);

    * method – this should be either  'get' or 'post'. For a get request, data to be passed to the script is appended to the URI using a query string in the form: uri.php?var1=value1&var2=value2. For a post request, the data is passed to the script in the HTTP request body. We use the uriEncodeComponent function to url encode the data to be sent.
    * uri – the path to the receiving script, relative to the current page (for reasons of security the open method will only open a document  within the same domain as  the current document).
    * async – tells us whether the request should be asynchronous. When set to true, the request for the document is sent and script execution continues immediately. If set to false, the script waits until the response has been fully received. It is advisable in most cases to set this to true, as a slow server could cause the user interface to hang.

To send the request, we need to call the send function. Once a response is received, the responseText property will contain the text sent by the server side script in the HTTP response body. The location at which this property is available is dependent on whether the request was synchronous or asynchronous. With a synchronous request, the script waits for the response before continuing, therefore, the responseText property is available immediately after the the call to send. In contrast, the script does not wait for the response if the request was asynchronous. Instead, the XMLHTTP object fires the onreadystatechange event. Each time the event is fired, the readyState property of the XMLHTTP has changed. A readyState value of 4 signifies that the response has been fully received and the responseText property contains the HTTP response body.
Synchronous Request     
    xmlHTTP.open('get', uri, false);
    xmlHTTP.send(null);

    alert(xmlHTTP.responseText);

Asynchronous Request
    xmlHTTP.open('get', uri, true);
    xmlHTTP.onreadystatechange = function () {
            if(xmlHTTP.readyState == 4) {
                  alert(xmlHTTP.responseText);
            }      
      };
    xmlHTTP.send(null);

A value of null is always supplied as the first argument to the send function in the case of a get request. In a post request, the data is sent in the body of the request--this is done by passing a url-encoded string to the send function instead of null.
Parsing the Response
In our email validation application, we will be using asynchronous requests and assigning a generic function to the onreadystatechange event. This function will parse the response, validate it and use the context supplied by the validation script to call the appropriate function to deal with the response.

Javascript:
function parseResponse()
{
    if (xmlHTTP.readyState != 4) {
        /* the request is not complete */
        return;
    }

    var responseArray = xmlHTTP.responseText.split(';');
    var response = Array();

    if (responseArray.length != 3) {
        /* response is invalid */
        return;
    }
    
    /* load the response into a logical associative array */
    response['status'] = parseInt(responseArray[0]);
    response['data'] = responseArray[1];
    response['context'] = responseArray[2];

    /* decide what to do based on the response context */
    switch(response['context']) {
        case 'validate':
            validateCallback(response);
            break;
        case 'verify':
            verifyCallback(response);
            break;
        case 'invalid':
            // return everything to its original state and start over
            startupState();
            validateAddress();
            break;
        case 'unknownerror':
            // something is wrong - so we are going to fall back
            btnSubmit.removeAttribute('disabled');
            txtEmail.onchange = null;
            verify.style.display = 'none';
            break;
    }
}

This function will be called each time the readstatechange event is fired. Note that the Ajax part of the application is disabled if an unknown error occurs. This ensures that the user can still submit the form if email validation is not functioning. It is important to plan for failure in any application, but more so in Ajax applications. Users have become accustomed to submitting forms and presenting them with an unsubmittable form is likely to cause frustration as the user may not realize that any communication has been made with the server.
Validating the Email Address
Validating the email address is done in two parts. The validateAddress function is assigned to the onchange event handler of the email input box. This event is fired each time a change is made to the contents by the user. The validateAddress function performs the HTTP request and sends the appropriate information such as the email address and the ID in the query string.

Javascript:
function validateAddress()
{
    var email = theForm.email.value;
    var id = parseInt(theForm.email_id.value);

    startupState();

    if (email != '') {
        /* add the email address to the query string */
        var dataString = 'email=' + encodeURIComponent(email);
        
        if (id > 0) {
            /* if an ID is set, add that too */
            dataString += '&id=' + id;
        }

    } else {
        /* no email entered, do nothing */
        return;
    }

    /* send the request */
    xmlHTTP.open('get', emailValidate + 'validate&' + dataString, true);
    xmlHTTP.onreadystatechange = parseResponse;
    xmlHTTP.send(null);
}

function startupState()
{
    verify.style.display = 'none';
    verifyMsg.innerHTML = '';

    txtVerify.removeAttribute('disabled');

    btnVerify.removeAttribute('disabled');
    btnVerify.innerHTML = 'Verify';

    btnSubmit.setAttribute('disabled', 'disabled');

    emailMsg.innerHTML = '';
    theForm.email_id.value = '';
    theForm.v_code.value = '';
}

I mentioned earlier that we are using asynchronous requests. Therefore the second part of the email validation takes place when the response has been received from the server. The validateCallback function is called when the server responds with  a 'validate' context. If validation was successful, the verification box is displayed.

Javascript:
function validateCallback(response)
{

    if (response['status']) {
        /* the email address is valid and a verification email has been sent */
        emailMsg.style.display = 'none';
        
        verify.style.display = 'inline';
        verifyMsg.innerHTML = '<b>An Email containing your verification code has been sent to this address. Please Enter it before continuing.</b>';
        theForm.email_id.value = response['data'];
    } else {
        /* the email address was invalid */
        verify.style.display = 'none';
        emailMsg.innerHTML = '<b>You have entered an invalid email address. Please correct it before continuing.</b>';
        emailMsg.style.display = 'block';
        theForm.email.focus();
    }
}

Verification follows a similar pattern to validation. There is verifyAddress function which is executed when the Verify button is clicked and the verifiyCallback function which is executed when the server responds with a context of 'verify'.

Javascript:
function verifyAddress()
{
    var v_code = theForm.v_code.value;
    var id = theForm.email_id.value;

    if (v_code == '') {
        /* no verification code has been entered */
        alert('No Verification Code Entered');
        theForm.v_code.focus();
        return;
    }

    /* add the verification code to the query string */
    var dataString = 'id=' + encodeURIComponent(id) + '&v_code=' + encodeURIComponent(v_code);

    xmlHTTP.open('get', emailValidate + 'verify&' + dataString, true);
    xmlHTTP.onreadystatechange = parseResponse;
    xmlHTTP.send(null);
}

The verifyCallback function checks for successful verification. If verification succeeded, the verify button's text is changed to “verified”, disabled and the submit button is enabled. It also clears the email input box. This means that when the form is submitted, only the email ID is passed to the receiving script and not the email address. The email ID can then be used by the script which processes the form data to check the address has been verified--if it has, it need not be verified again.

Javascript:
function verifyCallback(response)
{
    var v_code = theForm.v_code.value;
    
    theForm.email_id.value = response['data'];

    if(response['status']) { // successful verification
        btnVerify.setAttribute('disabled', 'disabled');
        txtVerify.setAttribute('disabled', 'disabled');

        btnVerify.innerHTML = '<i>Verified</i>';
        verifyMsg.innerHTML = '';
        
        /* enable the submit button */
        btnSubmit.removeAttribute('disabled');
        
        verifyMsg.innerHTML = '<b><i>' + theForm.email.value + '</i></b>';
        theForm.email.value = '';
    } else {
        verifyMsg.innerHTML = '<b>Verification Failed</b>';
    }
}

Putting it All Together
Congratulations, you now have a working Ajax application which validates emails. You should have the following four files in the same directory:

email_validate.php
email_validator.php
ajax_validation_engine.js
ajax_form.html

Ajax Email Validation

The three files required for this application are also included in the ZIP file.
Extending this Example
To keep the application simple, we have omitted some details which would be advisable to implement in a real world scenario:

    * An extra box field should be included in the form to confirm the email address. Only when both email addresses match, should the Ajax engine send it to the server and validate.
    * The email EmailValidator includes a remove method, which should be used by the script receiving the form data to remove the email address from the database once verification has been confirmed. This will prevent the database from growing to an unsavory size.
    * We have not created the input.php script which receives the form data. If the email address was validated, it will not be sent to the input.php script--instead the email_id variable will be sent. The script can then use the email validator to check whether or not the email has been verified.
    * By default, the EmailValidator creates the SQLite database in the same directory as the running script. For obvious security reasons, you should change the path of the database to one which is inaccessible by the web server.

Sites Which use Ajax
Below is a small taste of the many web sites with applications which use Ajax. This list is likely only to grow. So be one of the first web developers to jump on the Ajax bandwagon!

    * Yahoo News - Hovering over the links to articles produces a small image and synopsis or the news item.
    * Google Suggest - The text typed in the search box is buffered and sent to the Google server at regular intervals, producing a dropdown list of suggested searches.
    * A9 - Amazon-based search engine which, in conjunction with XMLHTTP and IFRAMES, delivers an interfaces which responds instantly to user input, updating search results immediately.
    * Google Mail - The Gmail application again uses a combination of IFRAMES and XMLHTTP to create a sleek responsive interface. Google also uses a pattern known as polling to regularly check the user's email.