Categories
Projects Technology Thought Experiments

Project: tsnXchat

After using a flooble chatterbox from www.flooble.com, and trying to (unsuccessfully) hack it to get rid of the ads at the bottom, I have resolved to putting my newly developed AJAX skills to the test, to create an open-source version, with no ads. I’ll explain how you can make one too in this entry.

It only requires 3 files, a MYSQL database, access to a server running PHP, and a basic understanding of JavaScript, HTML, PHP, MySQL, and about 10-30 minutes (depending on your understanding of this stuff). I’ll try to keep things as basic as possible so that anyone who reads this can understand what’s going on.

Before you get started, you need to have a couple things.

  • A database that you can access, with a known username and password, and that you’re able to write to. You’ll be creating a table and populating it with data. If you don’t have that, go to mysql.com and get one there. (If you want to facilitate the use of MySQL, then you should probably go with something like phpMyAdmin.
  • PHP engine. If you don’t have PHP, you’ll need to get that also.
  • A web server. Apache works fine. I haven’t used MS IIS in about 5 years, and I don’t think you should either really. But there’s not anything wrong with it…just setting it up take time.
  • Also, if you don’t have a good coding program, I recommend using Notepad++. It’s opensource, free, and rawks face.

Now if you don’t have the ability to set all these things up on your own, or don’t already have them on a web server somewhere – then you can always get WAMP and it will have everything you need, bundled together, and in one install file. (Note: I don’t offer support for setting these services up. There is documentation, and they are all freeware/opensource, so everything you need is out there on their website)

Moving on….

Once you have your empty database created, you’ll need to run some SQL Commands to set up the table…

CREATE TABLE `ajax_chat` 
(`id` INT NOT NULL AUTO_INCREMENT ,
`ajaxchat_username` VARCHAR( 255 ) NOT NULL ,
`ajaxchat_text` TEXT NOT NULL ,
PRIMARY KEY ( `id` ) ,
FULLTEXT (`ajaxchat_text`)) 
TYPE = MYISAM ;

This code creates a table ajax_chat with 3 fields: id, ajaxchat_username, and ajaxchat_text. id is used for the primary key to sort the entries by number, since we’re not keeping track of the time they were entered. ajaxchat_username is going to be the username that the user inputs on the chat dialogue page. And ajaxchat_text is the chat text itself. It’s set up for a full text box, not just a 255 input box, like the ajaxchat_username is.

And then some sample data so you can test it’s functionality…

INSERT INTO `ajax_chat` (`ajaxchat_username` , `ajaxchat_text` )
VALUES ('User1', 'hello world!'), 
('User2', 'testing...hello world again');

Here we enter two records. Note that in the first set of SQL code we created a field called ‘id’ but here we leave it out of the Values() section because it’s auto-incremented.So we have (‘username’, ‘chat_text’) as the format for entering this in the database manually.

Now let’s move on to the pages…
__________________________________________________

Inside the index.htm we’ll have the only page that the user will see:

<html>

<head>
<title>AJAXchatbox</title>
   <script type="text/javascript">
      //Called by getchatdata.php
      function requestChatInfo() 
      {
         top.frames["hiddenFrame"].location = "getchatdata.php";
      }
      
      function displayChatInfo(sText) 
      {
         var divChatInfo = document.getElementById("divChatInfo");
         divChatInfo.innerHTML = sText;
      }
      
      //Called by sendchat.php
      function clearChatBox () 
      {
         var sayBox = document.getElementById("txtChat");
         sayBox.value = "";
      }
      
      function saveResult(sMessage)
      {
         requestChatInfo();
         if (sMessage)
         {
            var divStatus = document.getElementById("divStatus");
            divStatus.innerHTML = sMessage;
         }
      }
   </script>   
</head>

<body onload="requestChatInfo()">

<div id="divChatInfo"></div>
<div id="divStatus"></div>
<form method="post" action="sendchat.php" target="hiddenFrame">
   <p>Name: <input type="text" name="txtName" value="" style="width: 100px" /><br />
   Say: <input type="text" id="txtChat" name="txtChat" value="" style="width: 113px"><br /></p>
   <p><input type="submit" value="Send" /> <input type="button" value="Refresh" onclick="requestChatInfo()" /></p>
</form>
<iframe src="about:blank" name="hiddenFrame" width="0" height="0" frameborder="0"></iframe>
</body>

</html>

Let’s break this down a bit…we’ll start at the bottom to understand the layout of the page:

<body onload="requestChatInfo()">

<div id="divChatInfo"></div>
<div id="divStatus"></div>
<form method="post" action="sendchat.php" target="hiddenFrame">
   <p>Name: <input type="text" name="txtName" value="" style="width: 100px" /><br />
   Say: <input type="text" id="txtChat" name="txtChat" value="" style="width: 113px"><br /></p>
   <p><input type="submit" value="Send" /> <input type="button" value="Refresh" onclick="requestChatInfo()" /></p>
</form>
<iframe src="about:blank" name="hiddenFrame" width="0" height="0" frameborder="0"></iframe>
</body>
The first line is the <body> tage with the call to requestChatInfo() when the page loads. That way it automatically shows the chat text. Then there is <div id="divChatInfo"></div>. This is where the chat text is going to show up. Next is <div id="divStatus"></div>. Any error messages will appear here if there is a problem. Then the form for posting. The form calls sendchat.php when submitted, and loads it in target="hiddenFrame". The hiddenFrame is at the end of the html segment. When the form is submitted it sends two input boxes, txtName and txtChat. There is also a "Refresh" button. This makes the function call to the function requestChatInfo() which will be explained in a bit. Then the iframe is the hiddenFrame mentioned earlier. It has a width and height both of 0px and a border of 0px. This hides it from the user's view. And since there is no useful information displayed on this page for the user to read, they don't need to know it's there. When you're debugging though, if you choose to edit the .php pages, you might want to put some greater values in for the width and height so you can see any SQL error messages that might show up. Now for the top half...the javascript codes.
   <script type="text/javascript">
   //Called by getchatdata.php
      function requestChatInfo() {
         top.frames["hiddenFrame"].location = "getchatdata.php";
      }
      
      function displayChatInfo(sText) {
         var divChatInfo = document.getElementById("divChatInfo");
         divChatInfo.innerHTML = sText; 
      }
      
   //Called by sendchat.php
      function clearChatBox () {
         txtChat.value = "";
      }
      
      function saveResult(sMessage)
      {
         requestChatInfo();
         if (sMessage)
         {
            var divStatus = document.getElementById("divStatus");
            divStatus.innerHTML = sMessage;
         }
      }
   </script>

The first set of functions are called by the getchatdata.php page
The first function is requestChatInfo(sText). This function goes to the hiddenFrame, and loads the getchatdata.php.
The second function is to display the chat messages. It is going to be called by getchatinfo.php to send a variable across from the hiddenFrame to this visible page, denoted in the function call as sText.

The next set of functions are for the sendchat.php.
The first function is clearChatBox. This one gave me the most trouble to come up with. It clears the text from the chat box after the information has been sent to the database and back to your page. You'll note in the html code above that the <input> for txtChat has an ID="txtChat" NAME="txtChat" tag, while the input for txtName does not, only the NAME= tag. This makes the txtChat an object so we can call the attributes as variables and set them. If for some reason you wanted to clear the name text box, you could add ID="txtName" to the name input box, and add another line to the clearChatBox function that said:

txtName.value = "";

The second function is the error message function, saveResult(sMessage). This function first calls requestChatInfo() to load the chat messages. Then it brings over any error messages from sendchat.php, and loads them to the divStatus element.
________________________________________________

On to the getchatdata.php page. This page operates in the hiddenFrame, making a database connection, quering the data, and returning it to the visible page every 10 seconds.

<html>
<head>
<title>Get Chat Data</title>
<?php
   //php code
   $sInfo = ""; //Variable for storing chat messages
   $max_id = ""; //Upper Limit of chat record IDs to show in the chat.
   $min_id = 0; //Lower Limit of chat record IDs to show in the chat.
   
   $sDBServer = "localhost"; //your server name, can usually be localhost,
                              //unless you're connecting across sites.
   $sDBName = "ajax_chat_db"; //your database name
   $sDBUsername = "ajax_chat_user123"; //user name to connect to the database
   $sDBPassword = "sdf07hw2df"; //password for user to connect to the database
   //SQL query to grab the max record id from the database.
   $sQuery1 = "SELECT MAX(id) as id FROM ajax_chat";

   //Connect to the database here
   $oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword);
   @mysql_select_db($sDBName) or $sInfo="Unable to open database";
   
   //Check if the Query worked, and that there is at least one row.
   if ($oResult = mysql_query($sQuery1) and mysql_num_rows($oResult) > 0)
   {
      //Grab the row from the results and put it to variable $max_id
      $max_id = mysql_fetch_array($oResult,MYSQL_ASSOC);
      
      //Is max_id bigger than 15?
      if ($max_id['id'] > 15)
      {
         //It is...so we'll set the lower limit to only grab 15 records.
         $min_id = $max_id['id'] - 15;
      }
      else
      {
         //It's not...so we'll set the lower limit to 0
         //so that we don't go negative with records.
         $min_id = 0;
      }
      
      //SQL Query number 2 to go get our records from
      //the database located between min and max ids.
      $sQuery2 = "SELECT * FROM ajax_chat 
               ORDER BY id LIMIT " . $min_id . ", " . $max_id['id'];
      
      //Did the query work? And is there at least one record?
      if ($oResult2 = mysql_query($sQuery2) and mysql_num_rows($oResult2) > 0)
      {
         //Loop-de-loop...grab up the data.
         for ($i=0; $i < mysql_num_rows($oResult2); $i++ )
         {
            //Get the array of data, and store it
            $aValues = mysql_fetch_array($oResult2,MYSQL_ASSOC);

            //Let's add all the arrayed data to one variable to 
            //simplify passing it back to the visible page.
            $sInfo .= "<font face=\"Trebuchet MS\" size=\"x-small\" color=\"#003366\">" .
               "<b>" . $aValues['ajaxchat_username'] . "</b>" .
               "</font><font face=\"Trebuchet MS\" size=\"x-small\"" .
               " color=\"#000000\">: $aValues['ajaxchat_text'] . "<br />";
         }
      }
      else
      {
         //Crap, something didn't work if you see this.
         $sInfo = "Error getting ajaxchat info.";
      }
   }
   else
   {
      //Shucks...something is wrong with your code if you see this.
      $sInfor = "Error getting Max ID.";
   }   
   //Thank you, come again.
   mysql_close($oLink);
?>

   <script type="text/javascript">
      window.onload = function () {
         var divInfoToReturn = document.getElementById("divInfoToReturn");
         parent.displayChatInfo(divInfoToReturn.innerHTML);
      };
   </script>
<meta http-equiv="refresh" content="10">   

</head>

<body>
   <div id="divInfoToReturn"><?php echo $sInfo ?></div>
</body>

</html>

I have commented each line to show you what is going on with each segment of code. Basically, without repeating the comments, if there is an error, then an error message is stored to $sInfo. If it is successful, then the chat is stored to $sInfo. Regardless, $sInfo is then passed to the <div> tag as an innerHTML, which will be called by the requestChatInfo() function in index.htm.
__________________________________________________

Finally, is the sendchat.php page. This page takes what you put in the text input boxes, gets them from the variables passed to the hiddenFrame, and runs an SQL query on it to either show an error message or input the data and update the chat screen.

<html>
<head>
<title>Send Chat Data</title>
<?php
   $sName = $_POST["txtName"]; //Input Box for Name passed from index.htm
   $sChat = $_POST["txtChat"]; //Input Box for Say passed from index.htm

   //Did the person enter a name in the box?
   //If not, call them Guest
   if(!$_POST["txtName"])
   {
      $sName = "Guest";
   }
   
   //Initiate status message for errors.
   $sStatus = "";
   
   //enter the same info from getchatdata.php for connecting
   $sDBServer = "localhost"; //your server name, can usually be localhost,
                        //unless you're connecting across sites.
   $sDBName = "ajax_chat_db"; //your database name
   $sDBUsername = "ajax_chat_user123"; //user name to connect to the database
   $sDBPassword = "sdf07hw2df"; //password for user to connect to the database
   
   //SQL Statement to enter the data into the database.
   //No spaces, and backquotes for column header declaration
   //and single quotes for data. Remember that `id` is auto-incremented
   //so we don't need a value for that section, just to declare it.
   $sSQL = "INSERT INTO ajax_chat(`ajaxchat_username`,`ajaxchat_text`)" .
         " values ('$sName','$sChat')";
   
   //Connect to the database
   $oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword);
   @mysql_select_db($sDBName) or $sStatus="Unable to open database";
   
   //Did it work? If not create an error message
   if(!$oResult = mysql_query($sSQL))
   {
      $sStatus = "<font color=\"red\">An error occurred while sending; chat not sent.</font>";
   }
   
   //Buh-bye now...g'bye...byebye now.
   mysql_close($oLink);
?>
   <script type="text/javascript">
      window.onload = function ()
      {
         parent.saveResult("<?php echo $sStatus ?>");
         parent.clearChatBox();
      }
   </script>

</head>

<body>
</body>

</html>

I have also commented this code in the php section, so I won't bother to repeat myself here. There is no body for this page in html, only the header info where there is a javascript call to the window.onload event.
When the window finishes loading, it calls the saveResult() function and passes it the $sStatus variable to be displayed on index.htm. If there is no error message, then there will be nothing displayed.
Then it calls the clearChatBox() function to clear the Say box so that you can continue typing like normal.

Now, load them all up to your server, and call it in Firefox or IE, and see if it works. Go here to see a demo verison. I'll be adding more functionality to this as I create it for the homepage of the-spot.net, and integrate it with the phpbb forums. I'm new to AJAX, therefore I may not have the most optimized code possible, but I'm open for suggestions for streamlining and security if you would like to add to the project. I'll comment your credits into the code. Also, you can feel free to bookmark this site and check back for update posts for this project. I don't offer any personal tech support for this (because to do so would be extremely trying on my time and availability), and you may have to modify it to meet your server's requirements. If you do use this though, and find it useful, all I ask is that you give me a little credit for the work I put into it (instead of doing homework) :-).

A side feature is that if you save the url to your Bookmark Toolbar of FF (or Links Toolbar in IE) you can load the page into the Sidebar of FF and IE. In Firefox just drag the url to the Bookmark Toolbar, and right click on the button > Properties > Check "Load link in sidebar". For IE users (hopefully there are none) create a new shortcut with the url:

javascript:Q='';if(top.frames.length==0)Q=document.selection.createRange().text;
void(_search=open('http://your.domain.com/page.htm?popuptitle='+escape(document.title)
+'&popupurl='+escape(location.href)+'&text='+escape(Q),'_search'))

and change the web address that's bolded.

By [[Neo]]

I am a web programmer, system integrator, and photographer. I have been writing code since high school, when I had only a TI-83 calculator. I enjoy getting different systems to talk to each other, coming up with ways to mimic human processes using technology, and explaining how complicated things work.

Of my many blogs, this one is purely about the technology projects, ideas, and solutions that I have come across in my internet travels. It's also the place for technical updates related to my other sites that are part of The-Spot.Network.

2 replies on “Project: tsnXchat”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.