Creating a Reusable Flash Uploader with ActionScript 3.0 and PHP

In this tutorial I’ll show you how to build a Flash uploader for uploading files from the user’s computer. The result will be ideal for large file sizes as it will display a progress bar and the percentage left to upload. We’ll even show the user the number of bytes uploaded per second.

Folder icon by Michael Ludwig.

Editor’s note: I’m afraid there’s no demo for this tut – you’ll have to download the source.zip and play around with uploading files to your own server :)

Step 1: Button Design

Create a new ActionScript 3.0 Flash file and set the dimensions to 500 x 100 pixels. We’ll begin by creating a select button. Draw a rounded rectangle, I’ve made mine with a 5px round corner, a blue gradient and a 2px gray stroke.

Press F8 to turn it into a button and give it the instance name “select”. Name the button on the stage “select_btn”.

Inside the button, fill the 3 states with a slightly different gradient. Create another layer above the first and add a static text field with the text “SELECT FILE”. It’s best to separate the assets because it’s easier to edit them later.

Step 2: Progress Bar Design

Back to the main stage, create another rounded box with a white colour and a gray stroke. This will be the progress bar. I did mine like this:

Again, press F8 and turn it into a movieclip with the name “progress”. Inside the progress movieclip, create 2 more layers above the first and move the white fill into the third, leaving only the stroke on the first layer.. Rename the first layer “margin”, the second “bar” and the third “mask”. We’re going to turn the third layer into a mask.

On the “bar” layer, create a blue rectange with the same dimensions as the fill layer, but be carefull to make it slightly bigger so that when we apply the mask we don’t have holes. Place it at 0,0 and turn it into a movieclip with the instance name “bar”. This will be the bar that will show the progress.

Right-click the third layer and select “Mask” from the menu. You should have something like this:

Step 3: Duplicate Button

In the library, right-click on the select button we created earlier and select “Duplicate”. Name the duplicate “cancel” and in the button change the textfield’s text to “CANCEL”. We’re making a duplicate of the select button that will be the cancel button. We’ll later show only one of them in the stage.

In the main scene, create another layer above the first and place the newly created cancel button exacly at the same position as the select button.

Step 4: Dynamic Label

We’re almost done with the assets. Create another text field, this time a dynamic text field and give it the instance name “label_txt”. This will show the user the success message, the error message, or the progress percent. Make sure the text is not selectable.

Test the file, to see how it’s going.

Step 5: Document Class

We have only one more thing to do before we begin coding; set the document class to “Uploader”.

Step 6: The cCoding

In the same folder as the Flash file, create a new ActionScript file with the name “Uploader.as”. The name is important for the class to be found. Begin coding the default package and import the required classes. I’ve used “import Flash.display.*” for speed, but once we’re done, we can include only the required classes to make the file smaller.

package {

	import Flash.display.*;
	import Flash.events.*;
	import Flash.text.*;

	import Flash.net.FileReference;
	import Flash.net.FileReferenceList;
	import Flash.net.FileFilter;
	import Flash.net.URLRequest;
	import Flash.utils.Timer;
	import Flash.events.TimerEvent;

	public class Uploader extends MovieClip {

	}
}

Step 7: Variables

We’ll begin by setting a few variables:

public class Uploader extends MovieClip {

		var file:FileReference;
		var filefilters:Array;
		var req:URLRequest;
		var tm:Timer;
		var speed:Number = 0;
		var currbytes:Number = 0;
		var lastbytes:Number = 0;

	}

Step 8: Constructor Function

Create the constructor function and add the following:

	public function Uploader(){
		req = new URLRequest();
		req.url = ( stage.loaderInfo.parameters.f )? stage.loaderInfo.parameters.f : 'http://www.cbesslabs.com'; //'http://cbess.ro/templates/Flashtuts/Flash_uploader/upload.php';
		file = new FileReference();
		setup( file );
		select_btn.addEventListener( MouseEvent.CLICK, browse );
		progress_mc.bar.scaleX = 0;
		cancel_btn.addEventListener( MouseEvent.CLICK, cancelUpload );
		cancel_btn.visible = false;
	}

Let me explain what’s going on here:

We’re creating a new URLRequest class and set the url to the upload php file.

The line “( stage.loaderInfo.parameters.f )? stage.loaderInfo.parameters.f : ‘http://www.google.com’” is a conditional, meaning that if we provide the movie the parameter f, it will set the url to the f parameter. Otherwise it will use the string hardcoded here, good ol’ Google, for testing only.

We’re doing the conditional so we can reuse the file. This way, we can change only the f parameter with a path to the url and it will upload to the specified url.

Next we’re creating a new FileReference Object, the class handling the upload process. We’re passing the FileReference Object to the function setup() which we’ll later code to set up the various listeners.

Finally, we add click listeners to the select and cancel buttons, set the scale of the progressbar to 0 and hide the cancel button.

Step 9: Events

We’re now creating the setup() function.

private function setup( file:FileReference ){
	file.addEventListener( Event.CANCEL, cancel_func );
	file.addEventListener( Event.COMPLETE, complete_func );
	file.addEventListener( IOErrorEvent.IO_ERROR, io_error );
	file.addEventListener( Event.OPEN, open_func );
	file.addEventListener( ProgressEvent.PROGRESS, progress_func );
	file.addEventListener( Event.SELECT, selectHandler );
	file.addEventListener( DataEvent.UPLOAD_COMPLETE_DATA, show_message );
}

We could omit the Event.COMPLETE and Event.CANCEL event, but I have added them just for testing. We’re setting up a CANCEL event for when the user cancels the selection dialog. We have:

  • an IO_ERROR event in case the file cannot be uploaded
  • an OPEN event for when the upload begins
  • the PROGRESS event that will update the percent uploaded
  • the SELECT event for when the user has selected a file and we automatically begin uploading
  • and an UPLOAD_COMPLETE_DATA event, which is a custom event triggered when the file has been uploaded and the php file has responded to the request.

Make sure you create all the event functions otherwise you’ll get an error compiling.

Step 10: Browse

We’re continuing with the browse function, triggered when the select button has been clicked. We have to show the dialog box so the user can select a file:

public function browse( e:MouseEvent ){
	filefilters = [ new FileFilter('Images', '*.jpg') ]; // add other file filters
	file.browse( filefilters );
}

Notice that I’ve added a FileFilter object inside an array and added the array to the FileReference’s browse method. You can add another file type by adding another FileFilter object with a different extension. This will filter the file extensions on the select dialog so the user can only select correct file types. This is only a filename check and doesn’t check whether the image file is indeed an image.

Step 11: Upload

When the user has selected a file to upload, the SELECT event is triggered. We’re now calling FileReference’s upload() method to upload the file to the php file on the server with the url request argument.

private function selectHandler( e:Event ){
	file.upload( req );
}

Step 12: Button Visibility

Les’s create the open_func function. This function is triggered when the upload begins. We’ll hide the select button and show the cancel button.

private function open_func( e:Event ){
	cancel_btn.visible = true;
	select_btn.visible = false;
}

Step 13: Progress

Create the progress function:

private function progress_func( e:ProgressEvent ){
	progress_mc.bar.scaleX = e.bytesLoaded / e.bytesTotal;
	var tf = new TextFormat();
	tf.color = 0x000000;
	label_txt.defaultTextFormat = tf;
	label_txt.text = Math.round( (e.bytesLoaded/e.bytesTotal)*100)+'% uploaded';
}

Let me explain what’s going on here. We’re setting the scale of the bar movieclip showing the percent uploaded. This is accomplished by dividing the bytesLoaded to bytesTotal properties of the event object. The progress event provides us with the amount of uploaded bytes and total bytes of the file.

Next, we create a TextFormat object and set the colour to black ( 0×000000 ) for the text label. We’ll need this step because later we’ll change the colour of the text to green or red according to the message.

Finally, we set the text field’s text with the percentage uploaded.

Step 14: Error

We’ll create the error function:

private function io_error( e:IOErrorEvent ){
	var tf = new TextFormat();
	tf.color = 0xff0000;
	label_txt.defaultTextFormat = tf;
	label_txt.text = 'The file could not be uploaded.';
	cancel_btn.visible = false;
	select_btn.visible = true;
}

Basically, we change the colour of the label text, set it to an error message and then swap the cancel and select buttons again.

Step 15: Show Message

Let’s create the show_message function which will check whether the upload has been successful:

private function show_message( e:DataEvent ){
	var tf = new TextFormat();
	if( e.data == 'ok' ){
		tf.color = 0x009900;
		label_txt.defaultTextFormat = tf;
		label_txt.text = 'The file has been uploaded.';
	} else if( e.data == 'error'){
		tf.color = 0xff0000;
		label_txt.defaultTextFormat = tf;
		label_txt.text = 'The file could not be uploaded.';
	}
}

Here, we’re testing if the data property of the UPLOAD_COMPLETE_DATA event is ‘ok’ or ‘error’ and show a message appropriately. The data property of this event contains the server response from the php script.

Step 16: Cancel

This is the last function which will be triggered when the cancel button is clicked. This calls the FileReference’s cancel() function to cancel the upload. We’re also calling reset() to clean up.

private function cancelUpload( e:MouseEvent ){
	file.cancel();
	reset();
}

We trigger a reset() function to clean up the assets, set the text to "" and swap the cancel and select buttons:

private function reset(){
	cancel_btn.visible = false;
	select_btn.visible = true;
	label_txt.text = '';
	progress_mc.bar.scaleX = 0;
}

Go ahead and test the file in Flash.

For now, the upload works, but at the end we get the error message. This is because we haven’t provided the path parameter, so the swf takes the hardcoded google page. As that page doesn’t return us ‘ok’ , we get the error. We have to build the php file..

Step 17: Upload Speed – Timer

Let’s show the user the speed he is uploading with. In the constructor function add the lines:

tm = new Timer( 1000 );
tm.addEventListener( TimerEvent.TIMER, updateSpeed );

We’re creating a timer that will run every second and will check the speed.

Step 18: Upload Speed – Method

In the open_func() function add this line:

tm.start();

This will start the timer when the upload begins. We’ll now create the updateSpeed() method:

private function updateSpeed( e:TimerEvent ){
	speed = Math.floor( (currbytes - lastbytes)/1024 );
	lastbytes = currbytes;
}

This is what happens here: we’re calculating the speed by subtracting the variable lastbytes from currbytes. The lastbytes variable is afterwards set to the currbytes. So, when both variables are 0, the speed is 0. The currbytes variable will hold the current number of bytes uploaded. We cannot access this directly, that’s why we’ve created the currbytes variable. This variable will be set from our PROGRESS event where we can access the bytesLoaded property.

Lastly, we divide everything by 1024 to get the result in kilobytes and round the value for display with Math.floor().

Step 19: Final Modification

Let’s add the last modification so we can go on to the php script. In the progress_func() modify the line:

label_txt.text = Math.round( (e.bytesLoaded/e.bytesTotal)*100)+'% uploaded';

with this:

label_txt.text = Math.round( (e.bytesLoaded/e.bytesTotal)*100)+'% uploaded '+speed+' kb/s';

Step 20: Full Code

Here is the full code for the Flash uploader:

package {

	import Flash.display.*;
	import Flash.events.*;
	import Flash.text.*;

	import Flash.net.FileReference;
	import Flash.net.FileReferenceList;
	import Flash.net.FileFilter;
	import Flash.net.URLRequest;
	import Flash.utils.Timer;
	import Flash.events.TimerEvent;

	public class Uploader extends MovieClip {

		var file:FileReference;
		var filefilters:Array;
		var req:URLRequest;
		var tm:Timer;
		var speed:Number = 0;
		var currbytes:Number = 0;
		var lastbytes:Number = 0;

		public function Uploader(){
			req = new URLRequest();
			req.url = ( stage.loaderInfo.parameters.f )? stage.loaderInfo.parameters.f : 'http://www.google.com';
			file = new FileReference();
			setup( file );
			select_btn.addEventListener( MouseEvent.CLICK, browse );
			progress_mc.bar.scaleX = 0;
			tm = new Timer( 1000 );
			tm.addEventListener( TimerEvent.TIMER, updateSpeed );
			cancel_btn.addEventListener( MouseEvent.CLICK, cancelUpload );
			cancel_btn.visible = false;
		}

		public function browse( e:MouseEvent ){
			filefilters = [ new FileFilter('Images', '*.jpg') ]; // add other file filters
			file.browse( filefilters );
		}

		private function setup( file:FileReference ){
			file.addEventListener( Event.CANCEL, cancel_func );
			file.addEventListener( Event.COMPLETE, complete_func );
			file.addEventListener( IOErrorEvent.IO_ERROR, io_error );
			file.addEventListener( Event.OPEN, open_func );
			file.addEventListener( ProgressEvent.PROGRESS, progress_func );
			file.addEventListener( Event.SELECT, selectHandler );
			file.addEventListener( DataEvent.UPLOAD_COMPLETE_DATA, show_message );
		}

		private function cancel_func( e:Event ){
			trace( 'canceled !' );
		}

		private function complete_func( e:Event ){
			trace( 'complete !' );
		}

		private function io_error( e:IOErrorEvent ){
			var tf = new TextFormat();
			tf.color = 0xff0000;
			label_txt.defaultTextFormat = tf;
			label_txt.text = 'The file could not be uploaded.';
			tm.stop();
			cancel_btn.visible = false;
			select_btn.visible = true;
		}

		private function open_func( e:Event ){
			//trace( 'opened !' );
			tm.start();
			cancel_btn.visible = true;
			select_btn.visible = false;
		}

		private function progress_func( e:ProgressEvent ){
			progress_mc.bar.scaleX = e.bytesLoaded / e.bytesTotal;
			var tf = new TextFormat();
			tf.color = 0x000000;
			label_txt.defaultTextFormat = tf;
			label_txt.text = Math.round( (e.bytesLoaded/e.bytesTotal)*100)+'% uploaded '+speed+' kb/s';
			currbytes = e.bytesLoaded;
		}

		private function selectHandler( e:Event ){
			file.upload( req );

		}

		private function show_message( e:DataEvent ){
			tm.stop();
			var tf = new TextFormat();
			if( e.data == 'ok' ){
				tf.color = 0x009900;
				label_txt.defaultTextFormat = tf;
				label_txt.text = 'The file has been uploaded.';
			} else if( e.data == 'error'){
				tf.color = 0xff0000;
				label_txt.defaultTextFormat = tf;
				label_txt.text = 'The file could not be uploaded.';
			}
		}

		private function updateSpeed( e:TimerEvent ){
			speed = Math.round( (currbytes - lastbytes)/1024 );
			lastbytes = currbytes;
		}

		private function cancelUpload( e:MouseEvent ){
			file.cancel();
			reset();
		}

		private function reset(){
			cancel_btn.visible = false;
			select_btn.visible = true;
			label_txt.text = '';
			progress_mc.bar.scaleX = 0;
		}

	}
}

Step 21: The PHP Script

Let’s build our php script quickly:

<?php

$uploads_dir = './uploads/';

if( $_FILES['Filedata']['error'] == 0 ){

  if( move_uploaded_file( $_FILES['Filedata']['tmp_name'], $uploads_dir.$_FILES['Filedata']['name'] ) ){

  echo 'ok';

  exit();

  }

  }

  echo 'error';

  exit();

?>

I’ll just quickly sum this up (PHP isn’t strictly within the scope of this tut). We define a path where we will put the file, then we check whether the $_FILES['Filedata']['error'] is 0 ( if there are no errors ). We then check if move_uploaded_file() has successfully transferred the file in the folder and we show “ok” or “error” depending on the result.

One last point: you’ll have to make sure that the folder exists and it is writable before running the script.

This is the end of our tutorial. Thank you for reading, I hope you learned something!

Related Posts

Add Comment

Discussion 38 Comments

  1. fabiopb says:

    hey looks like a great tutorial! i cant get the source though… it says access denied.

  2. I have looked so much for something like this for months, and have allready given up… When today, I opened Thunderbird and saw this post over RSS!

    Thanks a lot man!

  3. Hey wait, I got the same problem also now, but still a good tutorial… :P

  4. Flash Framer says:

    Very nice tut. Thanks!

  5. Leon says:

    Looks, good. Is the max file size of the upload still limited by PHP though?

  6. Yes, the php script has to be configured, maybe with:
    ini_set(“post_max_size”) = “10M”
    ini_set(“upload_max_size”) = “10M”

    for max 10 megabytes, for example.

    There are a lot of configuration problems in uploading files, hopefully I will make a tutorial on NETTuts about this, if anyone is interested.

    • AndrĂ© says:

      the server must accept this rule for ini_set, also you can define it throught a .htaccess file, but also the server must accept this rule.

      Very nice work Sebastian, congratulations and thanks!!

  7. Roberto XSM says:

    Very good and very useful!

  8. This really helps me create other nice tutorials. Thank you for your feedback !

  9. metaisaak says:

    This is so much great! been looking for this for a while, Thanks a lot!
    i have 3 doubts:
    1.- Can we anyhow get to know if php encounters an error and a message about it?
    2.-is there a special treatment with FLVs?
    3.- A real world example of injecting the “f” variable into the flash file!

    Again thanks a lot!!
    and its great to know other developers son deep and at the same age, (well im a year older! :D )

    • 1. If there is an error, the upload will show the message ‘The file could not be uploaded’. This is why we check in the php script if $_FILES['Filedata']['error'] == 0, basically it there’s an error it will return error.

      2. There is nothing to do with the type of file, but it has to be added as an accepted filetype in as3 to work.

      3. the simplest thing is to create the link to the flash file like this:

      flash_uploader.swf?f=’your link here’

      • metaisaak says:

        Re-AWESOME! thanks and congrats again for the tutorial and for the feedback, been a while since an autor takes enough time to give feedback in comments.

  10. Awesome, thanks for this! :D

  11. Omer says:

    this is what my client wanted on his website and very clear code and explanation. Thanks million times for the tutorial!

  12. Brian says:

    Awesome dude, thanks very much for that.. If anyone else wants more flash source check out my lab.. http://www.brianwiltshire.net/lab

    Thanks again, Awesome tut

  13. Hicham says:

    thank you very much for this great tutorial.

  14. Mihails says:

    Hey! Thanx alot for this tutorial. However, i could not get it to work:
    I have a folder http://www.blabla.com/flashtuts/ where i have uploaded .swf , .php and .as files to this folder. created a folder …/flashtuts/uploads/ and have given permissions 777.
    I have changed the link in the .as file from ‘www.google.com’ to ‘www.blabla.com/flashtuts/upload.php’

    however it still does not upload. what am i doing wrong?
    Could u help me please?..

    Mihails

  15. you have to create a html page and include the flash swf as an object and then access the html page. The swf itself cannot be accesed like this.
    And you need the as file only if you recompile the swf with Flash.

  16. Osvaldo M says:

    simple yet great and extremely useful. Thanks for the tutorial mate!

  17. Ben says:

    Same problem as Mihails … I’ve done an html publish.
    is there a problem doing this in flash 10 ??

    Sniff…

  18. You probably have to run the html page from a server, not from your own computer, as there are security restrictions.

  19. Mathias Stav says:

    Nice tutorial :) but:

    hum, Im getting a syntax error.
    and flash tells me that the package can’t be nested.
    WHY???

    If the folder the files are supposed to upload to is http://www.mathias.li/upload/uploads
    is this right then:

    req.url = ( stage.loaderInfo.parameters.f )? stage.loaderInfo.parameters.f : ‘http://www.mathias.li’;

    and

    $uploads_dir = ‘/uploads/’;

  20. Asim says:

    love it! thanks Bratu Sebastian

  21. henrik says:

    Very nice tut !

    For me do everyting work untill, when the file is 100 % loaded, Then do i get a error code, – This file can’t be uploaded. Its a 200 kb jpg.

    Any idea why ?

  22. Chris says:

    EXCELLENT!!!!

    –>> BUT!!!! I have a VERY serious problem with flash uploads and this source file is no different…….

    I am ripping my hair out here.

    AFTER I click “cancel” or “upload” …. the BROWSE and UPLOAD buttons “lose focus” and need to be clicked TWICE in order to “wake” them up again.

    I have been working using MANY tutorials and examples – including my own – and the problem is consistent, on any mac or pc platform, in any browser, and I am going bald ripping my hair out about this.

    I have tried to isolate the problem and it ONLY occurs after the OS file browser window has been initiated and closed.

    It breaks ALL my buttons in every level of the container SWF….. then I created a STAND-ALONE version… same exact thing.

    I am standing here with my hat in my hand for a solution if you can help.

    I would be most grateful.

    Once again thanks for your excellent AS3 example…. but unfortunately the same exact problem occurs.

    A thousand thanks in advance to anyone who can provide a solution.

  23. Sebastian says:

    Hey! Great tutorial!

    Is it possible to show the finale URL to the file when it uploaded? Need to be able to copy and send the URL link.

    Thanx for the help!

  24. kires says:

    thank you Bratu Sebastian. very useful. cheers!

  25. Khalid Sharif says:

    is there any way to rename the files after the upload ?

  26. alexber says:

    I have an actual question about sessions. after uploading file uploader calls to upload.php, where i taking some parameters from session, to write some user data in Database. Bat session work correctly only in IE in other browser sessions do not work. How can i solve this problem? Or what can i do for translate session parameter throughout uploader. Thank.

  27. Rui Palmeira says:

    is there any way of using this example, and instead being only able to upload 1 file, being able to upload various files at a time ??

    peace

  28. Brent P says:

    anyone try and change the PHP into asp.net????

  29. motty says:

    hi,

    thanks so much for the tut. Great!

    One massive issue however, on any browser on Windows 7 the progress goes straight to 100% and then sits there as the file uploads.

    Anyone else had an issue with this. It would seem it’s a flash bug…

  30. Brian says:

    very well written and very much appreciated. Thanks.

  31. Bob Snow says:

    >>Author: Bratu Sebastian
    I am a 22 year old web developer and musician from Romania. I love php,jquery,flash,as3 and lose 80% of my nights with them. I also have a lot of business ideas that I never get to build. I like to build lots of websites.<<

    I need a change to Flash from Java with my Navigation. Left side of my Web Site.

  32. Milan says:

    I have a question.

    Where is the command that says that the upload will send the data to upload.php?

    I suppose the variable url? Am I right?

    Thanks.

Add a Comment