Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

Build a Chatroom with Flash, Adobe AIR and PHP

by

"The primary use of a chat room is to share information via text with a group of other users." - Wikipedia. During this Premium tutorial, I'll show you how to create a chatroom using Flash, AIR, PHP, MySQL and XML.


The User Interface

We'll start by creating the user interface. You can copy my UI to the pixel, or you can create your own design.


Step 1: Setting up the Document

Open Flash and create a new 'Flash File (Adobe AIR)' document. Save the file into a new folder as 'chatroom.fla'. Next, create a new 'ActionScript' file and save that as 'chatroom.as' and save it in the new folder.



Step 2: Linking the Files

In Flash, navigate to the 'Properties' panel. In the text field type in 'chatroom' and hit enter. This will link the actionscript file (which we will soon create) and Flash document together. You can find a complete tutorial on how to set up the Document class here.



Step 3: Setting up the Stage and Background

In the properties panel, set the size of the stage to 230x400 pixels. Next, select the rectangle tool. Set the rounded corners property to 5 pixels. Give it a fill color of white and give it any alpha number you like -- I set mine to 10%. Also, give it a black stroke that is 1 pixel wide. Draw out a rectangle on the stage that is 245 pixels wide and 400 pixels in height. Press F8 to convert it to a movieclip. Give it a name of 'background' and an instance name of 'background'. In the filters panel, add a glow filter that has a blur of 24, strength of 66%, and set the quality to high. Next add a drop shadow filter. Give it a blur of 4, strength of 50%, high quality, 90 angle and set the distance to 2.



Step 4: Creating the Login/Sign up Panel

In the components panel, drag out a copy of the List component onto the stage. This will contain the list of users that are currently online. Give it an instance name of 'uList'. Set the width property to 200 and the height to 189. Next, grab the text tool. With the static text setting, draw out a text field above the new List component. In the text field, enter 'Users online'.

With the text tool still selected, draw out another text field below the List component and enter 'Username'. Below that text field, draw out another text field. The new text field should say 'Password'. Underneath the 'Username' text field, create a new input text field. Give it an instance name of 'user'. Set the width to 200 and the height to 17. Set the text color to black and font size to 12. Create another input text field with the same settings underneath the 'Password' text field. Give the new input text field an instance name of 'pass', and set the Line type to 'Password'. This will make the characters entered appear as asterisks.



Step 5: Finishing the Login/Sign up Panel

Next select the rectangle tool. Give it a rounded corner of 5, a color of #00CC00 and no stroke. Draw out a rectangle that has a width of 122 and height of 43. Convert the rectangle to a new movieclip and give it a name and instance name of 'button'. Double click on the button to enter edit mode.

Inside the button movieclip, create a new layer. Create a new dynamic text field. Give it an instance name of 'dyText', width of 110, height of 36, font size of 26 and white color, and set it to bold. Exit the edit mode and get back to the stage.

Select the button, and navigate to the filters panel. Give the button a drop shadow with a blur of 2, strength of 66%, high quality, an angle of 90 and distance of 1. Lastly, drag out a copy of the Checkbox component. Place it underneath the button movieclip. Give it an instance name of 'remember'. In the parameters panel, set the label to 'Remember'. Next, copy the Checkbox, and paste a new instance right next to the previous one. Give the new Checkbox an instance name of 'signUp'. Set its label property to 'Sign up'. Select all the elements and convert them to one big movieclip. Give it an instance name of 'screen1.'



Step 6: Creating the Rooms Panel

To the right of the 'screen1' movieclip, draw out a static text box, and give it a value of 'Rooms online'. Below the text field, drag a new List component onto the stage to contain the rooms. Give it an instance name of 'rList'. Set the width to 200 and the height to 189. Next create another static text field below the List component. Set it to say 'Room'. Underneath that text field, create a new input text field. Give it an instance name of 'table', a width of 200 and height of 17. Set the font size to 12 and color to black.



Step 7: Finishing the Rooms Panel

Drag another copy of the button movieclip onto the stage. Give it an instance name of 'button2' and place it under the 'rList' component. In the filters panel, apply the same drop shadow settings that were applied to the 'button1' movieclip. This will be used to enter the selected room.

Now, drag a copy of the Checkbox component onto the stage. Give it an instance name of 'createRoom'. The user will check this box to indicate that they wish to create a new room instead of entering an existing one.

Next, select the rectangle tool again. Give it a fill color of #BA0101 and no stroke. With the rounded corners still set at 5, draw out a rectangle that is 71 pixels wide and 25 pixels high. Convert the rectangle into a movieclip and give it an instance name of 'out'. Double click to enter the edit mode of the new 'out' movieclip. Create a second layer on top. Select the text tool and draw a dynamic text field. The next text field should be 63 in width and 18 in height. Give it an instance name of 'dyText'. Exit the edit mode and give the button a new drop shadow filter with the same properties as the other two green buttons. This red button will be used to go back to the login screen.

Select all the new elements and convert them to a movieclip. Give the movieclip an instance name of 'screen2'.



Step 8: Creating the Chatroom Panel

To the right of the 'screen2' movieclip, create a new static text field that says 'Current chat'. Underneath the text field, drag out a copy of the TextArea component. Give it a width of 200, a height of 123 and an instance name of 'cList'.

Next, drag out another copy of the List component and place it under the new TextArea. Give the new List component an instance name of 'uList'. This will hold the list of users currently in the chatroom.

Create another static text field under the 'uList' component that reads 'Comment'. Now, create an input text field underneath the 'Comment' text field. Give it an instance name of 'comm', a width of 200, height of 17, font size of 12 and color of black. Drag another copy of the green button onto the stage. Give it an instance name of 'button3'. Finally, drag a copy of the red button onto the stage and give it an instance name of 'back'. Select all of the new elements and convert them, as a group, to a movieclip with an instance name of 'screen3'.



Step 9: Creating the Error Panel

This will slide in whenever there's a problem (for example, if the user enters an incorrect password).

On the stage, create a new layer. Double click on the 'background' movieclip to enter its edit mode. Select the background shape and copy it. Navigate back up to the stage, and, on the new layer, paste the new shape to the left of the 'screen1' movieclip. Give the shape a color of black and alpha of 50%. Convert the shape into a movieclip and give it an instance name of 'errorPage'. Double click on the 'errorPage' movieclip to edit.

Inside the movieclip, create a new layer. Select the text tool and drag out a new dynamic text field. Give it a width of 120, a height of 26, font size of 20, white color and bold font. Align the text field to the vertical and horizontal center of the background shape.



Step 10: Finishing up the UI

Create a new layer on the stage for the exit button. Since we always want that button on top of everything else, move the new layer to the top of the stack. Select the text tool, and make an 'X'. Convert that to a movieclip with an instance name of 'closer'. Double click on it.

Create a new layer inside the 'closer' movieclip. Place the new layer underneath the layer with the 'X' text field. Draw out a square that is 16 pixels wide and 16 pixels in height. Give the square a fill of any color and an alpha of 0. Give the 'closer' movieclip a new drop shadow filter with a blur of 2, strength of 66%, high quality, angle of 90 and a distance of 1. Move it closer to the top right corner of the background movieclip.



Basic Application Code

The next seven steps deal with setting up the client application, before we get to the server-side PHP.


Step 11: Starting to Code

Open up the blank actionscript file that we created. Here is the skeleton for the document class we'll be using.

 
package { 
	import flash.display.Sprite; 
 
	public class chatroom extends Sprite 
	{ 
		public function chatroom() 
		{ 
 
		} 
	} 
}

Step 12: The Imports

Here are all the imports we'll be using for this project. I will be using the Tweener class which can be found here

 
	import caurina.transitions.*;	//this is Tweener 
	 
	import flash.data.EncryptedLocalStore; 
	import flash.desktop.NativeApplication; 
	import flash.display.MovieClip; 
	import flash.display.SimpleButton; 
	import flash.display.Sprite; 
	import flash.events.Event; 
	import flash.events.InvokeEvent; 
	import flash.events.KeyboardEvent; 
	import flash.events.MouseEvent; 
	import flash.events.TimerEvent; 
	import flash.net.URLLoader; 
	import flash.net.URLRequest; 
	import flash.net.URLRequestMethod; 
	import flash.net.URLVariables; 
	import flash.text.TextField; 
	import flash.utils.ByteArray; 
	import flash.utils.Timer;

Step 13: Global Variables

Here we are defining our global variables. We'll need to keep track of the user, the room the user is in, and their newest post in the chatroom. We also put the location of the most used PHP files into some constants.

 
package { 
	import caurina.transitions.*; 
	 
	import flash.data.EncryptedLocalStore; 
	import flash.desktop.NativeApplication; 
	import flash.display.MovieClip; 
	import flash.display.SimpleButton; 
	import flash.display.Sprite; 
	import flash.events.Event; 
	import flash.events.InvokeEvent; 
	import flash.events.KeyboardEvent; 
	import flash.events.MouseEvent; 
	import flash.events.TimerEvent; 
	import flash.net.URLLoader; 
	import flash.net.URLRequest; 
	import flash.net.URLRequestMethod; 
	import flash.net.URLVariables; 
	import flash.text.TextField; 
	import flash.utils.ByteArray; 
	import flash.utils.Timer; 
 
	public class chatroom extends Sprite 
	{ 
    	private var _user:String; 
        private var _room:String; 
        private var _id:int; 
        private var tracker:int; 
        private var exiting:int; 
        private static const URL:String = "URL_TO_PHP_FOLDER" 
        private static const USERS:String = URL + "user.php"; 
        private static const ROOMS:String = URL + "rooms.php"; 
        private static const COMMENTS:String = URL + "comment.php"; 
		 
		public function chatroom() 
		{ 
			 
		} 
	}

Step 14: The INVOKE Event

The first thing we do is listen for the INVOKE event. Whenever the app starts, it will fire the INVOKE event. When it does fire, we will check the EncryptedLocalStore for login credentials (in the next step).

 
package { 
	import caurina.transitions.*; 
	 
	import flash.data.EncryptedLocalStore; 
	import flash.desktop.NativeApplication; 
	import flash.display.MovieClip; 
	import flash.display.SimpleButton; 
	import flash.display.Sprite; 
	import flash.events.Event; 
	import flash.events.InvokeEvent; 
	import flash.events.KeyboardEvent; 
	import flash.events.MouseEvent; 
	import flash.events.TimerEvent; 
	import flash.net.URLLoader; 
	import flash.net.URLRequest; 
	import flash.net.URLRequestMethod; 
	import flash.net.URLVariables; 
	import flash.text.TextField; 
	import flash.utils.ByteArray; 
	import flash.utils.Timer; 
 
	public class chatroom extends Sprite 
	{ 
		private var _user:String; 
		private var _room:String; 
		private var _id:int; 
		private var tracker:int; 
		private var exiting:int; 
		private static const URL:String = "URL_TO_PHP_FOLDER" 
		private static const USERS:String = URL + "user.php"; 
		private static const ROOMS:String = URL + "rooms.php"; 
		private static const COMMENTS:String = URL + "comment.php"; 
 
		public function chatroom() 
		{ 
			NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke); 
		} 
	}

Step 15: Checking the EncryptedLocalStore

When the INVOKE event is fired, the EncryptedLocalStore will check for an object called 'creds' (short for 'credentials'). If it finds that object, it will pass the login credentials to the appropriate text fields. After that, we call the init function.

 
private function onInvoke(event:InvokeEvent):void 
{ 
	var value:ByteArray = EncryptedLocalStore.getItem("creds"); 
	if(value != null) 
	{ 
		var object:Object = value.readObject(); 
		screen1.user.text = object.user; 
		screen1.pass.text = object.password; 
		screen1.remember.selected = object.remember; 
	} 
	init(); 
}

Step 16: The init Function

Here we are setting some properties and adding some event listeners. We also create masks dynamically for our screen movieclips. We also create a new Timer so that we can check the database every three seconds for new comments, new users or new rooms. We're also listening for when the user goes idle and when the user returns, using NativeApplication.

 
private function init():void 
{ 
	screen1.mask = createMask();	//we'll create this function in the next step 
	screen2.mask = createMask(); 
	screen3.mask = createMask(); 
	errorPage.mask = createMask(); 
	 
	var timer:Timer = new Timer(3000);	//check for new activity every three seconds 
	timer.addEventListener(TimerEvent.TIMER, onTimer); 
	timer.start(); 
	 
	tracker = 0;	//keeps track of where the user is in the app. see Step 36 
	screen1.button.addEventListener(MouseEvent.CLICK, logOn); 
	 
	NativeApplication.nativeApplication.idleThreshold = 120;	//after 120 seconds, a USER_IDLE event will be dispatched 
	NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExiting); 
	closer.addEventListener(MouseEvent.CLICK, closerClick); 
	NativeApplication.nativeApplication.addEventListener(Event.USER_IDLE, onUser); 
	NativeApplication.nativeApplication.addEventListener(Event.USER_PRESENT, onUser);	//if the user has been idle, but then starts using the mouse/keyboard again, a USER_PRESENT event will be dispatched 
	 
	background.addEventListener(MouseEvent.MOUSE_DOWN, backgroundDown); 
	exiting = 0; 
	loadSomething(USERS, userLoaded);	//loads users, rooms, or chat 
	 
	//the rest of this function just sets up the UI 
	screen1.button.dyText.text = "Start"; 
	screen2.button2.dyText.text = "Go"; 
	screen3.button3.dyText.text = "Say"; 
	screen2.out.dyText.text = "Log out"; 
	screen3.back.dyText.text = "Leave"; 
	screen2.out.dyText.mouseEnabled = false; 
	screen3.back.dyText.mouseEnabled = false; 
	screen1.button.dyText.mouseEnabled = false; 
	screen2.button2.dyText.mouseEnabled = false; 
	screen3.button3.dyText.mouseEnabled = false; 
	screen1.button.buttonMode = screen2.button2.buttonMode = screen3.button3.buttonMode = screen2.out.buttonMode = screen3.back.buttonMode = true; 
}

Step 17: Creating the Dynamic Masks

Since we're using components and different type of text fields, we have to dynamically create the masks for the screen movieclips. We create a rounded rectangle that is the same size as the 'background' movieclip. We move the rectangle to the top of the display list and return the Sprite object.

 
private function createMask():Sprite 
{ 
	var rect:Sprite = new Sprite(); 
	rect.graphics.beginFill(0x000000, 1); 
	rect.graphics.drawRoundRect(0, 0, 219, 392.6, 5, 5); 
	rect.graphics.endFill(); 
	rect.x = 5.5; 
	rect.y = 3.8; 
	this.addChildAt(rect, this.numChildren-1); 
	return rect; 
}

The Server-Side Code

Next we will switch over to the back end: PHP and MySQL on your server.


Step 18: Setting up MySQL

The first step is to create a database. I use 'phpmyadmin' to do all my database and table setup. Log in to your account. In the 'Create new database' area, enter in 'chatroom' for the database name and click 'Create'.


When the database is successfully created, we will need to add a table that keeps track of all our users. In the 'Create new table on database chatroom', name the table 'chat_room_users', and in the 'Number of fields' section, give it a value of 4 and click 'Go'.


After you've clicked the 'Go' button, you will have to fill out the column detail. We'll need to store an ID, a username and a password for each user, as well as a flag to say whether they are currently online.

Set the first column name to 'id', set its type to 'INT', set it to auto-increment, and set it as the primary key. The name column should be named 'user'. The type should be 'VARCHAR' with a 'Length/Value' of 40. The third column should be named 'pass'. The type should be 'VARCHAR' with a 'Length/Value' of 40. The final column should be called 'on' with a type of 'VARCHAR', and a 'Length/Value' of 2.


If you are using something other than 'phpmyadmin', here is the MySQL code to set up the database.

 
#Create database 
CREATE DATABASE `chatroom`; 
 
 
#Create table 
CREATE TABLE `chatroom`.`chat_room_users` ( 
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , 
`user` VARCHAR( 40 ) NOT NULL , 
`pass` VARCHAR( 40 ) NOT NULL , 
`on` VARCHAR( 2 ) NOT NULL 
) ENGINE = MYISAM;

Step 19: Switching to PHP

First we will need to set up our database access. Create a new PHP document, paste in the following code, replace the login credentials with your own, and save it to your webserver as 'chat_require.php'.

 
<?php 
$username = "USERNAME"; 
$password = "PASSWORD"; 
$hostname = "HOSTNAME"; 
 
$dbhandle = mysql_connect($hostname, $username, $password) or die("Unable to connect to MySQL"); 
 
$selected = mysql_select_db("chatroom",$dbhandle) or die("Could not select examples"); 
?>

Step 20: Showing Users That are Online

This is where we will show a visitor who is currently online. We will need to use our database login information. Next, create a new PHP file and save it to your web server as 'user.php'. Then we will select all the users from the 'chat_room_users' table on our database. The PHP will echo out XML for Flash to read.

 
<?php 
require_once 'chat_require.php'; 
 
$query = "SELECT user FROM `chat_room_users` WHERE `on` = 1"; 
 
$result = mysql_query($query); 
 
header ("Content-Type: text/xml"); 
header("Cache-Control: no-cache, must-revalidate"); 
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); 
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; 
echo "<users>\n"; 
if (mysql_num_rows($result)) 
{ 
	while ($row = mysql_fetch_row($result)) 
	{ 
		echo "<user>" . $row[0] . "</user>\n"; 
	} 
} 
else 
{ 
	echo "<user>There are no users online.</user>\n"; 
} 
echo "</users>"; 
?>

The XML will look like this:

 
<?xml version="1.0" encoding="utf-8"?> 
<users> 
	<user>Jack</user> 
	<user>Ben</user> 
	<user>Jacob</user> 
</users>

Or, if no-one is online, like this:

 
<?xml version="1.0" encoding="utf-8"?> 
<users> 
	<user>There are no users online.</user> 
</users>

Step 21: Logging in the User

Next we'll create the login logic. Create a new PHP file, and save it to your server as 'logon.php'. We'll need to require our database credentials. Next we check to see if the user, pass, and log variables are set. If they've been received from Flash, we sanitize the variables, and check the database for the user. We check to see if the username is already in the database. Also, we're looking to see if the user is trying to create a new username. When the logic is complete, we send back a numeric value for Flash to parse.

 
<?php 
require_once 'chat_require.php'; 
 
if(isset($_POST['user']) && isset($_POST['pass']) && isset($_POST['log'])) 
{ 
 
	$user = sanitize($_POST['user']); 
	$pass = sanitize($_POST['pass']); 
	$log = sanitize($_POST['log']); 
	$sign = sanitize($_POST['sign']); 
	 
	$query = "SELECT user FROM `chat_room_users` WHERE `user` = '$user'"; 
	$result = mysql_query($query) or die(mysql_error()); 
 
	if(mysql_num_rows($result)) 
	{ 
		if($sign === 'true') 
		{ 
			//User exists 
			echo 6; 
		} 
		else 
		{ 
			$query = "SELECT user, pass FROM `chat_room_users` WHERE `user` = '$user' AND `pass` = '$pass'"; 
			$re = mysql_query($query) or die(mysql_error()); 
			if(mysql_num_rows($re)) 
			{ 
				$query = "UPDATE `chat_room_users` SET `on` = '$log' WHERE `user` = '$user' AND `pass` = '$pass'"; 
				$r = mysql_query($query) or die(mysql_error()); 
				if($r) 
				{ 
					if($log === "1") 
					{ 
						//Logged in 
						echo 1; 
					} 
					else 
					{ 
						//Logged out 
						echo 5; 
					} 
				} 
				else 
				{ 
					echo 0; 
				} 
			} 
			else 
			{ 
				//Wrong Password 
				echo 4; 
			} 
		} 
	} 
	elseif($sign === 'true') 
	{ 
		$query = "INSERT INTO `chat_room_users` VALUES ('', '$user', '$pass', '1')"; 
		$result = mysql_query($query) or die(mysql_error()); 
		if($result) 
		{ 
			//Account created 
			echo 2; 
		} 
		else 
		{ 
			echo 0; 
		} 
	} 
	else 
	{ 
		//User doesn't exist 
		echo 3; 
	} 
	 
} 
 
function sanitize($string) 
{ 
	$string = mysql_real_escape_string($string); 
	$string = strip_tags($string); 
	$string = filter_var($string, FILTER_SANITIZE_STRING); 
	$string = trim($string); 
	return $string; 
} 
?>

Step 22: Picking a Room

Now that the user has logged in, we'll give them access to the chatrooms. Create a new PHP file, save it to your web server as 'rooms.php'. We require our database credentials of course. Then we show all the tables that have been created on the database. The only table that we hide is our users table. We take the result and echo out some XML for Flash.

The first time the app is used there will be no tables in the database apart from the users table, as no rooms will have been created. We'll resolve this in the next step.

 
<?php 
require_once 'chat_require.php'; 
 
$query = "SHOW TABLES FROM chatroom"; 
 
$result = mysql_query($query); 
	 
if (mysql_num_rows($result)) 
{ 
	header ("Content-Type: text/xml"); 
	header("Cache-Control: no-cache, must-revalidate"); 
	header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); 
	echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; 
	echo "<rooms>\n"; 
	while ($row = mysql_fetch_row($result)) 
	{ 
		if($row[0] === "chat_room_users") 
		{ 
			// 
		} 
		else 
		{ 
			echo "<room>" . $row[0] . "</room>\n"; 
		} 
	} 
	echo "</rooms>"; 
} 
?>

Step 23: Creating a Room

The user also has the option to create a room. First, create a new PHP file, and save it to your server as 'create.php'. We will need to sanitize our variables. Next, we query the database to see if the user is trying to create a room that already exists. If it doesn't we create a new table (not a new row in an existing table). Again, we send integers back to Flash.

 
<?php 
require_once 'chat_require.php'; 
 
if(isset($_POST['table']) && isset($_POST['create'])) 
{ 
	$table = sanitize($_POST['table']); 
	$create = sanitize($_POST['create']); 
	$user = sanitize($_POST['user']); 
 
	$query = "SELECT * FROM $table"; 
	$result = mysql_query($query); 
 
	if($create === 'true') 
	{ 
		if(!$result) 
		{ 
			$query = "CREATE TABLE `$table` (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), user VARCHAR(40) NOT NULL, comment VARCHAR(120) NOT NULL, logged VARCHAR(2) NOT NULL)"; 
			$result = mysql_query($query) or die(mysql_error()); 
			if($result) 
			{ 
				echo 1; 
			} 
			else 
			{ 
				echo 0; 
			} 
		} 
		else 
		{ 
			echo 2; 
		} 
	} 
	else 
	{ 
		if(!$result) 
		{ 
			echo 3; 
		} 
		else 
		{ 
			echo 1; 
		} 
	} 
} 
 
function sanitize($string) 
{ 
	$string = mysql_real_escape_string($string); 
	$string = strip_tags($string); 
	$string = filter_var($string, FILTER_SANITIZE_STRING); 
	$string = trim($string); 
	return $string; 
} 
?>

Step 24: Getting the User's Newest Comment

When the user logs in, we don't want to show them the entire chat history. Since every time a user enters a room they automatically announce their presence, that results as a new entry into the database table. We will need to find the user's latest entry as a starting point for them to start receiving the chat. We will use the 'MAX' MySQL function to find it and send it back to Flash. Copy the code below and save it to your web server as 'enter.php.'

 
<?php 
 
require_once 'chat_require.php'; 
 
if(isset($_POST['comment']) && isset($_POST['table']) && isset($_POST['user'])) 
{ 
	$user = sanitize($_POST['user']); 
	$comment = sanitize($_POST['comment']); 
	$logged = sanitize($_POST['logged']); 
	$table = sanitize($_POST['table']); 
	$query = "INSERT INTO `$table` VALUES ('', '$user', '$comment', '$logged')"; 
	$result = mysql_query($query) or die(mysql_error()); 
	if($result) 
	{ 
		$query = "SELECT MAX(id) FROM `$table` WHERE `user` = '$user'"; 
		$r = mysql_query($query) or die(mysql_error()); 
		if($r) 
		{ 
			while($row = mysql_fetch_row($r)) 
			{ 
				echo $row[0]; 
			} 
		} 
	} 
} 
 
function sanitize($string) 
{ 
	$string = mysql_real_escape_string($string); 
	$string = strip_tags($string); 
	$string = filter_var($string, FILTER_SANITIZE_STRING); 
	$string = trim($string); 
	return $string; 
} 
 
?>

Step 25: Posting a Comment

Finally, we are at the point where the user can start to chat. We use this page to check if the user has submitted a comment. If they have said something, we put it into our table. We also use this file to echo out the chat since the user entered the room. This page also shows which user is currently in the room.

 
<?php 
 
require_once 'chat_require.php'; 
 
$table = sanitize($_POST['table']); 
$id = sanitize($_POST['id']); 
 
if(isset($_POST['comment']) && isset($_POST['table']) && isset($_POST['user'])) 
{ 
	$user = sanitize($_POST['user']); 
	$comment = sanitize($_POST['comment']); 
	$logged = sanitize($_POST['logged']); 
	$query = "INSERT INTO `$table` VALUES ('', '$user', '$comment', '$logged')"; 
	$result = mysql_query($query) or die(mysql_error()); 
} 
 
$query = "SELECT user, comment FROM `$table` WHERE `id` > $id"; 
$r = mysql_query($query) or die(mysql_error()); 
if($r) 
{ 
	header("Content-Type: text/xml"); 
	header("Cache-Control: no-cache, must-revalidate"); 
	header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); 
	echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; 
	echo "<comments>\n"; 
	while ($row = mysql_fetch_row($r)) 
	{ 
		echo "<comment>\n"; 
		echo "<user>" . $row[0] . "</user>\n"; 
		echo "<text>" . $row[1] . "</text>\n"; 
		echo "</comment>\n"; 
	} 
	mysql_free_result($r); 
	$query = "SELECT DISTINCT user FROM $table"; 
 
	$r = mysql_query($query) or die(mysql_error()); 
	if($r) 
	{ 
		while ($row = mysql_fetch_row($r)) 
		{ 
			$user = $row[0]; 
			$query = "SELECT user, logged FROM $table WHERE user = '$user' ORDER BY id DESC LIMIT 1"; 
			$result = mysql_query($query); 
			if($result) 
			{ 
				while($tr = mysql_fetch_row($result)) 
				{ 
					 
					if($tr[1] === '1') 
					{ 
						echo "<users>" . $tr[0] . "</users>/n"; 
						break; 
					} 
					else 
					{ 
						// 
					} 
				} 
			} 
			else 
			{ 
				// 
			} 
		} 
	} 
	else 
	{ 
		// 
	} 
	echo "</comments>"; 
} 
else 
{ 
	// 
} 
 
function sanitize($string) 
{ 
	$string = mysql_real_escape_string($string); 
	$string = strip_tags($string); 
	$string = filter_var($string, FILTER_SANITIZE_STRING); 
	$string = trim($string); 
	return $string; 
} 
 
?>

Connecting the Client to the Back End

Now it's time to make the chatroom connect to the server so that it can be truly interactive.


Step 26: Back to Flash

When the user first goes to log in to the chat area, they will click the 'button1' movieclip. When that button is clicked, it will call the 'logOn' function. All that function does is call the 'logger' function. The 'logger' function will do some simple checking to see if the required fields are filled in. Also, it will load the 'logon.php' file.

 
private function logOn(event:MouseEvent):void 
{ 
	logger(); 
} 
private function logger(log:int = 1):void 
{ 
	if(log === 1) 
	{ 
		if(screen1.user.text.search(/[a-zA-Z0-9]/g) === -1)	//make sure the user entered a valid name 
		{ 
			errorPage.dyText.text = "Enter a user name"; 
			tweenerTimer(); 
			return; 
		} 
		if(screen1.pass.text.search(/[a-zA-Z0-9]/g) === -1)	//make sure the user entered a valid password 
		{ 
			errorPage.dyText.text = "Enter a password"; 
			tweenerTimer(); 
			return; 
		} 
	} 
	 
	//this section loads the logon.php page we created earlier: 
	var url:URLLoader = new URLLoader(); 
	var req:URLRequest = new URLRequest(URL + "logon.php"); 
	var vars:URLVariables = new URLVariables(); 
	req.method = URLRequestMethod.POST; 
	vars.user = screen1.user.text; 
	vars.pass = screen1.pass.text; 
	vars.log = log; 
	vars.sign = screen1.signUp.selected; 
	req.data = vars; 
	url.addEventListener(Event.COMPLETE, loggingOn);	//when logon.php has loaded, call loggingOn() 
	url.load(req); 
	 
	_user = screen1.user.text; 
}

Step 27: The User is Logging in

When the user tries to log in, we send the credentials to the database to check whether they have access. We use the numbers that PHP returns to do some checking. If the number returned is a 1 or 2, the user is logged in. If a different number is returned, we use the 'errorPage' movieclip to handle it. This function is also the last function that we call when the user is closing the application. After we've told the database that the user is leaving the chat area, the application will close. This function also populates the room list on 'screen2'.

 
private function loggingOn(event:Event):void 
{ 
	screen1.signUp.selected = false; 
	switch(event.target.data) 
	{ 
		case "0" : 
			//Error -- shouldn't ever receive this number 
		break; 
		case "1" : 
		case "2" : 
			tracker = 1;	//keeps track of where the user is in the app. see Step 36 
			Tweener.addTween(screen1, {x: -screen1.width - 50, time:1});	//slide the current screen out... 
			Tweener.addTween(screen2, {x: (stage.stageWidth>>1) - (screen2.width>>1), time:1});	//...and slide the new screen in. 
			 
			//load the list of rooms using rooms.php 
			var url:URLLoader = new URLLoader(); 
			url.addEventListener(Event.COMPLETE, popRList); 
			url.load(new URLRequest(ROOMS)); 
			screen2.button2.addEventListener(MouseEvent.CLICK, room); 
		break 
		case "5" : 
			//Log out 
		break; 
		case "3" : 
		case "4" : 
		case "6" : 
			var string:String = event.target.data; 
			switch(string) 
			{ 
				case "3" : 
				errorPage.dyText.text = "User doesn't exist"; 
				break; 
				case "4" : 
				errorPage.dyText.text = "Wrong Password"; 
				break; 
				case "6" : 
				errorPage.dyText.text = "User already exists"; 
				break; 
			} 
			tweenerTimer();	//slide the error screen in 
		break; 
	} 
	loadSomething(USERS, userLoaded); 
	if(exiting === 1) 
	{ 
		if(screen1.remember.selected) 
		{ 
			//if the user checked the "remember" box on the login screen, this saves their name and password to the EncryptedLocalStore 
			var value:ByteArray = new ByteArray(); 
			value.writeObject({user:screen1.user.text, password:screen1.pass.text, remember:screen1.remember.selected}); 
			EncryptedLocalStore.setItem("creds", value); 
		} 
		else 
		{ 
			EncryptedLocalStore.reset(); 
		} 
		NativeApplication.nativeApplication.exit(); 
	} 
}

Step 28: Loading the Available Rooms

The 'popRList' function handles the xml that is returned from the PHP file. If the user sees a room that is already created, they can simply click on the list and the 'room' text field gets populated with their selection. The user is also able to log out here if they would like to sign in as a different user.

 
private function popRList(event:Event):void 
{ 
	screen2.out.addEventListener(MouseEvent.CLICK, outClick); 
	var xml:XML = new XML(event.target.data); 
	var list:XMLList = xml..room;	//creates an XMLList from all the <room> nodes in the XML returned by rooms.php 
	var len:int = list.length(); 
	screen2.rList.removeAll(); 
	for(var i:int = 0; i<len; i++)	//loops through all the <room> nodes in the XMLList 
	{ 
		screen2.rList.addItem({label:list[i], data:list[i]}); 
	} 
	screen2.rList.addEventListener(Event.CHANGE, onChange); 
}

Step 29: Logging Out

If the user decides that they would like to log in under a different username, they can click on the 'out' button on 'screen2'. This will call the 'logger' function again except it will pass a zero to the database. When a zero is passed, the user is logged out, and we return to 'screen1.'

 
private function outClick(event:MouseEvent):void 
{ 
	logger(0); 
	Tweener.addTween(screen2, {x: stage.stageWidth + 50, time:1}); 
	Tweener.addTween(screen1, {x: (stage.stageWidth>>1) - (screen1.width>>1), time:1}); 
	tracker = 0;	//keeps track of where the user is in the app. see Step 36 
	loadSomething(USERS, userLoaded); 
}

Step 30: Entering Room

When the user decides on a room they want to enter, the 'room' function is called. If the user is trying to create a new room, we do some simple checking to ensure the text field is filled in. We also replace any spaces with underscores.

 
private function room(event:MouseEvent):void 
{ 
	if(screen2.table.text.search(/[a-zA-Z0-9]/g) === -1) 
	{ 
		errorPage.dyText.text = "Select a room"; 
		tweenerTimer(); 
		return; 
	} 
	screen3.cList.text = ""; 
	screen3.comm.text = ""; 
	var url:URLLoader = new URLLoader(); 
	var req:URLRequest = new URLRequest(URL + "create.php"); 
	var vars:URLVariables = new URLVariables(); 
	req.method = URLRequestMethod.POST; 
	vars.table = screen2.table.text.replace(/[\s]/gi, "_"); 
	vars.create = screen2.createRoom.selected; 
	vars.user = _user; 
	req.data = vars; 
	url.addEventListener(Event.COMPLETE, roomed); 
	url.load(req); 
	_room = screen2.table.text; 
}

Step 31: Handling the Room Response

When Flash gets the response from PHP, we use a switch statement to determine the logic. If the user successfully enters the room, we add some event listeners, and we load the 'enter.php' file.

 
private function roomed(event:Event):void 
{ 
	screen2.createRoom.selected = false; 
	switch(event.target.data) 
	{ 
		case "0" : 
			//Error 
		break; 
		case "1" : 
			tracker = 2;	//keeps track of where the user is in the app. see Step 36 
			Tweener.addTween(screen2, {x: -screen2.width - 50, time:1}); 
			Tweener.addTween(screen3, {x: (stage.stageWidth>>1) - (screen3.width>>1), time:1}); 
			screen3.button3.addEventListener(MouseEvent.CLICK, commentClick); 
			this.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); 
			screen3.back.addEventListener(MouseEvent.CLICK, commentClick); 
			screen3.uList.addEventListener(Event.CHANGE, userClick); 
			 
			var url:URLLoader = new URLLoader(); 
			var req:URLRequest = new URLRequest(URL + "enter.php"); 
			var vars:URLVariables = new URLVariables(); 
			url.addEventListener(Event.COMPLETE, enteredRoom);	//see next step for this function 
			req.method = URLRequestMethod.POST; 
			vars.user = _user; 
			vars.comment = "has just entered the room"; 
			vars.logged = 1; 
			vars.table = _room; 
			req.data = vars; 
			url.load(req); 
		break; 
		case "2" : 
			errorPage.dyText.text = "Room already exists"; 
			tweenerTimer(); 
		break; 
		case "3" : 
			errorPage.dyText.text = "Room doesn't exist"; 
			tweenerTimer(); 
		break; 
	} 
}

Step 32: Entering the Room

When the user has entered the room, we have to get their newest post to determine how much of the conversation to display. We use the '_id' variable to track it. When the variable is set, we call the 'callComments' function.

 
private function enteredRoom(event:Event):void 
{ 
	_id = parseInt(event.target.data); 
	callComments(); 
}

Step 33: Getting the Comments From the Database

With this function, we will load the PHP file that will contain the XML of the chat. When we call this function, we say whether the user is logged in or logging out. Also, we pass it the user's comment. If the user hasn't said anything, we load just the XML and don't put anything in the database.

 
private function callComments(string:String = null, logged:int = 1):void 
{ 
	var url:URLLoader = new URLLoader(); 
	var req:URLRequest = new URLRequest(COMMENTS); 
	url.addEventListener(Event.COMPLETE, loadComments); 
	var vars:URLVariables = new URLVariables(); 
	req.method = URLRequestMethod.POST; 
	if(string != null)	//if the user said anything 
	{ 
		vars.user = _user; 
		vars.comment = string; 
		vars.logged = logged; 
	} 
	vars.table = _room; 
	vars.id = _id - 1; 
	req.data = vars; 
	url.load(req); 
}

Step 34: Displaying the Comments

In the comments XML, we have a list of all the comments by all the users since the current user has entered the room. We also populate the user list with the users currently in that room.

 
private function loadComments(event:Event):void 
{ 
	if(exiting) 
	{ 
		logger(0); 
	} 
	else 
	{ 
		var xml:XML = new XML(event.target.data); 
		var list:XMLList = xml..comment; 
		var llist:XMLList = xml..users; 
		var len:int = list.length(); 
		var i:int; 
		screen3.cList.text = ""; 
		for(i = 0; i<len; i++) 
		{ 
			screen3.cList.text += list[i].user + ": " + list[i].text + "\n";	//chat box 
		} 
		len = llist.length(); 
		screen3.uList.removeAll(); 
		for(i = 0; i<len; i++) 
		{ 
			screen3.uList.addItem({label:llist[i]});	//list of users 
		} 
	} 
}

Step 35: Sending a Comment to the Database

When the user has filled out their comment, they can click the 'button3' movieclip. When that happens, we call the 'callComments' function and pass it the user's message. However, we also use the 'commentClick' function for when the user wants to leave the room. We call the 'callComments' function but pass it a string saying that the user has left as well as a zero.

 
private function commentClick(event:Event):void 
{ 
	if(event != null) 
	{ 
		if(event.target.name === "back") 
		{ 
			Tweener.addTween(screen3, {x: stage.stageWidth + 50, time:1}); 
			Tweener.addTween(screen2, {x: (stage.stageWidth>>1) - (screen2.width>>1), time:1}); 
			callComments("has just left the room", 0); 
			screen3.cList.text = ""; 
			tracker = 1;	//keeps track of where the user is in the application. See next step. 
		} 
		else 
		{ 
			callComments(screen3.comm.text); 
			screen3.comm.text = ""; 
		} 
	} 
	else 
	{ 
		callComments(screen3.comm.text); 
		screen3.comm.text = ""; 
	} 
}

Step 36: Tracking the User

With these two functions we can track which PHP file we should be loading. The 'tracker' variable will keep track of where the user is in the application. Every three seconds, the timer will fire and call the 'loadSomething' function depending on the 'tracker' value.

 
private function loadSomething(string:String, func:Function):void 
{ 
	var url:URLLoader = new URLLoader(); 
	url.addEventListener(Event.COMPLETE, func); 
	url.load(new URLRequest(string)); 
} 
		 
private function onTimer(event:TimerEvent):void 
{ 
	switch(tracker) 
	{ 
		case 0 : 
			loadSomething(USERS, userLoaded); 
		break; 
		case 1 : 
			loadSomething(ROOMS, popRList); 
		break; 
		case 2 : 
			callComments(); 
		break; 
	} 
}

Step 37: Leaving the Application

When the user has decided to leave the app, we call the 'onExiting' function. When the 'closer' movieclip is clicked, we dispatch a new 'EXITING' event. When the 'onExiting' function is called, we tell the event to 'preventDefault'. What this means is that the event will not actually cause the default action of closing the app. We want to do some database stuff before the user can actually leave the application.

 
private function closerClick(event:MouseEvent):void 
{ 
	NativeApplication.nativeApplication.dispatchEvent(new Event(Event.EXITING)); 
} 
 
private function onExiting(event:Event):void 
{ 
	event.preventDefault(); 
	exiting = 1; 
	callComments("has just left the room", 0); 
}

Step 38: Other Functions

Here are some functions that are used throughout the application. We handle the 'errorPage' tweening, as well as moving the 'nativeWindow' around. Also, if the user wants to hit 'return' instead of clicking the 'button3' movieclip, the 'onKeyUp' function handles that.

 
private function onKeyUp(event:KeyboardEvent):void 
{ 
	if(event.keyCode === 13) 
	{ 
		if(event.shiftKey) 
		{ 
			screen3.comm.multiline = true; 
			screen3.comm.appendText("\n"); 
		} 
		else 
		{ 
			commentClick(null); 
		} 
	} 
	else 
	{ 
		// 
	} 
} 
 
private function onChange(event:Event):void 
{ 
	screen2.table.text = event.target.selectedItem.label; 
} 
 
private function onUser(event:Event):void 
{ 
	if(event.type === Event.USER_IDLE) 
	{ 
		callComments("is idle"); 
	} 
	else 
	{ 
		callComments("has returned"); 
	} 
} 
 
private function backgroundDown(event:MouseEvent):void 
{ 
	stage.nativeWindow.startMove();		//lets the user drag the app 
} 
 
private function userClick(event:Event):void 
{ 
	screen3.comm.appendText("@" + event.target.selectedItem.label);		//lets the user direct a comment at another user 
} 
 
private function tweenerTimer():void	//used to slide the Error screen 
{ 
	Tweener.addTween(errorPage, {x:background.x, time:1, onComplete:function(){ 
		var timer:Timer = new Timer(1000); 
		timer.addEventListener(TimerEvent.TIMER, function(){ 
			Tweener.addTween(errorPage, {x:-220, time:1}); 
			timer.stop(); 
		}); 
		timer.start(); 
	}}); 
}

Finishing off

We're almost done!


Step 39: Packaging the Application

We are finally ready to package our application to be distributed. Go to File > Commands > AIR - Application and Installer Settings.


Under 'Window style', select 'Custom Chrome (transparent).'


Click the 'Publish AIR File' button.



Step 40: Packaging the Application

When the 'Publish AIR File' button is clicked, a prompt to add a Digital Signature will pop up. You can select a file that you have already created. If you haven't, click on the 'Create' button.


Fill out the information and click 'OK'. After the file is created, you enter in the password and click 'OK'.


Once the file is created, you will get a prompt that says 'AIR file has been created'. Your chatroom application is now ready to be distributed.


Conclusion

I hope you enjoyed reading this tutorial. Don't forget to subscribe to the tuts+ feed to learn all kinds of the cool things PHP, MySQL and Flash can do.

Advertisement