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!

Monday, November 19, 2007

Final examinations!

My final examinations are coming closer and closer! I'm supposed to take the first one and the second one on the coming Sunday! :(
But after Dec 12 I'll have free time to do... :D

Wednesday, November 14, 2007

Going to Kish

I've not received my employment visa so far, so the company send me to Kish island this evening and will renew my visa... ;)
I've never been there and may have a little fun! :D

Monday, November 12, 2007

Uploading Files, Using Ajax

As you may know it is impossible to upload files to the server using XHR! And the easiest way to upload them in an AJAX way is to use Iframes.
But be aware that uploading files through the XMLHttpRequests is NOT impossible, although it has some security issues.

So we will see how to develop a simple Ajax based upload using Iframe. The upload process by itself doesn't have anything complicated. You can do it in a synchronous style using any kind of server-side technology such as PHP, JSP, ASP or...
It will happen in a document which is displaying on the page using an Iframe so from the whole document point of view it will upload the file as an asynchronous request. But the thing is so important here is the JavaScript integration which is required between the main document and the uploading document (the document inside the Iframe) for showing some progress or loading animations.

In this tutorial I use PHP as server-side language and prototype.js as Ajax/JavaScript framwork.
You can download this script here, or do it yourself step by step:

1. index.html
Create a new file called index.html and write the following code in the body:


<h2>Upload file</h2>
<iframe frameborder=0 src="upload.php"></iframe>
<div id="board"></div>
<div id="images"></div>


The first DIV with ID="board" is for some messages which will be received before/after the upload process from the uploading document (the document inside th IFrame).
And the second one is for displaying uploaded photos. (If the uploaded files are photos!)


2. upload.php
Create another file called upload.php and write the following code inside it:

<?php

?>
<script type="text/javascript" src="js/prototype.js"></script>

<script type="text/javascript">

<!--
var par = parent.content.document;
var board = par.getElementById("board");
var images = par.getElementById("images");

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

function message(msg, color) {
var message = par.createTextNode(msg);
board.setAttribute("style", "color: " + color);
board.appendChild(message);
}

function upload() {
var loader = par.createElement("img");
loader.setAttribute("src", "img/progress.gif");
removeChildrenOf(board);
board.appendChild(loader);
document.forms['photoform'].submit();
}

function addPhoto(source) {
var img = par.createElement("img");
img.setAttribute("src", "img/" + source);
images.appendChild(img);
}

<?php
if(isset($_FILES['file'])) {
sleep(1);
echo "removeChildrenOf(board);";
$ext = substr($_FILES['file']['name'], strrpos($_FILES['file']['name'], '.') + 1);

if((strtoupper($ext) == "JPG" || strtoupper($ext) == "GIF") || (strtoupper($ext) == "PNG" || strtoupper($ext) == "BMP")) {
copy($_FILES['file']['tmp_name'],'img/'.$_FILES['file']['name']);
echo "message('The photo was uploaded successfully.', '#22AA44'); ";
echo "addPhoto('".$_FILES['file']['name']."');";
} else {
echo "message('Invalid format! The valid formats are: JPG, GIF, PNG and BMP.', '#ff4444'); ";
}
}
?>

//-->
</script>

<form action="" method="post" id="photoform" enctype="multipart/form-data">
<input type="file" name="file" onchange="upload()"/>
</form>



3. The other needed files
Don't forget to create a new folder called js and copy the prototype.js file there.
And create another folder called img and copy a GIF animation called progress.gif there.

Enjoy uploading photos asynchronously!


Saturday, November 10, 2007

Ajax News

A major announcement today by Isomorphic Software, the SmartClient Ajax platform is being released free and open source, under the LGPL. SmartClient is the *only* Ajax platform that has been used to build the entire user interface of major software products, including:
  • Informatica PowerAnalyzer
  • Wily Introscope
  • Document Sciences xPression
  • Copyright Clearance Center RightSphere
  • Intuit Quickbooks TimeTracker Online
  • Lontra Service Portfolio Manager




Three announcements in one, the final versions of Prototype 1.6.0, script.aculo.us 1.8.0 are now available in addition to the Prototype & script.aculo.us book by Christophe Porteneuve. The latest Prototype 1.6.0 got a lot of API changes that you should be familiar if you worked with the RC0 and RC1, and in total there is 20 bug fixes and enhancements since the RC1, which was released by October 16th. More info on this release could be found on the changelog.



gmail_logo.jpg
Gmail just got a new update this week with a faster navigation and improved contact list manager, in addition to a restructured source code. The big change in this release is probably not visible to the public, and will be certainly noticed in the next months with more exciting features to be released. Google didn't comment on the technologies used in this release but just confirmed that it wasn't GWT a Google spokesperson told us "We don't have anything new to share about the technologies used to create Gmail, but I can tell you that we've used Google Web Toolkit to build parts of Google Base and Google Checkout, and all of Google Mashup Editor"
"In short, the Gmail team has been working on a major structural code change that we're rolling out to users over the coming weeks to make Gmail faster and more flexible.", explained a Google spokesperson, " To start with, you'll notice faster mail browsing, as well as an upgraded contact manager that presents your contact data in an easy-to-read column view. The new code structure also lays the groundwork for some new Gmail features we'll be launching in the coming months."

Thursday, November 8, 2007

Back and forward buttons


Ajax is excellent, of course, but it has its own problems as well. One of the most popular ones is that Ajax requests are not registered in the browser history. So you can not undo or redo them by means of the browsers Back and Forward buttons. Google, Gmail and GWT (Google Web Toolkit) support these functions and the reason is in Google Web Toolkit all the Ajax functionalities are not amazingly based on XMLHttpRequest object! Yes they use IFrames as well, so they can handle the browser history with back and forward buttons.
They started developing Gmail as their first Ajax application many years ago and that time XMLHttpRequest was not supported by all the browsers and it was not accepted by W3C also. But in the current time what is the best solution for keeping the history of Ajax requests and handling them by Back and Forward buttons???

Wednesday, November 7, 2007

XUL, new gift from Mozilla

I was surfing the Net looking for some DOM manipulation methods that I found a new word in the mozilla developer center, it is XUL! It is the first time I've seen this word! Oh what is it really?
It is mentioned there that it stands for XML User interface Language developed by Mozilla.

Seems delicious! ;)
Visit here also!



I may write more posts about this topic!

Thursday, November 1, 2007

W3C accepted XMLHttpRequest

Finally W3C accepted the XMLHttpRequest as an standard object.
You can review the draft of specification here.

And from now on all the browsers will have a united way to create an object of this class:

var client = new win.XMLHttpRequest()

And more cross-browser compatibility!

The interface that all browsers have to implement for this object (class) is like this:

interface XMLHttpRequest {
// event handler
attribute EventListener onreadystatechange;

// state
const unsigned short UNSENT = 0;
const unsigned short OPENED = 1;
const unsigned short HEADERS_RECEIVED = 2;
const unsigned short LOADING = 3;
const unsigned short DONE = 4;
readonly attribute unsigned short readyState;

// request
void open(in DOMString method, in DOMString url);
void open(in DOMString method, in DOMString url, in boolean async);
void open(in DOMString method, in DOMString url, in boolean async, in DOMString user);
void open(in DOMString method, in DOMString url, in boolean async, in DOMString user, in DOMString password);
void setRequestHeader(in DOMString header, in DOMString value);
void send();
void send(in DOMString data);
void send(in Document data);
void abort();

// response
DOMString getAllResponseHeaders();
DOMString getResponseHeader(in DOMString header);
readonly attribute DOMString responseText;
readonly attribute Document responseXML;
readonly attribute unsigned short status;
readonly attribute DOMString statusText;
};

It's also natively implemented in IE7 which means no more ActiveX. ;)

Saturday, October 27, 2007

Ajax clock, an alive clock using the server time

In this tutorial we will see how easy is to develop a simple clock using the prototype Ajax classes, specifically Ajax.PeriodicalUpdater class.

You can download this tutorial files here.

Developing a JavaScript clock is not so difficult, and there are a bunch of them available in the net. But sometimes we need to show the server's time on the clock, instead of using the clients' own machine time. So the solution is Ajax if we want to have an interactive (alive) clock on the page which is showing the server's time without refreshing the page again and again.


1.
Create a html file and write the following code :

in the head section:



in body section:




2.
Create a PHP file called clock.php containing the following code:




3.
Create a floder called js besides these files and copy the prototype.js in it. You can download the latest version of prototype framework here.

Thats it! Copy all the files in the apache htdocs folder and enjoy!


Explanation:

We have a div with id="clock" in the html body which is our placeholder for displaying the time.
In the JavaScript section we have created a new object of class Ajax.PeriodicalUpdater which is one of the Ajax classes provided by prototype framework.
According to the prototype document:

This object addresses the common need of periodical update, which is used by all sorts of “polling” mechanisms (e.g. in an online chatroom or an online mail client).

So we don't need to provide a mechanism for fetching the time again and again, this object will repeat its job automatically based on its frequency option in the options parameter.
The first parameter is the id of the HTML element which will show the result and the second one is the URL for the request (XMLHttpRequest).

Enjoy Ajax!


Friday, October 26, 2007

First day in new office

...yesterday was our opening day in the new office, we have launched the web portal as well...



Indi (our boss) 's mom is clicking the mouse button to launch the portal...










Tanvir is looking at our bonus envelope to find out how much it is








Indi and his mom



Tanvir


Asela


...having lunch at 4 o'clock ;)


now, today is the first real work day in the new office, I'm posting these photos...