Cross Domain Scripting using Flash

I was building a site for a client when I came across this cross domain security issue. My client had users that needed to be able to send data from their website to my clients server which would process the data and return a new set of data to replace the old. I couldn’t just make an ajax call since the browser wont allow you to receive data from another server. My options to get around this were that I could use iframes or use flash. I decided to go with the flash for no particular reason.

I’m going to go through each file I created. First I’m going to go through the .fla file and then the two .as files and then the javascript file.

I am using Flash 8 and actionscript 2.

To start, create a new .fla file.

Import the following class to allow flash and javascript to communicate.


import flash.external.ExternalInterface;

Flash wont allow you to access another domain without adding the following code. The ‘*’ will allow all domains to be able to access the file on your server or you can add individual domains.


System.security.allowDomain("*");

I create a new instance of DebugHelper which is created in a separate .as file which I’ll show later. This is only used to help me print out text to test the code. It creates a text field and then when you call the Log function will print out the string you pass to it.


var deb = new DebugHelper();
DebugHelper.Log("test");

This is a button I created in the .fla. When it is clicked it loads the policy file. This is an xml file that tells the flash which domains are allowed to access the files that are in the same folder the xml file is in and all subfolders on your server. You can use a ‘*’ to allow all domains. The ExternalInterface.call calls a javascript function which takes the content of the webpage and passes it to flash.


The crossdomain.xml file
<?xml version="1.0"?>
   <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/
dtds/cross-domain-policy.dtd">
   <cross-domain-policy>
       <allow-access-from domain="www.company.com" />
       <allow-access-from domain="*" />
   </cross-domain-policy>

btn.onRelease = function() {
  System.security.loadPolicyFile("http://yourdomain.com/crossdomain.xml");
  var successful = ExternalInterface.call("sendit");
};

This next bit allows the flash element in javascript to send data via the function “sendData” which calls the “xmlhttp” flash function. Then this function creates a new HttpConnection object which is in another .as file which I’ll explain later. You pass to it the filename of where you want to send the data. You then can set the body with the data you passed to the function and whether you want to use POST or GET. I then add the onData event handler to the object so I know when I get data back from the server. When that is fired I set the data to a variable called retText and then pass it to javascript with the call “setData”.


ExternalInterface.addCallback("sendData", this, xmlhttp);
function xmlhttp(body:String) {
	var http = new HttpConnection("http://yoursite.com/crossdomain.php");
	http.setAction("POST");
		http.setBody(body);
		http.setContentType("application/x-www-form-urlencoded");
		http.onData = function(src:String) {
				_root.retText = src;
				ExternalInterface.call("setData", "retText");
		};
		http.send();
}

This last function calls the javascript function “storageOnLoad” so we know the flash is loaded.


var ret = ExternalInterface.call("storageOnLoad");

This next bit is the DebugHelper.as file. This just creates a text field that allows me to call Log() on DebugHelper to help me debug by printing out text to the screen.


class DebugHelper {
	static var log:String;
	static var debug:Boolean;
	function DebugHelper() {
		_root.createTextField("tf", 0, 0, 0, 315, 238);
		log = "";
		var ret;
		_root.tf.text = "Running Flash version: "+getVersion();
		DebugHelper.Debug();
	}

	public static function Debug() {
		debug = true;
	}
	public static function Log(input:String) {
		log = log+" ___ "+input;
		if (debug) {
			_root.tf.text = input+"\r"+_root.tf.text;
		}
	}
}

This next file is the HttpConnection.as file. I start out by defining some variables and functions. The sendAndLoad and Load functions I set to the default LoadVars.prototype.sendAndLoad and LoadVars.prototype.load function which allows me to send this objects data to the given url using the LoadVars class.


 class HttpConnection {
	private var action:String = "POST";
	private var body:String = "";
	private var url:String = "";
	var contentType:String;
	var sendAndLoad:Function = LoadVars.prototype.sendAndLoad;
	var load:Function = LoadVars.prototype.load;
	// note: many headers can't be added. http://livedocs.macromedia.com/
       //   flash/8/main/wwhelp/wwhimpl/common/html/
       //   wwhelp.htm?context=LiveDocs_Parts&file=00002324.html
	var addRequestHeader:Function = LoadVars.prototype.addRequestHeader;
	var onData:Function;

This function creates an instance of this class.


	function HttpConnection(_urls:String) {
		url = _urls;
	}

The next four function allow me to set the url, action, body and contentType.


	function setUrl(_urls:String) {
		if (_urls) {
			url = _urls;
		}
	}
	function setAction(_action:String) {
		if (_action) {
			action = _action;
		}
	}
	function setBody(_body:String) {
		if (_body) {
			body = _body;
		}
	}
	function setContentType(_contentType:String) {
		if (_contentType) {
			contentType = _contentType;
		}
	}

This function is overriding the default toString() function. This automatically gets called when the sendAndLoad function is called. If I wasn’t using an object to call the sendAndLoad function I would have to create an instance of LoadVars and set the variables like this:

var my_lv:LoadVars = new LoadVars();
var result_lv:LoadVars = new LoadVars();
my_lv.id=10;
my_lv.text = “some text”;
my_lv.sendAndLoad(url, result_lv, ‘POST’);

The toString() function would get called to convert my_lv to “id=10&text=some+text”. Since I already have the body in that format I don’t need to do that so I just return the body.


	function toString():String {
		return body;
	}

This is the function that sends the data to the server.


	function send() {
		DebugHelper.Log("HttpConnection send this(action="+action+")");
		// note: if we did a sendAndLoad on a GET, the Flash API would add
                //a question mark '?' at the end of the querystring

		if (action == "GET") {
			load(url);
		} else {
			sendAndLoad(url, this, action);
		}
	}
}

Now the javascript file.

I create a javacript object to hold the flash.


var FlashObject = new Object();
FlashObject.height = 138;
FlashObject.width = 215;

This function will check to see if the flash is installed.


FlashObject.isFlashInstalled = function() {
	var ret;
	if (typeof(this.isFlashInstalledMemo) != "undefined") {
            return this.isFlashInstalledMemo;
        }
	if (typeof(ActiveXObject) != "undefined") {
  	   try {
		var ieObj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
	    } catch (e) { }
	     ret = (ieObj != null);
	} else {
		var plugin = navigator.mimeTypes["application/x-shockwave-flash"];
		ret = (plugin != null) && (plugin.enabledPlugin != null);
	}
	this.isFlashInstalledMemo = ret;
	return ret;
}

This simply gets the flash element.


FlashObject.getFlash = function() {
	return document.getElementById("flash");
}

This function will write the flash object on your page. For me, I needed to send the entire content of the body to flash and then replace it without replacing the flash object. So I needed to add a wrapper div around the entire content of the body. That way when I get the data back from flash I would replace everything inside that wrapper div. This will keep the flash from getting over written which can cause some errors. If you don’t need to replace the entire page then it’s not necessary.


FlashObject.writeFlash = function() {
	var swfName = "http://yourdomain.com/crossdomain.swf";
	if (window.ActiveXObject && !FlashObject.isFlashInstalled())
	{
	  // browser supports ActiveX
	 // Create object element with
	 // download URL for IE OCX
	 document.body.innerHTML="<div id='wrapperdiv'>"+document.body.innerHTML+
                                                    "</div>";
	 document.write('<object classid=
                           "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
	 document.write(' codebase="http://download.macromedia.com');
	 document.write('/pub/shockwave/cabs/flash/swflash.cab#version=8,5,0,0"');
	 document.write(' height="'+this.height+'" width="'+this.width+'"
                                   id="flash">');
	 document.write(' <param name="movie" value="' + swfName + '">');
	 document.write(' <param name="quality" value="high">');
	 document.write(' <param name="allowScriptAccess" value="always">');
	 document.write(' <param name="swliveconnect" value="true">');
	 document.write('<\/object>');
	}
	else
	{
	 // browser supports Netscape Plugin API
	 document.body.innerHTML="<div id='wrapperdiv'>"+document.body.innerHTML+
                                           "</div>";
         document.write('<object id="flash" data="' + swfName + '"');
	 document.write(' type="application/x-shockwave-flash"');
	 document.write(' height="'+this.height+'" width="'+this.width+'">');
	 document.write('<param name="movie" value="'+swfName+'">');
	 document.write('<param name="quality" value="high">');
	 document.write('<param name="swliveconnect" value="true">');
	 document.write('<param name="pluginurl"
                    value="http://www.macromedia.com/go/getflashplayer">');
	 document.write('<param name="pluginspage"
                     value="http://www.macromedia.com/go/getflashplayer">');
	 document.write(' <param name="allowScriptAccess" value="always">');
	 document.write('<p>You need Flash for this.');
	 document.write(' Get the latest version from');
	 document.write(' <a href="http://www.macromedia.com/software/
                                    flashplayer/">here<\/a>.');
	 document.write('<\/p>');
	 document.write('<\/object>');
	}
}

The next few functions are used to load up the flash.


FlashObject.load = function() {
	if (typeof(FlashObject.onload) != "function") { return; }

	if (FlashObject.isFlashInstalled()) {
		// if we expect Flash to work, wait for both flash and the document to be loaded
		var finishedLoading = this.flashLoaded && this.documentLoaded;
		if (!finishedLoading) { return; }
	}
	// todo: cancel timer
	var fs = FlashObject.getFlash();

	if ((!FlashObject.isFlashInstalled() || this.flashLoaded) && fs) {
		if (FlashObject.checkFlash()) {
			callAppOnLoad(fs);
		} else {
			callAppOnLoad(null);
		}
	} else {
		callAppOnLoad(null);
	}

	function callAppOnLoad(fs) {
		if (FlashHelper.onloadCalled) { return; } // todo: figure out why this case gets hit
		FlashHelper.onloadCalled = true;
		FlashHelper.onload(fs);
	}
}

function storageOnLoad() {
	FlashObject.flashLoaded = true;
	FlashObject.load();
}

This function is nice because if you already have a window.onload event and need to add more onload events this will add them.


FlashObject.addLoadEvent = function(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			oldonload();
			func();
		}
	}
}

This initializes the flash object variables and onload functions. If you wanted the flash to automatically run on page load you could simply add the function call (in this case “sendit()”) inside the onload function.


FlashObject.init = function() {
	this.flashLoaded = false;
	this.documentLoaded = false;
	// attach to the window.onload event
	this.addLoadEvent(onload);
	function onload() {
		FlashObject.documentLoaded = true;
		FlashObject.load();
	}
}

FlashObject.init();

The function that actually gets the data you want to send and then calls the flash function “sendData”.


 function sendit() {
    var body = 'uid='+testdata;
    body += '&pagetext='+
       encodeURIComponent(document.getElementById('wrapperdiv').innerHTML);
    FlashObject.getFlash().sendData(body);
 }

When the data gets returned it stores it in a variable which we set in the http.onData function. We then pass the name of the variable to this function and call GetVariable which returns the data.


function setData(varname){
	var str = FlashObject.getFlash().GetVariable(varname);
	document.getElementById("wrapperdiv").innerHTML = str
}

And finally this writes out the flash object to the page.


FlashObject.writeFlash();

Now all anyone would need to do would be to include this javascript file at then end of their page right before the body tag.

Here are the .fla, .as and .js files.
CrossDomain.zip

Access Webcam with Flash

I wanted a user to be able to upload pictures via their webcam. This post will show how to make a flash application using Flash 8 and actionscript 2 to have a website access a users webcam and take a picture and save it.

First off we need to import the following files:


 //This will allow us to create a photo
import flash.display.BitmapData;
// This is used to mirror the look of the webcam
import flash.geom.Matrix;
 //Used to interact with javascript
import flash.external.ExternalInterface;

This code is used to actually display the webcam on the screen except we’re setting the video visible to false.


video_vobj._visible = false;
var cam:Camera = Camera.get();
cam.setQuality(0,30);
cam.setMode(300, 400, 28);

Occasionally when you reload the page the webcam displays a scrambled image or the last frame displayed. I rather not see anything if the camera isn’t ready which is why we set the video visible to false to begin. This next bit is a little hack to fix that problem.


var firstone:Boolean = true;
cam.onActivity = function(isActive:Boolean) {
  if(firstone){
  //clears the video screen so it won't display the scrambled screen or frozen frame.
	video_vobj.clear();
        firstone = false;
        video_vobj._visible = true;
  }
};

The position of the video.


var videoX:Number = video_vobj._x;
var videoY:Number = video_vobj._y;
var videoW:Number = video_vobj._width;
var videoH:Number = video_vobj._height;

In order for the website to access the webcam, a user must give the website permission.

If muted is true it means that the website currently doesn’t have access. By default flash will popup with a allow/deny dialog box but I prefer to display the settings dialog box. This is because the settings dialog box allows you to check a remember box so the website will always have access to the webcam unless you go into the settings and change it again. It also has a few other options like choosing a different webcam.


if(cam.muted == true){
      //Shows the setting dialog box with which tab to display passed to it.
	System.showSettings(0);
}else{
	video_vobj.attachVideo(cam);
	createbutton();
}

This is a camera event that is triggered when access to the webcam has been granted or denied.

cam.onStatus = function(infoObj:Object) {
    switch (infoObj.code) {
    case 'Camera.Muted' :
    break;
    case 'Camera.Unmuted' :
	  video_vobj.attachVideo(cam);
	  createbutton();
    break;
    }
}

First we’ll create a movie clip that will hold the button to take the picture.


var root:MovieClip = this;
root._x = 50;
root.createEmptyMovieClip("take", root.getNextHighestDepth());

I wanted to create a button that a user could click to take a picture. This could have just as easily been accomplished by adding a button in flash but I wanted to try it this way.


function createbutton(){
	take._x = 10;
	take._y = 435;
	var fillType:String = "linear";
	var colors:Array = [0xFAD4DB, 0xEC748B, 0xC13A59, 0xA81230];
	var alphas:Array = [100, 100, 100, 100];
	var ratios:Array = [0, 126, 127, 255];
	var matrix:Object = {matrixType:"box", x:0, y:0, w:80, h:30,
        r:90/180*Math.PI};
	take.createEmptyMovieClip("takebtn", reset.getNextHighestDepth());
	take.takebtn.lineStyle(0, 0x820F26, 60, true, "none", "square", "round");
	take.takebtn.beginGradientFill(fillType, colors, alphas, ratios, matrix);
	take.takebtn.lineTo(120, 0);
	take.takebtn.lineTo(120, 30);
	take.takebtn.lineTo(0, 30);
	take.takebtn.lineTo(0, 0);
	take.takebtn.endFill();
	take.createTextField("labelText", take.getNextHighestDepth(), 0, 5,
         take._width, 24);
	take.labelText.text = "Take Picture";
}

Takes the inverse of the xscale in order to mirror the image.


video_vobj._x = video_vobj._width;
video_vobj._xscale = -video_vobj._xscale;

When you click the Take Picture button it triggers an event that will store the image that is currently on the screen
into this bitmap.


var screenS:BitmapData = new BitmapData(video_vobj._width, video_vobj._height,
                                       true, 0xff0000);

This function is called to reset everything to how it was at the start.


function resetflash(){
	root.holder.removeMovieClip();
	root.myButton1.removeMovieClip();
	root.reset.removeMovieClip();
	if(root.loader)
		root.loader.removeMovieClip();
}

This is the code to actually creates the image. The screenS.draw function takes the video and matrix to draw a mirrored image.


take.onRelease = function() {
	var mymatrix:Matrix = new Matrix();
	if(mymatrix.a>0){
		mymatrix.a=-1.875*mymatrix.a;
		mymatrix.d= 3.333*mymatrix.d;
		mymatrix.tx= video_vobj._width;
	}
       screenS.draw(video_vobj, mymatrix);

I create a empty movie clip to hold and display the image. This makes it easy to remove the image by simply removing the movie clip. When I create one I pass the name and the depth. The root.getNextHighestDepth() makes sure that flash renders the movie clip in front of all the others.


root.createEmptyMovieClip("holder", root.getNextHighestDepth());
holder.attachBitmap(screenS, 1);
holder._x = videoX;
holder._y = videoY;
holder._width = videoW;
holder._height = videoH;

Here I create another button to reset everything to the start positions.


root.createEmptyMovieClip("reset", root.getNextHighestDepth());
reset._x = 10;
reset._y = 435;
var fillType:String = "linear";
var colors:Array = [0xFAD4DB, 0xEC748B, 0xC13A59, 0xA81230];
var alphas:Array = [100, 100, 100, 100];
var ratios:Array = [0, 126, 127, 255];
var matrix:Object = {matrixType:"box", x:0, y:0, w:80, h:30, r:90/180*Math.PI};
reset.createEmptyMovieClip("resetbtn", reset.getNextHighestDepth());
reset.resetbtn.lineStyle(0, 0x820F26, 60, true, "none", "square", "round");
reset.resetbtn.beginGradientFill(fillType, colors, alphas, ratios, matrix);
reset.resetbtn.lineTo(120, 0);
reset.resetbtn.lineTo(120, 30);
reset.resetbtn.lineTo(0, 30);
reset.resetbtn.lineTo(0, 0);
reset.resetbtn.endFill();
reset.createTextField("labelText", reset.getNextHighestDepth(), 0, 5,
   reset._width, 24);
reset.labelText.text = "Discard";

Here I create another button in order to save the image.


root.createEmptyMovieClip("myButton1", root.getNextHighestDepth());
myButton1._x = 150;
myButton1._y = 435;
var fillType:String = "linear";
var colors:Array = [0xFAD4DB, 0xEC748B, 0xC13A59, 0xA81230];
var alphas:Array = [100, 100, 100, 100];
var ratios:Array = [0, 126, 127, 255];
var matrix:Object = {matrixType:"box", x:0, y:0, w:80, h:30, r:90/180*Math.PI};
myButton1.createEmptyMovieClip("buttonBkg", myButton1.getNextHighestDepth());
myButton1.buttonBkg.lineStyle(0, 0x820F26, 60, true, "none",
   "square", "round");
myButton1.buttonBkg.beginGradientFill(fillType, colors, alphas,
   ratios, matrix);
myButton1.buttonBkg.lineTo(120, 0);
myButton1.buttonBkg.lineTo(120, 30);
myButton1.buttonBkg.lineTo(0, 30);
myButton1.buttonBkg.lineTo(0, 0);
myButton1.buttonBkg.endFill();
myButton1.createTextField("labelText", myButton1.getNextHighestDepth(),
  0, 5, myButton1._width, 24);
myButton1.labelText.text = "Save Image";

reset.onRelease = resetflash;

This is the event that will trigger the image to begin saving. I first create a movie clip to display a red film over the picture and text to display the progress of the picture. It then creates a SaveImage object. This object is defined in SaveImage.as which is a file you’ll have to create.


myButton1.onRelease = function(){
		tbo.text= screenS.width;
		root.createEmptyMovieClip("loader", root.getNextHighestDepth());
		loader._x = 0;
		loader._y = 0;
		loader.beginFill(0xFF0000, 50);
		loader.lineTo(300, 0);
		loader.lineTo(300, 400);
		loader.lineTo(0, 400);
		loader.lineTo(0, 400);
		loader.endFill();

		loader.createTextField("my_txt", 1, 0, 150, 300, 100);
		var my_fmt:TextFormat = new TextFormat();
		my_fmt.color = 0xFFFFFF;
		my_fmt.align="center";
		loader.my_txt.text = "Progress";
		loader.my_txt.setTextFormat(my_fmt);

		var si:SaveImage = new SaveImage();
		si.addListener( listener ); // assign a listener
		si.print(root, 0, 0, video_vobj._width, video_vobj._height) // copy the root
	}

};

I create a listener object that I added to si (SaveImage object). This is used to view the progress of the picture being saved and also when it is completed.


var listener:Object = new Object();

listener.onProgress = function(target:MovieClip, loaded:Number, total:Number){
var perc = Math.round((loaded/total)*100)
	var my_fmt:TextFormat = new TextFormat();
	my_fmt.color = 0xFFFFFF;
	my_fmt.align="center";
       loader.my_txt.text = "computing "+perc+"%";
	loader.my_txt.setTextFormat(my_fmt);
}

When the image is finished copying the data it sends it to some server file for processing via the sendAndLoad function. It then takes whatever was returned from the file and stores it in result_lv. When data is put into that LoadVars object an event onData is triggered. The src variable is what is returned and in this case is the name of the image I created. I then call my javascript function with the ExternalInterface.call which will display the image.


listener.onComplete = function(target:MovieClip, load_var:LoadVars){
	var result_lv:LoadVars = new LoadVars();
       result_lv.onData = function(src:String) {
		var retText = src;
		resetflash();
		ExternalInterface.call("showimg", retText);
    };
    load_var.sendAndLoad("yourfile.php", result_lv, "POST");
}

This next part is to make the SaveImage.as file. Everthing will be in class SaveImage. You can’t have more than one class in a .as file. The first part is to define some variables.


 class SaveImage {
    public var addListener:Function
    public var broadcastMessage:Function
    private var id:   Number;
    public  var record:LoadVars;

This function initializes the object and makes it an event broadcaster. This allows us to create custom event handling mechanisms. The listener object we added earlier will now receive notification anytime we call the broadcastMessage() method.


    function SaveImage(){
        AsBroadcaster.initialize( this );
    }

This is the function we called to begin copying the image data. We store it in the LoadVars object “record”. Then we call the setInterval function that calls copysource.


    public function print(mc:MovieClip, x:Number, y:Number, w:Number, h:Number){
        if(x == undefined) x = 0;
        if(y == undefined) y = 0;
        if(w == undefined) w = mc._width;
        if(h == undefined) h = mc._height;
        record = new LoadVars();
        record.width  = w
        record.height = h
        record.cols   = 0
        record.rows   = 0
        id = setInterval(copysource, 5, this, _root.video_vobj, _root.screenS);
    }

This function is the one that is actually copying all the image data pixel by pixel. Instead of looping through all of it at once I do it row by row by using the setInterval function. I do this so I can show the progress which is displayed when I call broadcastMessage(“onProgress”). After it is completed I call the clearInterval(this.id) so it wont call the funtion anymore.


    private function copysource(scope, movie, bit){
        var pixel:Number
        var str_pixel:String
        scope.record["px" + scope.record.rows] = new Array();
        for(var a = 0; a < bit.width; a++){
            pixel     = bit.getPixel(a, scope.record.rows)
            str_pixel = pixel.toString(16)
            if(pixel == 0xFFFFFF) str_pixel = "";   // don't send blank pixel
            scope.record["px" + scope.record.rows].push(str_pixel)
        }

        scope.broadcastMessage("onProgress", movie, scope.record.rows, bit.height)
        scope.record.rows += 1
        if(scope.record.rows >= bit.height){
            clearInterval(scope.id)
            scope.broadcastMessage("onComplete", movie, scope.record)
        }
    }
}

Here is the php code I use to process the post variables.

View PHP code


View All Flash Code

View Example

Here is the .fla and .as files
Flash Files

Multiple File Upload Using Flash


I came across this issue recently when I was building a website where I wanted users to be able to upload multiple photos. Since they were allowed to upload as many photos as they wanted I thought it would be nice for them not to have to do it one by one. So I began looking around to figure out the best way to do this.
I came across a few options to do this.

  • I could spend a few hundred dollars on a java applet. Though this is a nice application that lets you view and select the files you want, it is a little expensive when you just want the functionality of uploading multiple files. Or you could build your own. Though for me, I think buying one is cheaper than spending the time on building one.
  • I could use flash to turn my regular browse dialog box into a multiple file upload dialog box.

For now, I decided to go with option B. At some point I might add option A to the site but it will still be nice to have the Flash based upload application for those people that don’t have java installed. And if they don’t have flash installed I’ll make sure they can upload one file at a time as well.

So this is how I accomplished it.

First off I am using Flash 8 and actionscript 2

Create a new Flash document and add a button. Originally I didn’t add a button and used a regular html button to open the browse dialog box. This worked fine unless you have Flash 10 installed which has extra security features which don’t allow that. So I had to add a button in flash to get around it.

After you create the button go back to the root and add everything there.
Here is what we need to include:

import flash.net.FileReferenceList; (this is to actually select multiple files at once)
import flash.net.FileReference; (this is the individual file that is being uploaded)
import flash.external.ExternalInterface; (I included this because I like to be able to call javascript functions in flash and flash functions in javascript. But it is not needed to upload multiple files.)

I create two listener objects, one for the FileReferenceList and one for the FileReference.

var listener:Object = new Object();
var listener2:Object = new Object();

I then create a few variables:

var itemnum = 0; // This is the current file position in the fileList array
var numfiles = 0; // How many files are being uploaded
var list:Array; // This is what we will store the files being uploaded into

This is the onSelect event that is fired after selecting file(s) in the browse dialog box and then hitting the Select button.

listener.onSelect = function(fileRefList:FileReferenceList) {
	list = fileRefList.fileList;
	numfiles = list.length;
	uploadItem(itemnum);   // function to actually upload the photos
}

This event is called after each photo selected has been uploaded. It also calls a javascript function “showpics” which is an ajax call to display each photo after it has been uploaded.

listener2.onComplete = function(){
	itemnum += 1;
	ExternalInterface.call("showpics");
	if(itemnum<numfiles)
		uploadItem(itemnum);  //call function on next photo
}

This is the function to actually upload the file . The file you send it to should be a relative link otherwise flash 10 will throw a security error.

function uploadItem(num:Number){
	var item:FileReference = list[num];
	item.addListener(listener2);
	item.upload("yourfile.php");
}

We need to create an array of the types of files that we want to to be able to select from the browse dialog box.

var allTypes:Array = new Array();
var imageTypes:Object = new Object();
imageTypes.description = "Images (*.JPG;*.JPEG;*.JPE;*.GIF;*.PNG;)";
imageTypes.extension = "*.jpg; *.JPG; *.jpeg; *.jpe; *.gif; *.png;";
allTypes.push(imageTypes);

Finally, this is the function that will actually display the browse dialog box.

function uploadFile(){
	var fileRef:FileReferenceList = new FileReferenceList();
	fileRef.addListener(listener);
	fileRef.browse(allTypes);
}

The next part is to add the onClick handler to the button. Make sure you set the variable name of the button to something; in this case “btn”.

btn.onClick = function(){
uploadpics();
}

This next part allows me to use a simple input of type button to call the uploadFile function unless the user has flash 10 installed and then this wont work.

ExternalInterface.addCallback("javascript_function_name", this, "uploadFile");

And that is it. Nice and simple.

* Note: Apparently if you’re using a Mac OS the onComplete event doesn’t work unless you echo “1” at the end of the file you passed the image to. This way Macs know the file finished uploading.

**Also note that there is an even simpler and quicker way if all you want to do is upload the images without changing them.

To do it that way just change the following code:

listener.onSelect = function(fileRefList:FileReferenceList) {
    list = fileRefList.fileList;
    var item:FileReference;
    numfiles = list.length;
    for(var i=0; i<numfiles; i++){
        item = list[i];
  	item.upload("yourfile.php");
    }
}

I didn’t do it this way because I am creating thumbnails of each image and needed each image to be done before the next image is uploaded.

View Example

Download FLA File

Show Code