Introduction to Flash [top]
Adobe Flash movies are graphics, text, animation, and applications for Web sites. They consist primarily of vector graphics, but they can also contain imported video, bitmap graphics, and sounds. Flash movies can incorporate interactivity to permit input from viewers, and you can create nonlinear movies that can interact with other Web applications. Web designers use Flash to create navigation controls, animated logos, long-form animations with synchronized sound, and even complete, sensory-rich Web sites. Flash movies use compact vector graphics, so they download rapidly and scale to the viewer's screen size.
You've probably watched and interacted with Flash movies on many Web sites. Millions of Web users have received the Flash Player with their computers, browsers, or system software; others have downloaded it from the Adobe Web site. The Flash Player resides on the local computer, where it plays back movies in browsers or as stand-alone applications. Viewing a Flash movie on the Flash Player is similar to viewing a DVD on a DVD player - the Flash Player is the device used to display the movies you create in the Flash authoring application.
Flash documents, which have the .fla filename extension, contain all the information required to develop, design, and test interactive content. Flash documents are not the movies the Flash Player displays. Instead, you publish your FLA documents as Flash movies, which have the .swf filename extension and contain only the information needed to display the movie.
ActionScript is the scripting language of Macromedia Flash MX, and it lets you add interactivity to a movie. ActionScript provides elements, such as actions, operators, and objects, that you put together in scripts that tell your movie what to do; you set up your movie so that events, such as button clicks and keypresses, trigger these scripts. In order to communicate with PHP on the server, we will need to develop a basic understanding of ActionScript.
Note: The demos on this page are targeted to the Flash 9 player and above, and use ActionScript 3.0. The FLA movies have been saved as Flash CS3 files, and both CS3 and CS4 formats are available in separate zipped downloads in the syllabus or at the bottom of the page.
On the Web, Flash movies can be embedded in straight HTML pages, or HTML pages generated by PHP or any other scripting language. The basic syntax for this is as follows, though Flash can also generate the HTML for you when publishing your movie:
<html>
<head>
<title>[Your Title Here]</title>
</head>
<body bgcolor="#FFFFCC">
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
width="[Movie Width]" height="[Movie Height]">
<param name="movie" value="[Name of Flash SWF File]">
<param name="quality" value="high">
<param name="bgcolor" value="#FFFFCC">
<param name="allowScriptAccess" value="sameDomain" />
<embed src="[Name of Flash SWF File]" quality="high" bgcolor="#FFFFCC"
width="[Movie Width]" height="[Movie Height]"
type="application/x-shockwave-flash"
allowScriptAccess="sameDomain"
pluginspage="http://www.macromedia.com/go/getflashplayer">
</object>
</body>
</html>
Also two main things to remember when you are testing and debugging:
Flash-Only Interaction [top]
In this first example, there is a textarea and a submit button. When the submit button is clicked, some pre-made text is deposited in the window. In this case, the interaction is completely self-contained within Flash. No communication has been made with the server. We can see what some of the ActionScripting looks like here:
// Put some text in text box when submit is clicked
function submitData(event:Event):void
{ // Put some text into the textContents text field
textContents.text = "Here is some text. What a lousy example.";
// You can also append
textContents.text += "\n\nSomebody please tell Red to find a new DWD teacher.";
textContents.text += "\n\nThanks.";
};
mySubmit.addEventListener("click", submitData);
This type of function is called a callback function, because it can only be initiated through some user action. In this case, it is called when a button named "mySubmit" is clicked. Also, note how similar ActionScript looks to JavaScript.
However, in this case, once we write the text, the interaction never changes. We can simply add another button that clears the text:
// Put some text in text box when submit is clicked
function submitData(event:Event):void
{ // Put some text into the textContents text field
textContents.text = "Here is some text. What a lousy example.";
// You can also append
textContents.text += "\n\nSomebody please tell Red to find a new DWD teacher.";
textContents.text += "\n\nThanks.";
};
function resetData(event:Event):void
{ // Clear the text field
textContents.text = "";
};
mySubmit.addEventListener("click", submitData);
myReset.addEventListener("click", resetData);
In this case, we have a callback function on "mySubmit" that writes to the text widget, and a callback function of "myReset" which sets the value of the text to be "", which is the same thing as clearing the text.
Flash/PHP Interaction - The PHP Side [top]
Flash and PHP communicate through name-value pairs that they each send to each other. This is similar to how an HTML form sends variables to PHP. In all cases, the values in these pairs are URL-encoded. Fortunately, we have a built PHP function which can take of this for us, urlencode(), which we can call in our PHP scripts as follows:
# Here is a data value to be sent to PHP $phpData = "This is a value to be obtained in Flash"; # We need to URL encode the data for HTTP transport $phpData = urlencode($phpData); # We are now going to send one variable to Flash. The name # of the var in Flash will be "serverData" and it will contain # the contents of the PHP var $phpData print "serverData=$phpData";which is sent to Flash as the following:
serverData=This+is+a+value+to+be+obtained+in+FlashThus, our PHP script, instead of printing HTML to the browser, is now printing name-value pairs to Flash. Note that when you first combine Flash with calls to PHP scripts on a web server, it's important to first make sure that your PHP scripts are working properly. It's hard enough to get Flash working without worrying about the PHP side. Make sure your PHP script is working first, and then concentrate on calling it from your Flash movie.
Flash/PHP Interaction - The Flash Side [top]
The main object used for client-server communication in Flash is the URLLoader object, which has set properties and methods for communicating with a remote web server. To specify a URL of interest, one creates a URLRequest object, and if there are name-value pairs to be sent to this URL (as in a GET or POST operation), a URLVariables object is used to define this data. The variables object is attached to the request object, and then the request object is used an argument to the URLLoader object. Thus, the basic flow of receiving data from a PHP script in Actionscript goes something like this:
import flash.net.*;
// Define the basic web path to our PHP script
var serverScript = "http://itp.nyu.edu/~netId/dwd/script.php";
var request:URLRequest = new URLRequest(serverScript);
var loader:URLLoader = new URLLoader();
var sent_vars:URLVariables = new URLVariables();
sent_vars.id = 56; // This is like calling: script.php?id=56
request.method = URLRequestMethod.GET;
request.data = sent_vars;
loader.addEventListener(Event.COMPLETE, onLoaded);
loader.load(request);
function onLoaded(event:Event):void
{
// Create vars from the data returned in loader.data
// and put contents of serverData into the textContents text field
var received_vars:URLVariables = new URLVariables(loader.data)
textContents.text = received_vars.serverData;
}
The URL of the PHP script on our server is used to make a URLRequest object. Using this object, we can specify any data to be sent to the PHP script, and also the method: GET or POST.
To specify the data to be submitted, we can create a new instance of a URLVariables object, assign properties and values to it, and this data will be sent to our PHP script as name-value pairs, just as an HTML form might. Also, you don't need to URL encode your data like in PHP because Flash takes care of this for us. When this data arrives in PHP, it arrives as name-value pairs just like our HTML form submissions. The format is exactly the same.
When the data returns from the PHP script and is received in Flash, the onLoaded function is automatically called, and the data is in the "data" property of the URLLoader object. We can then use the URLVariables object to take the url-encoded string of name-value pairs returned by PHP and parse it into an object where the name becomes a property of the object and its value is the value in the name-value pair.
Flash Security Note Regarding Domains [top]
Make sure the URL of the PHP script embedded in your movie has the same domain of the web page that contains your movie. In your movie, if you define the PHP script that you will use to be:
// Define PHP script to be called serverScript = "http://stage.itp.tsoa.nyu.edu/~netId/dwd/submitSite.php";and the HTML page that contains this movie is "site.html", then when you bring it up in the browser, it should be from the domain "stage.itp.tsoa.nyu.edu", i.e.
http://stage.itp.tsoa.nyu.edu/~netId/dwd/site.htmlRemember: A Flash movie can only communicate with a domain which is the exact same as the one from which it was served. This is for security reasons. Other good examples:
// Define PHP script to be called serverScript = "http://itp.nyu.edu/~netId/dwd/yourScript.php"; View at: http://itp.nyu.edu/~netId/dwd/PageContainingMovie.html --- // Define PHP script to be called serverScript = "http://stage.itp.nyu.edu/~netId/dwd/yourScript.php"; View at: http://stage.itp.nyu.edu/~netId/dwd/PageContainingMovie.htmlThis may be the jumping the gun, but for those who are starting to think about pulling data from a third-party web service in Flash, this most likely won't work due to the issues outlined above - communicating with a server not in the same domain as the originating one. This is actually governed site to site using a file kept by each site called crossdomain.xml, and it is up to the 3rd-party site to decide if they will allow a user to cross this security line.
Flash/PHP Example Movies [top]
So let's look at some different ways we can interface Flash, PHP, and MySQL. In this first example, when the submit button is pressed in Flash, we use the URLLoader.load() method to call a PHP script on the server. This script gets all rows of our instruments table in the database, puts it in one variable called serverData and send it to Flash.
In this next example, we do pretty much the same thing except that we call the load() method at the beginning of our movie such that we don't have to press a button to initiate the request.
A common method for pulling data from a remote server is having Flash "poll" the database, meaning that it should check the contents of the DB continuously at some set interval. In this case, we simply use the Timer object built into Flash to define what will happen and with what frequency:
// Set the timer to make a request every 5 sec, looping inifinitely
var myTimer:Timer = new Timer(5000);
myTimer.addEventListener(TimerEvent.TIMER, refreshContents);
myTimer.start();
// Define function that will be called continuously
function refreshContents(event:TimerEvent):void
{ // Simply call our PHP script to refresh text field with table contents
loader.load(request);
}
The data in this text field is now tied to the live database. If we should happen to change it, then it will dynamically change with it. This next example provides us with the ability to "enable" and "disable" certain entries in our instruments DB table. In this case, we enter the ID of the row we want to change in the table, and we then either enable or disable it in our listing. Flash collects the value of the ID and whether the command is to enable or disable, sticks them in our URLVariables object, and then makes the call to PHP using the load() method of the URLLoader object. PHP makes the requested changes to the DB, then gets the new listing, and sends it back to Flash. When Flash receives it, it takes the listing and sticks it in the text field.
// Enable display of instrument when enable button is pressed
function enableItem(event:Event):void
{
var sent_vars:URLVariables = new URLVariables();
// Create cmd property and set it to "enable"
sent_vars.cmd = "enable";
// Get the ID of the row to affect which is in the textID widget
sent_vars.id = textId.text;
// Send it to the server using the GET method and wait for response
var request:URLRequest = new URLRequest(serverScript);
request.data = sent_vars;
request.method = URLRequestMethod.GET;
loader.load(request);
request = null;
sent_vars = null;
};
// Disable display of instrument when enable button is pressed
function disableItem(event:Event):void
{
var sent_vars:URLVariables = new URLVariables();
// Create cmd property and set it to "disable"
sent_vars.cmd = "disable";
// Get the ID of the row to affect which is in the textID widget
sent_vars.id = textId.text;
// Send it to the server using the GET method and wait for response
var request:URLRequest = new URLRequest(serverScript);
request.data = sent_vars;
request.method = URLRequestMethod.GET;
loader.load(request);
request = null;
sent_vars = null;
};
loader.addEventListener(Event.COMPLETE, onLoaded);
myEnable.addEventListener("click", enableItem);
myDisable.addEventListener("click", disableItem);
Favorite Sites Submission - Revisited [top]
Now let's see how we can revamp the site submission portion of our favorite sites demo from a previous class. On the PHP side, the code is pretty much the same as it was in our previous version except that we don't need to format any of the visual stuff - since we are using Flash for our interface.
# Get the values from the widgets and trim whitespace
$title = trim($textTitleValue);
$url = trim($textUrlValue);
$desc = trim($textDescValue);
# Now check each widget. Title widget is checked first to see if blank
if (empty($title))
{ # If blank, set general error flag, title error flag, and general error message
$hasErrors = 1;
$noTitle = 1;
$statusMsg = "There were errors in your site submission.";
}
# Url widget is checked first to see if blank or default
if (empty($url) || $url=="http://")
{ # If blank, set general error flag, url error flag, and general error message
$hasErrors = 1;
$noUrl = 1;
$statusMsg = "There were errors in your site submission.";
}
# Description widget is checked first to see if blank
if (empty($desc))
{ # If blank, set general error flag, desc error flag, and general error message
$hasErrors = 1;
$noDesc = 1;
$statusMsg = "There were errors in your site submission.";
}
# If we had no errors, we can put it in the database
if (!$hasErrors)
{ # This is a good submission, so escape any single quotes in the text values
$titleDB = str_replace("'", "''", $title);
$urlDB = str_replace("'", "''", $url);
$descDB = str_replace("'", "''", $desc);
# Create the SQL query
$SqlStatement = "INSERT INTO class05_table2 (title,url,description)
VALUES ('$titleDB','$urlDB','$descDB') ";
# Run the query on the database through the connection
$result = mysql_query($SqlStatement,$connection);
$statusMsg = "Thank you for your site submission!";
}
$statusMsg = urlencode($statusMsg);
# Tell Flash what type of content to expect
header("Content-type: text/html");
# Send it to Flash
print "hasErrors=$hasErrors&statusMsg=$statusMsg";
The only difference is that we're now sending back just the var that says whether or not we had error, $hasErrors, and the $statusMsg. On the Flash side, we simply use the callback function associated with the submit button to collect the values of the text widgets, to put them in our URLLoader object, and to initiate the load() function to our PHP script. When we receive a response, we stick the status message in a text widget and use the hasErrors flag to determine if we need to reset the input widgets.
// Enable display of instrument when enable button is pressed
function submitItem(event:Event):void
{
var sent_vars:URLVariables = new URLVariables();
sent_vars.siteName = siteName.text; // Get value of name widget
sent_vars.siteUrl = siteUrl.text; // Get value of URL widget
sent_vars.siteDesc = siteDesc.text; // Get value of description widget
// Accumulate the vars in a string just for show, and show it
textSend.text = sent_vars.toString(); // This is text field under "Sent Text"
// Send it to the server using the POST method and wait for response
var request:URLRequest = new URLRequest(serverScript);
request.data = sent_vars;
request.method = URLRequestMethod.POST;
loader.load(request);
request = null;
sent_vars = null;
};
function onLoaded(event:Event):void
{
textReturn.text = loader.data;
// Create vars from the data returned in loader.data
// and parse the returned vars
var received_vars:URLVariables = new URLVariables(loader.data)
// Show the status that was returned. Our PHP script sends:
// result: 0=OK, 1=problem
// status: string
// If there was a status message, then show it
if (received_vars.statusMsg.length>0)
textStatus.text = received_vars.statusMsg;
// If it was successful, then clear the widgets
if (received_vars.hasErrors==0)
{ siteName.text = "";
siteUrl.text = "http://";
siteDesc.text = "";
}
received_vars = null;
loader.data = null;
}
Flash, XML, and Dynamic Widget Population [top]
In the same way that we could use PHP to dynamically populate dropdowns or checkboxes in HTML forms using data from our DB, we can do the same thing in Flash. Receiving lists of data in Flash as name-value pairs is OK, but somewhat cumbersome to parse, so we can use another format to receive the data that we now know quite well: XML. Flash has dedicated XML support, such that receiving XML from the server instead of name-value pairs, and parsing this data is performed with great ease:
import flash.net.*;
var myXML:XML = new XML(); // Have an XML object ready to go
// Define the basic web path to our PHP script
var serverScript = "http://itp.nyu.edu/~netId/dwd/script.php";
var request:URLRequest = new URLRequest(serverScript);
var loader:URLLoader = new URLLoader(request);
loader.addEventListener("complete", xmlLoaded);
// Make the request
loader.load(request);
request = null;
function xmlLoaded(event:Event):void
{
myXML = XML(loader.data);
mySelect.removeAll();
mySelect.addItem({label:"-- Select --", id:0});
for (var i:String in myXML.item)
{
// trace(i + ": " + myXML.item.id[i] + ": " + myXML.item.name[i]);
mySelect.addItem({label:myXML.item.name[i], id:myXML.item.id[i]});
}
}
The main task in receiving XML data in Flash is parsing. When XML data arrives in Flash, it is placed in a structure consisting of nodes and their children. To get at the actual values, we can simply navigate the tree of names and values to get to our actual data.
For the other XML format we used for AJAX in class 10, we can parse attributes in a similar manner, which we can use to populate our favorite sites inside a Flash combo box:
function xmlLoaded(event:Event):void
{
myXML = XML(loader.data);
mySelect.removeAll();
mySelect.addItem({label:"-- Select --", id:0});
for (var i:String in myXML.o)
{
//trace(i + ": " + myXML.o.@id[i] + ": " + myXML.o.@title[i]);
mySelect.addItem({label: myXML.o.@title[i], id: myXML.o.@id[i]});
}
}
Flash and JSON [top]
As part of the Adobe corelib project, a JSON ActionScript library is now available to provide JSON support in Flash. Using this library, we can easily load the data from our JSON web service that we created last week, decode it, and then use it to create a combo box containing our favorite sites:
import com.adobe.serialization.json.JSON;
...
function jsonLoaded(event:Event):void
{
var sites:Array = JSON.decode(loader.data);
mySelect.removeAll();
mySelect.addItem({label:"-- Select --", id:0});
for (var key:Object in sites)
{
trace(sites[key].id + ": " + sites[key].title);
mySelect.addItem({label: sites[key].title, id: sites[key].id});
}
}
In order for Flash to be able to find any ActionScript libraries not included with the main distribution, we can put our libraries on our local hard drive in a folder of our choosing, and then include this folder in the settings for our source path in the settings under File > Publish Settings.
Introduction to Amazon Web Services (AWS) [top]
Some of the most common web services in use today are the suite of tools provided by Amazon, known as Amazon Web Services (AWS). The ones we'll cover today are Amazon Simple Storage (S3): their service for online storage and static file serving, and SimpleDB: their service for providing basic database functionality.
Amazon Simple Storage (S3)
One of the cheapest method of storage is S3. Once you've obtained an account, along with a set of access keys, you'll be able to upload and download files into the Amazon cloud in any fashion you wish and from anywhere you can run PHP. Each file is given a unique URL that provides web access to that file depending upon the permissions you've set (public or private). Thus, not only do you get cheap storage but also the serving of that content as well. For example, you can serve all your images using S3 or even stream video via .flv files a la Youtube. All you need is a Flash video player, many of which are freely available online.
Amazon PHP Software Development Kit (SDK) for Amazon Web Services
For many years, the primary PHP library for interfacing w/Amazon Web Services was CloudFusion. Now this project has been adopted by Amazon as the official SDK in PHP. Using this library, you can utilize all of Amazon's Web Services easily.
Creating a Mobile Version of a Web App [top]
To illustrate this concept, we can further recast our favorite sites demo to have a mobile component.
Favorite Sites Demo with Mobile
In order to restrucure this, we'll add a few different files:
public function isMobile($agent)
{
$RE_MOBILE = '/(nokia|iphone|android|motorola|^mot\-|softbank|foma ...)/i';
$isMobile = isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE']) ||
preg_match($RE_MOBILE, $_SERVER['HTTP_USER_AGENT']) ||
preg_match($RE_MOBILE, $agent);
return $isMobile;
}
Every time a page is requested, in the controller, we can check whether or not we are serving the mobile or full version. We can allow the user to explicitly ask for a specific version as well, by looking for a name-value pair in the $_GET, such as layout=fs or layout=mb. The steps are:
$theme = 'full';
$layout = MobileHelper::setLayout($_GET['layout']);
if ($layout=='mb') $theme = 'mobile';
public function setLayout($text)
{
$map = array('fs'=>true,'mb'=>true);
# First check for explicit set from query string
if ($text && strlen($text)==2 && $map[$text]) {
setcookie('lo',$text,time()+3600*24*180,'/');
$_SESSION['lo'] = $text;
return $text;
}
# Then check if set in session
if ($_SESSION['lo'] && $map[$_SESSION['lo']]) {
return $_SESSION['lo'];
}
# Then check in cookie
if ($_COOKIE['lo'] && $map[$_COOKIE['lo']]) {
$_SESSION['lo'] = $_COOKIE['lo'];
return $_COOKIE['lo'];
}
# Otherwise try to derive from user agent
$type = 'fs';
if (self::isMobile($_SERVER['HTTP_USER_AGENT'])) $type = 'mb';
setcookie('lo',$type,time()+3600*24*180,'/');
$_SESSION['lo'] = $type;
return $type;
}
Then, once we know the theme, we can call the set of corresponding view templates. This means you need a separate set of templates for each version of the site (each theme).
# Set the view file html if default format
$view_file = "themes/{$theme}/{$view}.php";
Related Resources [top]