// destructor closes database connection public function __destruct { $this->mMysqli->close; } // truncates the table containing the messages public function deleteMessages { //
Trang 1// destructor closes database connection
public function destruct()
{
$this->mMysqli->close();
}
// truncates the table containing the messages
public function deleteMessages()
{
// build the SQL query that adds a new message to the server
$query = 'TRUNCATE TABLE chat';
// execute the SQL query
$result = $this->mMysqli->query($query);
}
/*
The postMessages method inserts a message into the database
- $name represents the name of the user that posted the message
- $messsage is the posted message
- $color contains the color chosen by the user
*/
public function postMessage($name, $message, $color)
{
// escape the variable data for safely adding them to the database $name = $this->mMysqli->real_escape_string($name);
$message = $this->mMysqli->real_escape_string($message);
$color = $this->mMysqli->real_escape_string($color);
// build the SQL query that adds a new message to the server
$query = 'INSERT INTO chat(posted_on, user_name, message, color) ' 'VALUES (NOW(), "' $name '" , "' $message
'","' $color '")';
// execute the SQL query
$result = $this->mMysqli->query($query);
}
/*
The retrieveNewMessages method retrieves the new messages that have been posted to the server
- the $id parameter is sent by the client and it
represents the id of the last message received by the client Messages more recent by $id will be fetched from the database and returned to the client in XML format
*/
public function retrieveNewMessages($id=0)
{
// escape the variable data
$id = $this->mMysqli->real_escape_string($id);
// compose the SQL query that retrieves new messages
if($id>0)
{
// retrieve messages newer than $id
$query =
'SELECT chat_id, user_name, message, color, '
' DATE_FORMAT(posted_on, "%Y-%m-%d %H:%i:%s") '
' AS posted_on '
' FROM chat WHERE chat_id > ' $id
' ORDER BY chat_id ASC';
}
else
{
// on the first load only retrieve the last 50 messages from server $query =
' SELECT chat_id, user_name, message, color, posted_on FROM '
Trang 2Chapter 5 ' DATE_FORMAT(posted_on, "%Y-%m-%d %H:%i:%s") AS posted_on ' ' FROM chat '
' ORDER BY chat_id DESC '
' LIMIT 50) AS Last50'
' ORDER BY chat_id ASC';
}
// execute the query
$result = $this->mMysqli->query($query);
// build the XML response
$response = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'; $response = '<response>';
// output the clear flag
$response = $this->isDatabaseCleared($id);
// check to see if we have any results
if($result->num_rows)
{
// loop through all the fetched messages to build the result message while ($row = $result->fetch_array(MYSQLI_ASSOC))
{
$id = $row['chat_id'];
$color = $row['color'];
$userName = $row['user_name'];
$time = $row['posted_on'];
$message = $row['message'];
$response = '<id>' $id '</id>'
'<color>' $color '</color>'
'<time>' $time '</time>'
'<name>' $userName '</name>'
'<message>' $message '</message>';
}
// close the database connection as soon as possible
$result->close();
}
// finish the XML response and return it
$response = $response '</response>';
return $response;
}
/*
The isDatabaseCleared method checks to see if the database has been cleared since last call to the server
- the $id parameter contains the id of the last message received by the client
*/
private function isDatabaseCleared($id)
{
if($id>0)
{
// by checking the number of rows with ids smaller than the client's // last id we check to see if a truncate operation was performed in // the meantime
$check_clear = 'SELECT count(*) old FROM chat where chat_id<=' $id; $result = $this->mMysqli->query($check_clear);
$row = $result->fetch_array(MYSQLI_ASSOC);
// if a truncate operation occured the whiteboard needs to be reset if($row['old']==0)
return '<clear>true</clear>';
}
return '<clear>false</clear>';
Trang 3}
}
?>
8 Create another file named get_color.php and add this code to it:
<?php
// the name of the image file
$imgfile='palette.png';
// load the image file
$img=imagecreatefrompng($imgfile);
// obtain the coordinates of the point clicked by the user
$offsetx=$_GET['offsetx'];
$offsety=$_GET['offsety'];
// get the clicked color
$rgb = ImageColorAt($img, $offsetx, $offsety);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// return the color code
printf('#%02s%02s%02s', dechex($r), dechex($g), dechex($b));
?>
9 Let's deal with the client now Start by creating chat.css and adding this code to it:
body
{
font-family: Tahoma, Helvetica, sans-serif;
margin: 1px;
font-size: 12px;
text-align: left
}
#content
{
border: DarkGreen 1px solid;
margin-bottom: 10px
}
input
{
border: #999 1px solid;
font-size: 10px
}
#scroll
{
position: relative;
width: 340px;
height: 270px;
overflow: auto
}
.item
{
margin-bottom: 6px
}
#colorpicker
{
text-align:center
}
Trang 4Chapter 5
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>AJAX Chat</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link href="chat.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="chat.js" ></script>
</head>
<body onload="init();">
<noscript>
Your browser does not support JavaScript!!
</noscript>
<table id="content">
<tr>
<td>
<div id="scroll">
</div>
</td>
<td id="colorpicker">
<img src="palette.png" id="palette" alt="Color
Palette" border="1" onclick="getColor(event);"/>
<br />
<input id="color" type="hidden" readonly="true" value="#000000" /> <span id="sampleText">
(text will look like this)
</span>
</td>
</tr>
</table>
<div>
<input type="text" id="userName" maxlength="10" size="10"
onblur="checkUsername();"/>
<input type="text" id="messageBox" maxlength="2000" size="50" onkeydown="handleKey(event)"/>
<input type="button" value="Send" onclick="sendMessage();" />
<input type="button" value="Delete All" onclick="deleteMessages();" /> </div>
</body>
</html>
11 Create another file named chat.js and add this code to it:
/* chatURL - URL for updating chat messages */
var chatURL = "chat.php";
/* getColorURL - URL for retrieving the chosen RGB color */
var getColorURL = "get_color.php";
/* create XMLHttpRequest objects for updating the chat messages and
getting the selected color */
var xmlHttpGetMessages = createXmlHttpRequestObject();
var xmlHttpGetColor = createXmlHttpRequestObject();
/* variables that establish how often to access the server */
var updateInterval = 1000; // how many miliseconds to wait to get new message
// when set to true, display detailed error messages
var debugMode = true;
/* initialize the messages cache */
var cache = new Array();
/* lastMessageID - the ID of the most recent chat message */
var lastMessageID = -1;
/* mouseX, mouseY - the event's mouse coordinates */
var mouseX,mouseY;
Trang 5/* creates an XMLHttpRequest instance */
function createXmlHttpRequestObject()
{
// will store the reference to the XMLHttpRequest object
var xmlHttp;
// this should work for all browsers except IE6 and older
try
{
// try to create XMLHttpRequest object
xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// assume IE6 or older
var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0",
"MSXML2.XMLHTTP.5.0",
"MSXML2.XMLHTTP.4.0",
"MSXML2.XMLHTTP.3.0",
"MSXML2.XMLHTTP",
"Microsoft.XMLHTTP");
// try every prog id until one works
for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++)
{
try
{
// try to create XMLHttpRequest object
xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
}
catch (e) {}
}
}
// return the created object or display an error message
if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;
}
/* this function initiates the chat; it executes when the chat page loads
*/
function init()
{
// get a reference to the text box where the user writes new messages var oMessageBox = document.getElementById("messageBox");
// prevents the autofill function from starting
oMessageBox.setAttribute("autocomplete", "off");
// references the "Text will look like this" message
var oSampleText = document.getElementById("sampleText");
// set the default color to black
oSampleText.style.color = "black";
// ensures our user has a default random name when the form loads checkUsername();
// initiates updating the chat window
requestNewMessages();
}
// function that ensures that the username is never empty and if so // a random name is generated
function checkUsername()
{
// ensures our user has a default random name when the form loads var oUser=document.getElementById("userName");
if(oUser.value == "")
Trang 6Chapter 5 /* function called when the Send button is pressed */
function sendMessage()
{
// save the message to a local variable and clear the text box
var oCurrentMessage = document.getElementById("messageBox");
var currentUser = document.getElementById("userName").value;
var currentColor = document.getElementById("color").value;
// don't send void messages
if (trim(oCurrentMessage.value) != "" &&
trim(currentUser) != "" && trim (currentColor) != "")
{
// if we need to send and retrieve messages
params = "mode=SendAndRetrieveNew" +
"&id=" + encodeURIComponent(lastMessageID) +
"&color=" + encodeURIComponent(currentColor) +
"&name=" + encodeURIComponent(currentUser) +
"&message=" + encodeURIComponent(oCurrentMessage.value); // add the message to the queue
cache.push(params);
// clear the text box
oCurrentMessage.value = "";
}
}
/* function called when the Delete Messages button is pressed */
function deleteMessages()
{
// set the flag that specifies we're deleting the messages
params = "mode=DeleteAndRetrieveNew";
// add the message to the queue
cache.push(params);
}
/* makes asynchronous request to retrieve new messages, post new messages, delete messages */
function requestNewMessages()
{
// retrieve the username and color from the page
var currentUser = document.getElementById("userName").value;
var currentColor = document.getElementById("color").value;
// only continue if xmlHttpGetMessages isn't void
if(xmlHttpGetMessages)
{
try
{
// don't start another server operation if such an operation
// is already in progress
if (xmlHttpGetMessages.readyState == 4 ||
xmlHttpGetMessages.readyState == 0)
{
// we will store the parameters used to make the server request var params = "";
// if there are requests stored in queue, take the oldest one
if (cache.length>0)
params = cache.shift();
// if the cache is empty, just retrieve new messages else
params = "mode=RetrieveNew" +
"&id=" +lastMessageID;
// call the server page to execute the server-side operation xmlHttpGetMessages.open("POST", chatURL, true);
xmlHttpGetMessages.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded"); xmlHttpGetMessages.onreadystatechange = handleReceivingMessages;
Trang 7xmlHttpGetMessages.send(params);
}
else
{
// we will check again for new messages
setTimeout("requestNewMessages();", updateInterval);
}
}
catch(e)
{
displayError(e.toString());
}
}
}
/* function that handles the http response when updating messages */ function handleReceivingMessages()
{
// continue if the process is completed
if (xmlHttpGetMessages.readyState == 4)
{
// continue only if HTTP status is "OK"
if (xmlHttpGetMessages.status == 200)
{
try
{
// process the server's response
readMessages();
}
catch(e)
{
// display the error message
displayError(e.toString());
}
}
else
{
// display the error message
displayError(xmlHttpGetMessages.statusText);
}
}
}
/* function that processes the server's response when updating messages */ function readMessages()
{
// retrieve the server's response
var response = xmlHttpGetMessages.responseText;
// server error?
if (response.indexOf("ERRNO") >= 0
|| response.indexOf("error:") >= 0
|| response.length == 0)
throw(response.length == 0 ? "Void server response." : response); // retrieve the document element
response = xmlHttpGetMessages.responseXML.documentElement;
// retrieve the flag that says if the chat window has been cleared or not clearChat =
response.getElementsByTagName("clear").item(0).firstChild.data; // if the flag is set to true, we need to clear the chat window
if(clearChat == "true")
{
// clear chat window and reset the id
document.getElementById("scroll").innerHTML = "";
Trang 8Chapter 5 }
// retrieve the arrays from the server's response
idArray = response.getElementsByTagName("id");
colorArray = response.getElementsByTagName("color");
nameArray = response.getElementsByTagName("name");
timeArray = response.getElementsByTagName("time");
messageArray = response.getElementsByTagName("message");
// add the new messages to the chat window
displayMessages(idArray, colorArray, nameArray, timeArray,
messageArray); // the ID of the last received message is stored locally
if(idArray.length>0)
lastMessageID = idArray.item(idArray.length - 1).firstChild.data; // restart sequence
setTimeout("requestNewMessages();", updateInterval);
}
/* function that appends the new messages to the chat list */
function displayMessages(idArray, colorArray, nameArray,
timeArray, messageArray)
{
// each loop adds a new message
for(var i=0; i<idArray.length; i++)
{
// get the message details
var color = colorArray.item(i).firstChild.data.toString();
var time = timeArray.item(i).firstChild.data.toString();
var name = nameArray.item(i).firstChild.data.toString();
var message = messageArray.item(i).firstChild.data.toString();
// compose the HTML code that displays the message
var htmlMessage = "";
htmlMessage += "<div class=\"item\" style=\"color:" + color + "\">"; htmlMessage += "[" + time + "] " + name + " said: <br/>";
htmlMessage += message.toString();
htmlMessage += "</div>";
// display the message
displayMessage (htmlMessage);
}
}
// displays a message
function displayMessage(message)
{
// get the scroll object
var oScroll = document.getElementById("scroll");
// check if the scroll is down
var scrollDown = (oScroll.scrollHeight - oScroll.scrollTop <=
oScroll.offsetHeight );
// display the message
oScroll.innerHTML += message;
// scroll down the scrollbar
oScroll.scrollTop = scrollDown ? oScroll.scrollHeight :
oScroll.scrollTop;
}
// function that displays an error message
function displayError(message)
{
// display error message, with more technical details if debugMode is true displayMessage("Error accessing the server! "+
(debugMode ? "<br/>" + message : ""));
}
/* handles keydown to detect when enter is pressed */
Trang 9function handleKey(e)
{
// get the event
e = (!e) ? window.event : e;
// get the code of the character that has been pressed code = (e.charCode) ? e.charCode :
((e.keyCode) ? e.keyCode :
((e.which) ? e.which : 0));
// handle the keydown event
if (e.type == "keydown")
{
// if enter (code 13) is pressed
if(code == 13)
{
// send the current message
sendMessage();
}
}
}
/* removes leading and trailing spaces from the string */
function trim(s)
{
return s.replace(/(^\s+)|(\s+$)/g, "")
}
/* function that computes the mouse's coordinates in page */
function getMouseXY(e)
{
// browser specific
if(window.ActiveXObject)
{
mouseX = window.event.x + document.body.scrollLeft;
mouseY = window.event.y + document.body.scrollTop;
}
else
{
mouseX = e.pageX;
mouseY = e.pageY;
}
}
/* makes a server call to get the RGB code of the chosen color */ function getColor(e)
{
getMouseXY(e);
// don't do anything if the XMLHttpRequest object is null
if(xmlHttpGetColor)
{
// initialize the offset position with the mouse current position var offsetX = mouseX;
var offsetY = mouseY;
// get references
var oPalette = document.getElementById("palette");
var oTd = document.getElementById("colorpicker");
// compute the offset position in our window
if(window.ActiveXObject)
{
offsetX = window.event.offsetX;
offsetY = window.event.offsetY;
}
else
{
Trang 10Chapter 5 }
// call server asynchronously to find out the clicked color
try
{
if (xmlHttpGetColor.readyState == 4 ||
xmlHttpGetColor.readyState == 0)
{
params = "?offsetx=" + offsetX + "&offsety=" + offsetY; xmlHttpGetColor.open("GET", getColorURL+params, true);
xmlHttpGetColor.onreadystatechange = handleGettingColor;
xmlHttpGetColor.send(null);
}
}
catch(e)
{
// display error message
displayError(xmlHttp.statusText);
}
}
}
/* function that handles the http response */
function handleGettingColor()
{
// if the process is completed, decide to do with the returned data
if (xmlHttpGetColor.readyState == 4)
{
// only if HTTP status is "OK"
if (xmlHttpGetColor.status == 200)
{
try
{
//change the color
changeColor();
}
catch(e)
{
// display error message
displayError(xmlHttpGetColor.statusText);
}
}
else
{
// display error message
displayError(xmlHttpGetColor.statusText);
}
}
}
/* function that changes the color used for displaying messages */
function changeColor()
{
response=xmlHttpGetColor.responseText;
// server error?
if (response.indexOf("ERRNO") >= 0
|| response.indexOf("error:") >= 0
|| response.length == 0)
throw(response.length == 0 ? "Can't change color!" : response);
// change color
var oColor = document.getElementById("color");
var oSampleText = document.getElementById("sampleText");
oColor.value = response;
oSampleText.style.color = response;
}