This time, we are making a Simple AJAX Commenting System. It will feature a gravatar integration and demonstrate how to achieve effective communication between jQuery and PHP/MySQL with the help of JSON.

Step 1 – XHTML

First, lets take a look at the markup of the comments. This code is generated by PHP in the Comment class, which we are going to take a look at in a moment.

The avatar div contains a hyperlink (if the user entered a valid URL when submitting the comment) and an avatar image, which is fetched from gravatar.com. We will return to this in the PHP step of the tut. Lastly we have the name and time divs, and the comment body.

The other important element in the XHTML part is the comment form. It is sent via POST. All fields except for the URL field are required.

The form is submitted via AJAX. The validation is performed entirely in the backend by submit.php, as you will see in the jQuery step of the tutorial. Every field has a corresponding label element, with an appropriate for attribute.

Simple AJAX Commenting System

Step 2 – PHP

PHP handles the communication with the MySQL database and generates the markup of the comments. It is also on the receiving end of the AJAX requests and inserts the comment data to the comments table. You can see the code that prints the comments to the page below.

The MySQL query selects all the entries from the database and fills the $comments array with objects of the comment class, which you will see below. This array is outputted later in the execution of the script.

demo.php

Each comment has a markup() method, which generates valid HTML code ready to be printed to the page. You can see the definition of this method and the class below.

The class takes a row from the database (fetched with mysql_fetch_assoc() ) and stores it in the private variable $data. It is available only to the methods of the class and cannot be accessed from outside.

This script uses gravatar to present avatars in the comments. For those of you, who have not used gravatar, this is a really useful service, which lets you associate an avatar with your email address. The avatar image can easily be fetched by passing an md5() encoded hash of your email address to gravatar.com. This is exactly what we do on line 48.

Notice line 39 above it – the script tries to figure out the URL at which it is located, and determines the exact address of the default_avatar.gif image. This gif is passed to gravatar along the md5 hash, so if no avatar was found for this particular email, the fallback image is displayed instead.

The validate() method above (also part of the class) is defined as static. This means that it can be evoked directly like Comment::validate(), without the need of creating an object of the class. What this method does, is validate the input data which is submitted via AJAX.

This method uses the new filter functions, which are available as of PHP 5.2.0. These allow us to easily validate and filter any input data that is passed to the script. For example filter_input(INPUT_POST,’url’,FILTER_VALIDATE_URL) means that we are checking whether $_POST['url'] is a valid URL address. If it is, the function returns the value of the variable, otherwise it return false.

This is really useful, as up until now, we had to use custom regular expressions to validate data (and have series of if statements). Also, another advantage is that this data is fetched before any configuration-specific transformations (like magic quotes) are applied.

We also have the option of specifying a custom function which is going to apply some more advanced modifications of the data, as you can see from lines 31 and 37.

comment.class.php – Part 3

private static function validate_text($str)
{
/*
/ This method is used internally as a FILTER_CALLBACK
*/
if(mb_strlen($str,'utf8')<1)
return false;
// Encode all html special characters (<, >, ", & .. etc) and convert
// the new line characters to <br> tags:
$str = nl2br(htmlspecialchars($str));
// Remove the new line characters that are left
$str = str_replace(array(chr(10),chr(13)),'',$str);
return $str;
}
}

The last method is validate_text, which we are passing as a callback function in the two filter_input calls above. It encodes all special HTML characters, effectively blocking XSS attacks. It also replaces the newline characters with <br /> line breaks.

submit.php

/*
/ This array is going to be populated with either
/ the data that was sent to the script, or the
/ error messages:
/*/
$arr = array();
$validates = Comment::validate($arr);
if($validates)
{
/* Everything is OK, insert to database: */
mysql_query(" INSERT INTO comments(name,url,email,body)
VALUES (
'".$arr['name']."',
'".$arr['url']."',
'".$arr['email']."',
'".$arr['body']."'
)");
$arr['dt'] = date('r',time());
$arr['id'] = mysql_insert_id();
/*
/ The data in $arr is escaped for the mysql insert query,
/ but we need the unescaped text, so we apply,
/ stripslashes to all the elements in the array:
/*/
$arr = array_map('stripslashes',$arr);
$insertedComment = new Comment($arr);
/* Outputting the markup of the just-inserted comment: */
echo json_encode(array('status'=>1,'html'=>$insertedComment->markup()));
}
else
{
/* Outputting the error messages */
echo '{"status":0,"errors":'.json_encode($arr).'}';
}

submit.php receives the comment form data via an AJAX request. It validates it and outputs a JSON object with either the XHTML markup of the successfully inserted comment, or a list of error messages. jQuery uses the status property to determine whether to display the error messages or add the comment markup to the page.

You can see two example responses below.

Successful response

{
'status': 1,
'html': 'Html Code Of The Comment Comes Here...'
}

The html property contains the code of the comment, similar to markup in step one.

The .comment divs and the #addCommentContainer are styled at once because they share most of the styling. A number of CSS3 rules are applied, including rounded corners and a box-shadow. Needless to say, these do not work in older browsers, but as they are purely presentational, the script will still work without them.

In the second part of the stylesheet, we style the comment and form elements. Notice the input[type=text] selector, which selects elements depending on the type attribute.

Step 4 – jQuery

Now lets continue with jQuery, which is the last step of this tutorial. After including the library to the bottom of the page (best for the perceived performance of the page) we can start coding the script file.

script.js

$(document).ready(function(){
/* The following code is executed once the DOM is loaded */
/* This flag will prevent multiple comment submits: */
var working = false;
/* Listening for the submit event of the form: */
$('#addCommentForm').submit(function(e){
e.preventDefault();
if(working) return false;
working = true;
$('#submit').val('Working..');
$('span.error').remove();
/* Sending the form fileds to submit.php: */
$.post('submit.php',$(this).serialize(),function(msg){
working = false;
$('#submit').val('Submit');
if(msg.status){
/*
/ If the insert was successful, add the comment
/ below the last one on the page with a slideDown effect
/*/
$(msg.html).hide().insertAfter('.comment:last').slideDown();
$('#body').val('');
}
else {
/*
/ If there were errors, loop through the
/ msg.errors object and display them on the page
/*/
$.each(msg.errors,function(k,v){
$('label[for='+k+']').append('<span class="error">'+
v+'</span>');
});
}
},'json');
});
});

Starting from the top, we have the $(document).ready() call, which binds a function to the DOM content loaded event. The working variable acts as a flag, which tells the script if an AJAX request is in progress (thus preventing double posting).

In the callback function for the POST AJAX request, we check the status property to determine whether the comment was successfully inserted. If it was, we add the received markup to the page after the last comment with a slideDown animation.

If there were problems, we display the error messages by appending an error span to the appropriate label element (the for attribute of the label contains the id of the input that caused the error).

With this our Simple AJAX Commenting System is complete!

Conclusion

To be able to run this script on your server, you need to create the comments table in your MySQL database. You can do this by executing the SQL code found in table.sql from the SQL tab of phpMyAdmin. After this you need to enter your MySQL connection details in connect.php.