Adobe Flex 3 Help

Working with file upload and download

The FileReference class lets you add the ability to upload and download files between a client and a server. Users are prompted to select a file to upload or a location for download from a dialog box (such as the Open dialog box on the Windows operating system).

Each FileReference object that you create with ActionScript refers to a single file on the user's hard disk. The object has properties that contain information about the file's size, type, name, creation date, and modification date.

Note: The creator property is supported on Mac OS only. All other platforms return null.

You can create an instance of the FileReference class in two ways. You can use the new operator, as the following code shows:

import flash.net.FileReference;
var myFileReference:FileReference = new FileReference();

Or you can call the FileReferenceList.browse() method, which opens a dialog box on the user's system to prompt the user to select one or more files to upload and then creates an array of FileReference objects if the user selects one or more files successfully. Each FileReference object represents a file selected by the user from the dialog box. A FileReference object does not contain any data in the FileReference properties (such as name, size, or modificationDate) until one of the following happens:

  • The FileReference.browse() method or FileReferenceList.browse() method has been called, and the user has selected a file from the file picker.
  • The FileReference.download() method has been called, and the user has selected a file from the file picker.

Note: When performing a download, only the FileReference.name property is populated before the download is complete. After the file has been downloaded, all properties are available.

While calls to the FileReference.browse(), FileReferenceList.browse(), or FileReference.download() method are executing, most players will continue SWF file playback.

Subtopics



FileReference class

The FileReference class allows you to upload and download files between a user's computer and a server. An operating system dialog box prompts the user to select a file to upload or a location for download. Each FileReference object refers to a single file on the user's disk and has properties that contain information about the file's size, type, name, creation date, modification date, and creator.

FileReference instances can be created in two ways:

  • When you use the new operator with the FileReference constructor, as in the following:

    var myFileReference:FileReference = new FileReference();

  • When you call FileReferenceList.browse(), which creates an array of FileReference objects.

For uploading and downloading operations, a SWF file can access files only within its own domain, including any domains specified by a cross-domain policy file. You need to put a policy file on the file server if the SWF file initiating the upload or download doesn't come from the same domain as the file server.

Note: You can only perform one browse() or download() action at a time, because only one dialog box can be open at any point.

The server script that handles the file upload should expect an HTTP POST request with the following elements:

  • Content-Type with a value of multipart/form-data.
  • Content-Disposition with a name attribute set to "Filedata" and a filename attribute set to the name of the original file. You can specify a custom name attribute by passing a value for the uploadDataFieldName parameter in the FileReference.upload() method.
  • The binary contents of the file.

Here is a sample HTTP POST request:

POST /handler.asp HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
User-Agent: Shockwave Flash
Host: www.mydomain.com
Content-Length: 421
Connection: Keep-Alive
Cache-Control: no-cache

------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6 
Content-Disposition: form-data; name="Filename"

sushi.jpg 
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
Content-Disposition: form-data; name="Filedata"; filename="sushi.jpg"
Content-Type: application/octet-stream

Test File 
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
Content-Disposition: form-data; name="Upload"

Submit Query
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
(actual file data,,,)

The following sample HTTP POST request sends three POST variables: api_sig, api_key, and auth_token, and uses a custom upload data field name value of "photo":

POST /handler.asp HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
User-Agent: Shockwave Flash
Host: www.mydomain.com
Content-Length: 421
Connection: Keep-Alive
Cache-Control: no-cache

------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"

sushi.jpg
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="api_sig"

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="api_key"

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="auth_token"

XXXXXXXXXXXXXXXXXXXXXXX
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="photo"; filename="sushi.jpg"
Content-Type: application/octet-stream

(actual file data,,,)
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"

Submit Query
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--

Uploading files to a server

To upload files to a server, first call the browse() method to allow a user to select one or more files. Next, when the FileReference.upload() method is called, the selected file will be transferred to the server. If the user selected multiple files using the FileReferenceList.browse() method, Flash Player creates an array of selected files called FileReferenceList.fileList. You can then use the FileReference.upload() method to upload each file individually.

Note: Using the FileReference.browse() method allows you to upload single files only. To allow a user to upload multiple files, you must use the FileReferenceList.browse() method.

By default, the system file picker dialog box allows users to pick any file type from the local computer, although developers can specify one or more custom file type filters by using the FileFilter class and passing an array of file filter instances to the browse() method:

var imageTypes:FileFilter = new FileFilter("Images (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg; *.jpeg; *.gif; *.png");
var textTypes:FileFilter = new FileFilter("Text Files (*.txt, *.rtf)", "*.txt; *.rtf");
var allTypes:Array = new Array(imageTypes, textTypes);
var fileRef:FileReference = new FileReference();
fileRef.browse(allTypes);

When the user has selected the files and clicked the Open button in the system file picker, the Event.SELECT event is dispatched. If the FileReference.browse() method was used to select a file to upload, the following code is needed to send the file to a web server:

var fileRef:FileReference = new FileReference();
fileRef.addEventListener(Event.SELECT, selectHandler);
fileRef.addEventListener(Event.COMPLETE, completeHandler);
try
{
    var success:Boolean = fileRef.browse();
}
catch (error:Error)
{
    trace("Unable to browse for files.");
}
function selectHandler(event:Event):void
{
    var request:URLRequest = new URLRequest("http://www.[yourdomain].com/fileUploadScript.cfm")
    try
    {
        fileRef.upload(request);
    }
    catch (error:Error)
    {
        trace("Unable to upload file.");
    }
}
function completeHandler(event:Event):void
{
    trace("uploaded");
}

You can send data to the server with the FileReference.upload() method by using the URLRequest.method and URLRequest.data properties to send variables using the POST or GET methods.

When you attempt to upload a file using the FileReference.upload() method, any of the following events may be dispatched:

  • Event.OPEN: Dispatched when an upload operation starts.
  • ProgressEvent.PROGRESS: Dispatched periodically during the file upload operation.
  • Event.COMPLETE: Dispatched when the file upload operation completes successfully.
  • SecurityErrorEvent.SECURITY_ERROR: Dispatched when an upload fails because of a security violation.
  • HTTPStatusEvent.HTTP_STATUS: Dispatched when an upload fails because of an HTTP error.
  • IOErrorEvent.IO_ERROR: Dispatched if the upload fails because of any of the following reasons:
    • An input/output error occurred while Flash Player is reading, writing, or transmitting the file.
    • The SWF tried to upload a file to a server that requires authentication (such as a user name and password). During upload, Flash Player does not provide a means for users to enter passwords.
    • The url parameter contains an invalid protocol. The FileReference.upload() method must use either HTTP or HTTPS.

Flash Player does not offer complete support for servers that require authentication. Only SWF files that are running in a browser using the browser plug-in or Microsoft ActiveX® control can provide a dialog box to prompt the user to enter a user name and password for authentication, and then only for downloads. For uploads using the plug-in or ActiveX control or upload/download using either the stand-alone or external player, the file transfer fails.

If you create a server script in ColdFusion to accept a file upload from Flash Player, you can use code similar to the following:

<cffile action="upload" filefield="Filedata" destination="#ExpandPath('./')#" nameconflict="OVERWRITE" />

This ColdFusion code uploads the file sent by Flash Player and saves it to the same directory as the ColdFusion template, overwriting any file with the same name. The previous code shows the bare minimum amount of code necessary to accept a file upload; this script should not be used in a production environment. Ideally, you should add data validation to ensure that users upload only accepted file types, such as an image instead of a potentially dangerous server-side script.

The following code demonstrates file uploads using PHP, and it includes data validation. The script limits the number of uploaded files in the upload directory to 10, ensures that the file is less than 200 KB, and permits only JPEG, GIF, or PNG files to be uploaded and saved to the file system.

<?php
$MAXIMUM_FILESIZE = 1024 * 200; // 200KB
$MAXIMUM_FILE_COUNT = 10; // keep maximum 10 files on server
echo exif_imagetype($_FILES['Filedata']);
if ($_FILES['Filedata']['size'] <= $MAXIMUM_FILESIZE)
{
    move_uploaded_file($_FILES['Filedata']['tmp_name'], "./temporary/".$_FILES['Filedata']['name']);
    $type = exif_imagetype("./temporary/".$_FILES['Filedata']['name']);
    if ($type == 1 || $type == 2 || $type == 3)
    {
        rename("./temporary/".$_FILES['Filedata']['name'], "./images/".$_FILES['Filedata']['name']);
    }
    else
    {
        unlink("./temporary/".$_FILES['Filedata']['name']);
    }
}
$directory = opendir('./images/');
$files = array();
while ($file = readdir($directory))
{
    array_push($files, array('./images/'.$file, filectime('./images/'.$file)));
}
usort($files, sorter);
if (count($files) > $MAXIMUM_FILE_COUNT)
{
    $files_to_delete = array_splice($files, 0, count($files) - $MAXIMUM_FILE_COUNT);
    for ($i = 0; $i < count($files_to_delete); $i++)
    {
        unlink($files_to_delete[$i][0]);
    }
}
print_r($files);
closedir($directory);

function sorter($a, $b)
{
    if ($a[1] == $b[1])
    {
        return 0;
    }
    else
    {
        return ($a[1] < $b[1]) ? -1 : 1;
    }
}
?>

You can pass additional variables to the upload script using either the POST or GET request method. To send additional POST variables to your upload script, you can use the following code:

var fileRef:FileReference = new FileReference();
fileRef.addEventListener(Event.SELECT, selectHandler);
fileRef.addEventListener(Event.COMPLETE, completeHandler);
fileRef.browse();
function selectHandler(event:Event):void
{
    var params:URLVariables = new URLVariables();
    params.date = new Date();
    params.ssid = "94103-1394-2345";
    var request:URLRequest = new URLRequest("http://www.yourdomain.com/FileReferenceUpload/fileupload.cfm");
    request.method = URLRequestMethod.POST;
    request.data = params;
    fileRef.upload(request, "Custom1");
}
function completeHandler(event:Event):void
{
    trace("uploaded");
}

The previous example creates a new URLVariables object that you pass to the remote server- side script. In previous versions of ActionScript, you could pass variables to the server upload script by passing values in the query string. ActionScript 3.0 allows you to pass variables to the remote script using a URLRequest object, which allows you to pass data using either the POST or GET method; this, in turn, makes passing larger sets of data easier and cleaner. In order to specify whether the variables are passed using the GET or POST request method, you can set the URLRequest.method property to either URLRequestMethod.GET or URLRequestMethod.POST, respectively.

ActionScript 3.0 also lets you override the default Filedata upload file field name by providing a second parameter to the upload() method, as demonstrated in the previous example (which replaced the default value Filedata with Custom1).

By default, Flash Player will not attempt to send a test upload, although you can override this by passing a value of true as the third parameter to the upload() method. The purpose of the test upload is to check whether the actual file upload will be successful and that server authentication, if required, will succeed.

Note: A test upload occurs only on Windows-based Flash Players at this time.

Downloading files from a server

You can let users download files from a server using the FileReference.download() method, which takes two parameters: request and defaultFileName. The first parameter is the URLRequest object that contains the URL of the file to download. The second parameter is optional--it lets you specify a default filename that appears in the download file dialog box. If you omit the second parameter, defaultFileName, the filename from the specified URL is used.

The following code downloads a file named index.xml from the same directory as the SWF document:

var request:URLRequest = new URLRequest("index.xml");
var fileRef:FileReference = new FileReference();
fileRef.download(request);

To set the default name to currentnews.xml instead of index.xml, specify the defaultFileName parameter, as the following snippet shows:

var request:URLRequest = new URLRequest("index.xml");
var fileToDownload:FileReference = new FileReference();
fileToDownload.download(request, "currentnews.xml");

Renaming a file can be very useful if the server filename was not intuitive or was server-generated. It's also good to explicitly specify the defaultFileName parameter when you download a file using a server-side script, instead of downloading the file directly. For example, you need to specify the defaultFileName parameter if you have a server-side script that downloads specific files based on URL variables passed to it. Otherwise, the default name of the downloaded file is the name of your server-side script.

Data can be sent to the server using the download() method by appending parameters to the URL for the server script to parse. The following ActionScript 3.0 snippet downloads a document based on which parameters are passed to a ColdFusion script:

package
{
    import flash.display.Sprite;
    import flash.net.FileReference;
    import flash.net.URLRequest;
    import flash.net.URLRequestMethod;
    import flash.net.URLVariables;

    public class DownloadFileExample extends Sprite
    {
        private var fileToDownload:FileReference;
        public function DownloadFileExample()
        {
            var request:URLRequest = new URLRequest();
            request.url = "http://www.[yourdomain].com/downloadfile.cfm";
            request.method = URLRequestMethod.GET;
            request.data = new URLVariables("id=2");
            fileToDownload = new FileReference();
            try
            {
                fileToDownload.download(request, "file2.txt");
            }
            catch (error:Error)
            {
                trace("Unable to download file.");
            }
        }
    }
}

The following code demonstrates the ColdFusion script, download.cfm, that downloads one of two files from the server, depending on the value of a URL variable:

<cfparam name="URL.id" default="1" />
<cfswitch expression="#URL.id#">
    <cfcase value="2">
        <cfcontent type="text/plain" file="#ExpandPath('two.txt')#" deletefile="No" />
    </cfcase>
    <cfdefaultcase>
        <cfcontent type="text/plain" file="#ExpandPath('one.txt')#" deletefile="No" />
    </cfdefaultcase>
</cfswitch>

FileReferenceList class

The FileReferenceList class lets the user select one or more files to upload to a server-side script. The file upload is handled by the FileReference.upload() method, which must be called on each file that the user selects.

The following code creates two FileFilter objects (imageFilter and textFilter) and passes them in an array to the FileReferenceList.browse() method. This causes the operating system file dialog box to display two possible filters for file types.

var imageFilter:FileFilter = new FileFilter("Image Files (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg; *.jpeg; *.gif; *.png");
var textFilter:FileFilter = new FileFilter("Text Files (*.txt, *.rtf)", "*.txt; *.rtf");
var fileRefList:FileReferenceList = new FileReferenceList();
try
{
    var success:Boolean = fileRefList.browse(new Array(imageFilter, textFilter));
}
catch (error:Error) 
{
    trace("Unable to browse for files.");
}

Allowing the user to select and upload one or more files by using the FileReferenceList class is the same as using FileReference.browse() to select files, although the FileReferenceList allows you to select more than one file. Uploading multiple files requires you to upload each of the selected files by using FileReference.upload(), as the following code shows:

var fileRefList:FileReferenceList = new FileReferenceList();
fileRefList.addEventListener(Event.SELECT, selectHandler);
fileRefList.browse();

function selectHandler(event:Event):void
{
    var request:URLRequest = new URLRequest("http://www.[yourdomain].com/fileUploadScript.cfm");
    var file:FileReference;
    var files:FileReferenceList = FileReferenceList(event.target);
    var selectedFileArray:Array = files.fileList;
    for (var i:uint = 0; i < selectedFileArray.length; i++)
    {
        file = FileReference(selectedFileArray[i]);
        file.addEventListener(Event.COMPLETE, completeHandler);
        try
        {
            file.upload(request);
        }
        catch (error:Error)
        {
            trace("Unable to upload files.");
        }
    }
}
function completeHandler(event:Event):void
{
    trace("uploaded");
}

Because the Event.COMPLETE event is added to each individual FileReference object in the array, Flash Player calls the completeHandler() method when each individual file finishes uploading.