Monday, December 31, 2007

non-UTF8 characters in XML

Have you ever used an Ajax tool which is very sensitive to the non-UTF characters in the XML data which is coming back from the server-side script??? I mean those tools which are using the responseXML field of XMLHttpRequest instead of its responseText! Taconite is one of this kind of tools.
It is a big headache when you couldn't see the result due to only one invalid character which is there because you (or the operator) have copy paste the text in your DB from MS Word or any other applications which are not supporting Unicode by default!
Some standard browsers are not so sensitive to these invalid characters and do the correction automatically, Firefox, Opera and Safari do this but the most popular one (it's a pity) which is MS IE doesn't do that! And is 100% sensitive to all kind of these characters! :(
In the company everyday one of us reports the others that
Oh shit! search results of the ... part of the portal are not coming in IE!!! Ehsuuuuuuuuuuuuuun!!!
- Oh who entered data for ...part??? Have you copied them from Word?!!! Oh one of you should go through the records and find that invalid character which is 99% a comma!

Tiered of this lengthy solution, I've decided to find a way that convert invalid characters in an string to their corresponding UTF8 character! After some research in the PHP resources I found this nice function here!

$text = iconv("UTF-8","UTF-8//IGNORE",$text);

Tuesday, December 25, 2007

XSLT or Template Engines

Having a nice separation between business logic and presentation logic in web development is a really beneficial and important functionality to be obtained. There are many template engines for any server-side technology out there such as: Smarty, Heyes Template Class, FastTemplate, ShellPage, STP Simple Template Parser, OO Template Class, SimpleTemplate, bTemplate for PHP scripting language and Velocity, FreeMarker, SiteMesh, Better Templates for Everybody, WebMacro, Transformica, Tea, Jamon, StringTemplate, jxp for JSP. There are lots of them but there are many common features in all of them.
Usually 2 goals are achieved by using a template engine:
  1. Separation of the business logic and presentation logic
  2. Separation of the server-side scripts and HTML code. (logic and content)

The former is the right goal! and the latter shouldn't be a direct goal. The separation of HTML and Scripting language will achieve in some extent but we shouldn't go deliberately for gaining it! For example assume that we want to display a table-based report of all customers who have bought something in the last month in 3 columns. Executing the query and fetching the result should be happened in the business logic and separated from HTML code. But dividing the customers in 3 groups in the business logic is a wrong solution! Because in a new layout (template design) we may want the customers in 4 columns, so we should achieve this without amending the business layer. So our template engine should have the features to let us have some logic in the templates (presentation logic) in this example we need to have FOR loops or similar structures in order to display the group of customers in 3 columns. This is exactly what is done by Smarty and XSLT. But there are some problems with using the template engines which are:
  1. They usually have complex process and documents.
  2. Some of them are replacing the standard and popular scripting language e.g. PHP with a more complex and non-standard conventional language
  3. The business layer usually produce a non-standard and non-structured data which is totally useless to other websites or applications
  4. They usually (NOT always) bring some security risks if we have untrusted template developers.



Using XSLT realize the main goal which is separating the business logic from presentation logic. We can have powerful logical structures in the presentation layer which could not be malicious as well. Generally XSLT will bring the following benefits:
  1. The XSLT documents are not more than some XML files and HTML files.
  2. XSLT could be as complex as some of the template engines but there are lots of books and resources out there due to its standard and support from W3C.
  3. The data which is produced by business layer i.e. XML is 100% standard and reusable by other programming technologies.
  4. The XSLT logical structures could not be used in a malicious fashion.





Download the e-book: Beginning XSLT 2.0 from Novice to Professional

Saturday, December 22, 2007

Firefox 3 Beta


You can download Firefox 3 beta here.
Let's check it out.

Google Suggest Tutorial

In the web sites and web applications most of the users are not aware of the exact and complete name of terms they are searching for! So it is a good idea to give them suggestion while they are trying to write the name of the desired words. Similar to what is happening in Google suggest.

In this tutorial we will do the same thing for a search in a group of people whose information are stored in a table of database. The same as the previous tutorials we use prototype.js as Ajax/DOM framework.

Since the steps are too simple and so similar to the previous tutorials, I let you download it and check it out by yourself! ;)

Good Luck!

Tuesday, December 18, 2007

Prototype and Scriptaculous Ebook


The first book about prototype.js framework and scriptaculous animation library!
Download the book here!

Friday, December 14, 2007

Goodbye AIT

My final examinations finished and I've just submitted my final project. Now I have more time to learn!!! :D ....and to think about the future...maybe Master.... :-)

Tuesday, December 11, 2007

Ajax Chat - Using Prototype & PHP

In the past years chat rooms were so rare in the websites and only those website which needed it were using chat facilities. Most of those chat rooms were developed by means of Java Applet technology hence the client browser had to be Java-enabled in order to use the chat rooms. After a while flash chat rooms came in the picture but they had the same drawback since the client needs to have the Flash player plugin installed in order to use the chat rooms.
Recently the Ajax-enabled chat rooms have come to the websites even the personal websites. They are so light, easy to develop and don't need any special software or prerequisites on the clients' browsers.

In this tutorial we will learn how to develop a very simple Ajax-enabled chat room based on PHP 5 server-side scripting language and Prototype JavaScript framework.

You can develop this chat room following the steps bellow or download it here.

1. JavaScript Message class and one utility function
Create 2 folders called php and js. Copy the prototype.js file in the js folder.
Create a new javascript file called chat.js which contains the following code and put it in the js folder.

var Message = Class.create();
Message.prototype = {
initialize: function(id, timestamp, serverTimestamp, nickname, text) {
this.id = id;
this.timestamp = timestamp;
this.serverTimestamp = serverTimestamp;
this.nickname = nickname;
this.text = text;
},
};


function removeChildrenOf(s) {
while (s.hasChildNodes())
s.removeChild(s.childNodes[0]);
}


2. PHP Message class
Create a new php file called message.class.php which contains the following code and put it in the php folder.


<?php
class Message {

const MAX_TEXT_LENGTH = 100;
const MAX_NICKNAME_LENGTH = 20;

// ...........................................

private $id;
private $timestamp;
private $serverTimestamp;
private $nickname;
private $text;

// ...........................................

public function __construct($id = 0, $timestamp = 0, $serverTimestamp, $nickname = "", $text = "") {
$this->id = $id;
$this->timestamp = $timestamp;
$this->serverTimestamp = $serverTimestamp;
$this->nickname = $nickname;
$this->text = $text;
}

// ...........................................

public function setId($id) {
$this->id = $id;
}

public function getId() {
return $this->id;
}

public function setTimestamp($timestamp) {
$this->timestamp = $timestamp;
}

public function getTimestamp() {
return $this->timestamp;
}

public function setServerTimestamp($serverTimestamp) {
$this->serverTimestamp= $serverTimestamp;
}

public function getServerTimestamp() {
return $this->serverTimestamp;
}

public function setText($text) {
if(strlen($text) > self::MAX_TEXT_LENGTH)
echo "Error: Text is too long! Maximum is ".self::MAX_TEXT_LENGTH;
else
$this->text = $text;
}

public function getText() {
return $this->text;
}

public function setNickname($nickname) {
if(strlen($text) > self::MAX_NICKNAME_LENGTH)
echo "Error: Nickname is too long! Maximum is ".self::MAX_NICKNAME_LENGTH;
else
$this->nickname = $nickname;
}

public function getNickname() {
return $this->nickname;
}
}
?>


3. Database, Tables and Configuration
Create a database in your mysql DBMS and run the following query on it in order to create the message table.


CREATE TABLE `message` (
`id` int(10) unsigned NOT NULL auto_increment,
`timestamp` bigint(20) unsigned default NULL,
`text` varchar(100) default NULL,
`serverTimestamp` bigint(20) unsigned default NULL,
`nickname` varchar(20) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


Create a php file called config.inc.php which contains the following code and put it in the php folder.
Don't forget to write database name, username and password of your mySql server instead of corresponding parameters in this file.

<?php
define("DB_HOST", "localhost");
define("DB_USERNAME", "root");
define("DB_PASSWORD", "ebic");
define("DB_NAME", "chat");
?>


4. Send Message server-side script

Create a php file called send.php which contains the following code, don't put it in any folder, let it be in the root folder of your website.


<?php
include_once('./php/config.inc.php');

$mysqli = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);

if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}

$text = isset($_POST['text']) ? $_POST['text'] : "";
$timestamp = isset($_POST['timestamp']) ? $_POST['timestamp'] : 0;
$serverTimestamp = isset($_POST['serverTimestamp']) ? $_POST['serverTimestamp'] : 0;
$nickname = isset($_POST['nickname']) ? $_POST['nickname'] : "";

$sql = "INSERT INTO message (text, nickname, timestamp, serverTimestamp)
VALUES('$text', '$nickname', '$timestamp', '$serverTimestamp')";

if (!$mysqli->query($sql)) {
echo "Error in query";
}

?>


5. Receive Messages server-side script
Create a php file called get.php which contains the following code, don't put it in any folder, let it be in the root folder of your website.


<?php
include_once('./php/config.inc.php');

header('Content-type: text/xml');

$mysqli = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);

if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}

echo "<messages>";

$timestamp = time();
$sql = "DELETE FROM message WHERE $timestamp - serverTimestamp > 1000 ";

if (!$mysqli->query($sql)) {
echo "Error in query";
} else {
$sql = "SELECT * FROM message";
if (!$result = $mysqli->query($sql)) {
echo "Error in query";
} else {
while($record = $result->fetch_assoc()) {
echo "<message>";

echo "<id>";
echo $record['id'];
echo "</id>";

echo "<timestamp>";
echo $record['timestamp'];
echo "</timestamp>";

echo "<serverTimestamp>";
echo $record['serverTimestamp'];
echo "</serverTimestamp>";

echo "<text>";
echo $record['text'];
echo "</text>";

echo "<nickname>";
echo $record['nickname'];
echo "</nickname>";

echo "</message>";
}
}
}

echo"</messages>";

?>


6. Utility server-side script for getting the server timestamp
Create a php file called timestamp.php which contains the following code, don't put it in any folder, let it be in the root folder of your website.


<?php
echo mktime();
?>


7. Client script for sending and getting (main html page)
Create a html file called index.html which contains the following code, don't put it in any folder, let it be in the root folder of your website.


<?xml version="1.0" encoding="UTF-8" ?>
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Chat Room (Shout Box)</title>
<script type="text/javascript" src="js/prototype.js"></script>
<script type="text/javascript" src="js/chat.js"></script>

<script type="text/javascript"><!--
<!--

var serverTimestamp = 0;
var messages = new Array(10000);
var msgCount = 0;

function existInArray(msg) {
for(i = 0; i < msgCount; i++) {
if(msg.timestamp == messages[i].timestamp)
if(msg.serverTimestamp == messages[i].serverTimestamp)
return true;
}
return false;
}

function getMessages() {
new Ajax.Request('get.php?ts=' + new Date().getTime(), {
onSuccess: function(transport) {
var xml = transport.responseXML;
var msgNodes = xml.documentElement.childNodes;
for(i = 0; i < msgNodes.length; i++) {
var id = msgNodes[i].getElementsByTagName("id")[0].firstChild.nodeValue;
var nickname = msgNodes[i].getElementsByTagName("nickname")[0].firstChild.nodeValue;
var text = msgNodes[i].getElementsByTagName("text")[0].firstChild.nodeValue;
var timestamp = msgNodes[i].getElementsByTagName("timestamp")[0].firstChild.nodeValue;
var serverTimestamp = msgNodes[i].getElementsByTagName("serverTimestamp")[0].firstChild.nodeValue;
var msg = new Message(id, timestamp, serverTimestamp, nickname, text);
//alert(i);
if(!existInArray(msg)) {
messages[msgCount++] = msg;
}
}
}
});

showMessages();
setTimeout("getMessages()", 4000);
}

function updateServerTimestamp() {
new Ajax.Request('timestamp.php?ts=' + new Date().getTime(), {
onSuccess: function(transport) {
serverTimestamp = transport.responseText;
}
});
}

function showMessages() {
var board = $('board');
removeChildrenOf(board);
for(i = 0; i < msgCount; i++) {
var msgView = document.createElement("div");
var msg = messages[i];
var date = new Date(parseInt(msg.timestamp, 10));
msgView.innerHTML = msg.nickname + " <small>(" + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + ")</small>: " + msg.text;
board.appendChild(msgView);
}
board.scrollTop = board.scrollHeight;
}

function sendMessage(msg) {
new Ajax.Request('send.php', {
method: 'post',
parameters: {
text: msg.text,
nickname: msg.nickname,
timestamp: msg.timestamp,
serverTimestamp: msg.serverTimestamp
},
onFailure: function() {
sendMessage(msg);
}
});

}

function doMessage() {
if ($F("message").length > 0) {
var board = $('board');
var msg = new Message(0, new Date().getTime(), serverTimestamp, $F('name'), $F("message"));
//alert(msg.timestamp);
messages[msgCount++] = msg;
showMessages();
sendMessage(msg);
board.scrollTop = board.scrollHeight;
}
$('message').clear();
$('message').focus();
updateServerTimestamp();
}

Event.observe(window, 'load', function() {
updateServerTimestamp();
getMessages();
});


//-->
</script>


<style>
<!--

#board {
width: 400px;
border: inset 2px;
height: 300px;
padding: 2px;
overflow: auto;
}

-->
</style>
</head>
<body>

<h1>Chat Room</h1>

<form action="" onsubmit="return false;">
<div id="board"></div>
<br />
<label>Nickname:</label>
<input type="text" name="name" id="name" maxlength="20" />
<br />
<label>Message:</label>
<input type="text" id="message" name="message" maxlength="100" size="45"/>
<input type="submit" value="Send" name="send" onclick="doMessage()"/>
</form>
<br />
<br />
<a href="http://ehsun7b.blogspot.com">ehsun7b.blogspot.com</a>
</body>
</html>



Enjoy chatting in your own website!