How to create a file upload application using the FileReference API
One of the largest demands from the Flash development community was a file system that could be used for file upload and downloading. A lot of the users/developers were hoping Macromedia can implement a new function/object in Flash 8 regarding to this issue. When Macromedia developed Flash 8, they incorporated the fileReference Object, which allows the SWF file access the user's machine and thus able to perform the file upload and download operation.

Before we jump into the coding part, let's look at the overall picture on how the FileReference Object transfers the user's file to the web server.

FIGURE1: Traffic flow of the FileReference Object

FIGURE 1: Traffic flow of the FileReference Object

The FileReference Object first open up a file browsing dialog window on the user's machine with the browse() method and prompt the user to select a local file to upload. Once the user select the file to upload, the FileReference Object will upload the selected file to a web server that is specified in the upload() method. Once the file is uploaded by the FileReference Object, it will not be uploaded to the web server immediately, instead it will be uploaded to the browser's temp directory. The server side script then comes in and it will check the existence of the upload file. If the file exists then the server side script will move the file from the browser's temp directory to the specify directory of the server. It sounds complicated, believe me, it's not that bad.

Let's take a closer look at the FileReference Object. There are two kinds of FileReference Object:
However, each FileReference Object refers to a single file on the user's hard disk and has the properties of file size, type, name, creation date, modification date, and creator type (Macintosh only). These properties of the file will be available once the user has selected a file to upload in the dialog box. In this tutorial, we will be focusing on a single file uploading; as a result we will not discuss the FileReferenceList class.

Note Due to security reasons you CANNOT get the file path of the file which you are uploading to the server.

Other then the properties that was mentioned above, there are a few methods that are available for the FileReference API:
The above methods explain themselves pretty well, now we can see how these methods comes in play in the FileReference API

The browse() method opens an operating-system dialog box which prompts the user to select any local file for upload. After a successful call to the browse() method, the upload() method or download() method comes in to play. The upload() method will upload one file at a time and the download() method will prompt the user for a location to save the file and initiates downloading from a remote URL.

Note The download() method is not use in this tutorial, because you can always download a newly uploaded file by type in the server upload directory + the newly add file name.

The FileReference API do not allow you to set the default file location for the dialog box generated by browse() and download() methods. The default location shown in the dialog box is the most recently browsed folder. If such location cannot be determined, the default location will then direct to the user desktop. The FileReference API does not allow you to read from or write to the transferred file. They do not allow the SWF file that initiated the upload or download to access the uploaded or downloaded file or the file's location on the user's disk.

Note You must call FileReference.browse() before calling the download() or upload() method.

We now have enough knowledge to implement a File Upload Application, however we may need some progress checking and Error checking mechanisms, as a result I introduce you the events that are available to the FileReference class.

Note Flash Player can upload files of up to 100MB, also a file size may be limited by the web server itself.

onCancel = function(fileRef:FileReference) {}
Invoked when the user dismisses the file-browsing dialog box. (clicking the cancel button in the dialog box).

onComplete = function(fileRef:FileReference) {}
Invoked when the upload or download operation has successfully completed.

onHTTPError = function(fileRef:FileReference, httpError:Number) {}
Invoked when an upload fails because of an HTTP error.

Note: This event applies only to File Upload and not File Download. If a file download fails, an IO Error is reported instead of a HTTP Error.

onIOError = function(fileRef:FileReference) {}
Invoked when an input/output error occurs.

onOpen = function(fileRef:FileReference) {}
Invoked when an upload or download operation starts.

onProgress = function(fileRef:FileReference, bytesLoaded:Number, bytesTotal:Number) {}
Invoked periodically during the file upload or download operation.


onSecurityError = function(fileRef:FileReference, errorString:String) {}
Invoked when an upload or download fails because of a security error.

Note: In most of the cases this error occurs due to the sandbox restriction, which means the calling SWF file may have tried to access a SWF file outside its domain and does not have permission to do so. You can try to remedy this error by using a cross-domain policy.

onSelect = function(fileRef:FileReference) {}
Invoked when the user selects a file to upload or download from the file-browsing dialog box.

Now we have all the assets that we need, let's get into implementing an example using FileReference API which will be an application which you can upload files into a web server.

So what do you need to implement this example?
  • The Flash application
  • A PHP/ASP/JSP page which will catch the file stream and create the file on the server. In our example, I have chosen to use a PHP script
  • A folder on the Web Server with full read and write permission.
FIGURE2: FileReference API application flow char

FIGURE2: FileReference API application flow char

The example we are going to implement will be composed of two parts: one Flash file that will access the file system and grab the file and one PHP page that will do the work of uploading the file to the web server. Create a new PHP file, save it as upload.php, and paste the follow script inside:

<?php
 if (is_uploaded_file($_FILES['Filedata']['tmp_name'])){

	$uploadDirectory="uploads/";
	$uploadFile=$uploadDirectory.basename($_FILES['Filedata']['name']);
				
	copy($_FILES['Filedata']['tmp_name'], $uploadFile);
		
 }
?> 
This page is called by the upload() method from the Flash file, when a file is ready to upload. As we discussed before, the file will be resident in the browser's temp directory, the PHP script first checks to see whether the file is there by using is_uploaded_file() method. Then we define the directory that the file to be uploaded to (the folder name is uploads in our example). Finally we move the file from the browser's temp directory to the folder uploads.

Now we can jump to the Flash part. Create a new Flash file and save it as fileUpload.fla. Create a new layer on your timeline, rename the top layer to action and the bottom layer to content. In the content layer create the following components and name the instance as shown in the figure beneath

FIGURE3: Instance Name label

FIGURE3: Instance Name label

In the action layer paste the following code in frame 1:
//import the FileReference Object
import flash.net.FileReference;
//initial settings-since no upload file type selet yet 
//user cannot upload a file
uploadButn.enabled = false;
browseButn.enabled = false
//create a new FileReference object
var fileRef:FileReference = new FileReference();
//create a listener object for FileReference events
var fileRefListener:Object = new Object();
//create a listener object for comboBox events
var myComBoxListener:Object = new Object();

var isDefault:Boolean = false;

//a small function to redraw (reset) the progress bar
function reDrawPB (pb, xCor, yCor) {
	_root.destroyObject(pb);
	_root.createObject("progressbar",pb,0);
   	_root.progressbar.move(xcor,ycor);
}
	

//===================== combo box event handler =====================//

mycomboxlistener.change = function(obj) {
	filetype = obj.target.selectedItem.label
	
	switch (filetype) {
		case "Images": 
			fileDescription = "Images";
			fileExtension = "*.jpg; *.jpeg; *.gif; *.png";
			reDrawPB ("progressBar", 215.9, 128);
			break;
		case "Text Files":
			fileDescription = "Text Files";
			fileExtension = "*.txt; *.rtf; *.doc";
			reDrawPB ("progressBar", 215.9, 128);
			break;
		case "Zip Files":
			fileDescription = "Zip File";
			fileExtension = "*.zip";
			reDrawPB ("progressBar", 215.9, 128);
			break;
		default:
			isDefault = true;
			trace (isDefault);
			break;
	}
	
	status_txt.vPosition = status_txt.maxVPosition;
	
	if (isDefault == true) {
	  //text area clear when user select different file types
	  status_txt.text="";
	  browseButn.enabled = false;
	  isDefault = false;
	}else {
	  status_txt.text=fileDescription+' '+'('+fileExtension+')'+'\n';
	  browseButn.enabled = true;
	}
}
//apply object listener to the file reference object
fileType.addEventListener("change", myComBoxListener);

//=================== FILEREFERENCE EVENT HANDLER ===================//

//When user selects a file from the file-browsing dialog box, 
//the onSelect() method is called, 
//and passed a reference to the FileReference object
fileRefListener.onSelect = function (fileRef:FileReference):Void {
	uploadButn.enabled = true;
	reDrawPB("progressBar", 215.9, 128);
	status_txt.vPosition = status_txt.maxVPosition;	
	status_txt.text += "File is selected to upload \n";
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "-------------FILE DETAILS------------- \n";
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "File Size: " + fileRef.size + " bytes" + '\n';
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "File Type: " + fileRef.type + '\n';
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "File Name: " + fileRef.name + '\n';
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "Date Created: " + fileRef.creationDate + '\n';
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text +="Date Modified: "+fileRef.modificationDate+'\n';
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "--------------------------------------- \n";
}

//When user dismiss the file-browsing dialog box, 
//the onCancel() method is called, 
//and passed a reference to the FileReference object
fileRefListener.onCancel = function (fileRef:FileReference):Void {
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text +="User terminated file upload. \n";
}

//When the file upload/download process started, 
//the onOpen() method is called, 
//and passed a reference to the FileReference object
fileRefListener.onOpen = function (fileRef:FileReference):Void {
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text +="Opening file " + fileRef.name + '\n';	
}

//The onProgress() method is called periodically 
//during the file upload operation
fileRefListener.onProgress = function (fileRef:FileReference, 
bytesLoaded:Number, bytesTotal:Number):Void {
	//setting the status bar function
	progressBar.mode = "manual";
	progressBar.setProgress(bytesLoaded, bytesTotal);
}

//When the file upload/download operation is successfully complete, 
//the onComplete() method is called, 
//and passed a reference to the FileReference object
fileRefListener.onComplete = function (fileRef:FileReference):Void {
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text += "The "+fileRef.name + " ha been uploaded.\n";
	//upload is now complete, disable the upload & browse button
	uploadButn.enabled = false;
}

//******************* ERROR EVENT HANDLING *******************//

//This method will be called if and only if an upload fails 
//because of an HTTP error
fileRefListener.onHTTPError=function(fileRef:FileReference, error:Number){
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text +=
	"HTTPerror:with "+fileRef.name+" :error #"+error+'\n';
}

//This method will be called if and only if a file input/output error occur
fileRefListener.onIOError = function (fileRef:FileReference) {
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text +="HTTP error: with " + fileRef.name + '\n';
}

//This method will be called if and only if an upload fails 
//make sure you type in the same URL as the upload() method
//Please check cross domain policy
fileRefListener.onSecurityError=
function (fileRef:FileReference, errorString:String) {
	status_txt.vPosition = status_txt.maxVPosition;
	status_txt.text +=
	"Security error: with "+fileRef.name+" : "+errorString+'\n';
}
//********************************************************//

//attach Listener to the FileReference Object
fileRef.addListener(fileRefListener);

//button event for the browse button
browseButn.clickHandler = function () {
  //The browse function is the key, coz it displays a file-browsing 
  //dialog box in which the user can select a local file to upload
  fileRef.browse([{description:fileDescription,extension:fileExtension}]);
}

//Button event for the upload button
uploadButn.clickHandler = function () {
  status_txt.vPosition = status_txt.maxVPosition;
  status_txt.text +="Attempting to upload " + fileRef.name + '\n';
  //upload the file to the PHP script on the server
  //put your domain in the upload() method
  //Example: 
  //fileRef.upload("http://www.markshu.ca/imm/flash/tutorial/upload.php");
  fileRef.upload("put your domain + upload.php here");
}
In the preceding code we do quite a few things. First and the most important we import the fileReference object so that we can access the file system. Then we create a new instance of the Object and name it fileRef. Then we create two listeners, one for the fileRef Object and another one for our comboBox component. Majority of the events (onSelect, onComplete, ¡K.) should be self-explanatory, then we have our error checking events (HTTP, IO, and Security error). These built events allow us to know if any of these errors arise during the file upload operation. Then we attach the fileRefListener to our instance of the Object. We then assign the click handlers to the select and upload buttons. Notice that we specify what file types to upload.
fileRef.browse([{description: fileDescription, extension: fileExtension}]);
Wthin the browse() method we have an array as an argument and the array contain two elements:
  • Description, which will show in the bottom of the dialog box
  • Extension, which is where we limit what type of file to upload.
Note I have predefine three file types by using the comboBox component, in order to change the file types you have to :
  • change the Parameters of the comboBox
  • modify the comBox event handler switch statement
FIGURE 4: Parameters setting for comboBox component

FIGURE 4: Parameters setting for comboBox component

The argument of the browse() method is optional, if we do not pass in the array, the browse() method will allow the user to select any file types.

The upload button click handler used the upload() method to pass our fileRef Object to the upload.php page.

Note The URL path that get passed in to the upload() method can be either an absolute path or a relative path. However because of cross domain policy, when you are using absolute path, please ensure you type in the same absolute path in the browser in order to avoid the Security Error.

Now we have both the Flash and PHP files ready, we will need to create the upload folder in our web server. In the same directory as your published files, create a directory and name it uploads with full read and write permissions for public users.

If you followed the instructions along, you should now have an application which allows you to upload different types of files to your server.
Download the example files here

Unzip the archive into a folder and upload it to your web server and you are ready to upload files into the server.

Note In order for the application to work correctly, please ensure you modified the followings:
  • URL within the upload() method in the fileUpload.fla
  • edit the uploadDirectory variable in the upload.php
  • create a folder with the same name as you have assign to the $target_path variable in the previous step


Questions? Click here to contact me.