Fx{r} is trying to start the Fx{r} Community! Please join our group on Adobe Groups following this link: http://groups.adobe.com/groups/ab29539ab9.
Fx{r} is now on Twitter too. Follow us @ twitter.com/fx_r!
«
»

AMF, ActionScript, Components, Flash Builder 4, Flex 4 SDK, How to, MXML, PHP

Multiple File Upload Using AMFPHP

Andrei Ionescu | 02.09.09 | 7 Comments

Google Buzz

What is AMF and a bit of history

Action Message Format (AMF) is a compact binary format that is used to serialize ActionScript object graphs. Once serialized an AMF encoded object graph may be used to persist and retrieve the public state of an application across sessions or allow two endpoints to communicate through the exchange of strongly typed data.

AMF was introduced in Flash Player 6 in 2001 and remained unchanged with the introduction of Actionscript 2.0 in Flash Player 7 and with the release of Flash Player 8. This version of AMF is referred to as AMF 0. In Flash Player 9, Action Script 3.0 was introduced along with a new Actionscript Virtual Machine (AVM+) – the new data types and language features made possible by these improvements prompted AMF to be updated. Given the opportunity to release a new version of AMF, several optimizations were also made to the encoding format to remove redundant information from serialized data.

Why AMF?

  1. AMF is a compact binary format which means few bits to be transferred from the server to the client.
  2. Using AMF you can call methods from the server as the method would be in you Actionscript code.
    In my opinion these two are the main advantages of AMF. There are others advantages as well that you may find important.

Some stats about AMF and its concurrent protocols available can be seen on James Ward’s Census Application (http://www.jamesward.com/census).

What you need

In order to complete this article you need the following things:

  1. Flash Builder 4 (http://labs.adobe.com/technologies/flashbuilder4) or other IDE with Flex 4 SDK
  2. AMFPHP (http://www.amfphp.org)
  3. Local LAMP server (ex: Zend Server Community Edition, XAMPP, WAMP, etc)

Once you have those requirements satisfied we can go on.

At this moment the last version of AMFPHP is 1.9.

Setting up the server side

First of all create a folder in your htdocs or an alias so the web services, will be made available through your installed web server. In that place create a folder called webservices. Copy everything (but not the .htaccess file) that is in amf folder of the AMFPHP archive downloaded from amfphp.org to webservices folder. All your PHP web services will be in webservices/services folder.

Another thing to know is that you may need to put a crossdomain.xml file so the resulting swf file will be able to connect to the web services.

On same level with the webservices folder create _uploads folder (include the first underline). In this folder we will save our uploaded files.

This should be enough for now and we will go further to the next step.

Creating our upload web service

Create a new php file in webservices/services folder called upload.php. This will be the file that will contain our upload class and its methods and all its methods will be available in our flex upload application.

Create a class called upload as the file’s name. This class will have only one method named uploadFiles.

This method takes an object ($fileData) as parameter. This object contains the filename ($fileData["filename"]) and the file content as byte array ($fileData["filedata"]). The method gets those two and saves the file on the server location. It always returns true if it doesn’t crash. In case of a crash that means the file is not saved or an error is in our web service in which case we assume that the file is not saved. See upload.php bellow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class upload {
 
    // method saves files on the server
    function uploadFiles($fileData) {
        // new file path an name
        // to not overwrite the files we add the microtime before the file name 
        $myFilePath = '../../_uploads/'.
            preg_replace("/[^0-9]+/","_",microtime()).'_'.$fileData["filename"];
        // writing on the disk
        file_put_contents($myFilePath, $fileData["filedata"]);
        // returning response - is not used anywhere 
        return true;
    }    
 
}

Getting into the client side

We will use the Spark components of the Flex 4 SDK. This will ease up a lot the development needed to finalize our application. The states will help us a lot.

Bellow in you can see the content of my MultipleFileUploadUsingAMFPHP project.

MultipleFileUploadUsingAMFPHP Flex Project

Let’s look at the attributes of declaration which contains the paths and settings to reach to our upload web service. Our web service file is called upload.php and can be found in webservices/services/ folder. The url to our web server location is http://localhost/multiplefileupload/.

  • endpoint: this must point to gateway.php; in our case the url is http://localhost/multiplefileupload/webservices/gateway.php
  • source: this is the filename of the PHP file containing the web service without the “.php” extension; in our case is upload
  • destination: is the method from the file and class defined in source; in our case uploadFiles

These three are the attributes to reach the web service. Of course we set up the result and fault event handlers, the id and the showBusyCursor to true to visually show that the application is working.

Now we will define four states that will display different components depending of the state we are in.

  1. initUpload: the first state that will be displayed at starting

    MultipleFileUploadUsingAMFPHP Flex Project

  2. beforeUploading: this will show the list with the files chosen and some buttons

    MultipleFileUploadUsingAMFPHP Flex Project

  3. inUploadProcess: this will show the progress and will have a button for canceling the process

    MultipleFileUploadUsingAMFPHP Flex Project

  4. uploadFinalized: this will show all the files and the finalized button

    MultipleFileUploadUsingAMFPHP Flex Project

Next we will have a panel that will contain a Spark list and a few buttons that will appear according to the state we are in. I will not stop explaining about the new features of Flex 4 SDK and Flash Builder 4 because that is over our scope for now.

A bit of theory – how the upload process work

Now I want to explain how the upload process will work. The whole process is based on a stack idea. Files are uploaded one at a time. After the current file is uploaded or it has failed the next one will take its place and will be processed.

All files that have been chosen for upload are stored in a FileReferenceList object (_refAddFiles). We will iterate through it and we will add each FileReference object to _arrUploadFiles array collection. This array collection is used to display the files in a list and iterate through it to process each file reference object.

The process is started calling startUpload() method. These are the steps taken for each file reference object from _arrUploadFiles array collection:

  1. We add a complete event to current file reference
     
    _arrUploadFiles[_numCurrentUpload].data.addEventListener(
        Event.COMPLETE, handleFileLoadedComplete
    );
  2. We instruct it to load the file in the application memory
     
    _arrUploadFiles[_numCurrentUpload].data.load();
  3. When the file is loaded into the memory handleFileLoadedComplete is triggered
  4. After the file is loaded into the memory we can read the content of the file
     
    var tmpFileContent:String = 
        fileRef.data.readUTFBytes(fileRef.data.length);
  5. We call the upload web service
     
    myUploadService.uploadFiles(
        {filedata:tmpFileContent, filename:fileRef.name}
    );
  6. The upload web service which is defined at the beginning with the tag will trigger one of its event handlers:
    • result event if it is a success – myUploadService_resultHandler
    • fault event if it is a failure – myUploadService_faultHandler
  7. Result event will show in the list if the upload was successful with a green dot and the fault event will show that it has been an error and a failure with a red dot
  8. The current file number is incremented and the process is started again with startUpload() method

These are the steps taken for each file contained in a file reference object from _arrUploadFiles array collection.

You should notice that you need to use readUTFBytes method to get the content of the file and send them through the web service. Also you will be able to read the data of a file reference (fileRef.data) only after the files is loaded. This means that load() method must be called and the when the load is complete a complete event is triggered. After this the fileRef.data is available.

The main application code listing can be seen in the source archive. I will not put the whole code here because has lots of lines.

About the custom list item renderer

In order to display a feedback icon for each file we have to create a custom item renderer for our Spark list control. We tell the list that we are using a custom item renderer by specifying the item renderer attribute like bellow:

itemRenderer="com.flexer.CustomListItemRenderer"

We won’t go deep into the inner things of the custom component only just to specify that the icon is added at the end like this:

<s:BitmapImage id="icon"
        source="{data.ico}"
        verticalCenter="0"
        right="3" />

The image is taken from data object which is present in each item of the list, and is horizontally aligned at 3 pixels from right. You can see the whole component code bellow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer name="CustomListItemRenderer"
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    focusEnabled="false">
 
    <s:states>
        <s:State name="normal" />
        <s:State name="hovered" />
        <s:State name="selected" />
        <s:State name="normalAndShowsCaret"/>
        <s:State name="hoveredAndShowsCaret"/>
        <s:State name="selectedAndShowsCaret"/>
    </s:states>
 
    <fx:Script>
        <![CDATA[
            override public function set labelText(value:String):void {
                super.labelText = value;
                labelDisplay.text = labelText; 
            }
        ]]>
    </fx:Script>
 
    <s:Rect left="0" right="0" top="0" bottom="0">
        <s:stroke.normalAndShowsCaret>
            <s:SolidColorStroke color="{selectionColor}" weight="1"/>
        </s:stroke.normalAndShowsCaret>
        <s:stroke.hoveredAndShowsCaret>
            <s:SolidColorStroke color="{selectionColor}" weight="1"/>
        </s:stroke.hoveredAndShowsCaret>
        <s:stroke.selectedAndShowsCaret>
            <s:SolidColorStroke color="{selectionColor}" weight="1"/>
        </s:stroke.selectedAndShowsCaret>
        <s:fill>
            <s:SolidColor color.normal="{contentBackgroundColor}"
                color.normalAndShowsCaret="{contentBackgroundColor}"
                color.hovered="{rollOverColor}"    
                color.hoveredAndShowsCaret="{rollOverColor}"
                color.selected="{selectionColor}"
                color.selectedAndShowsCaret="{selectionColor}" />
        </s:fill>
    </s:Rect>
 
    <s:SimpleText id="labelDisplay"
        verticalCenter="0"
        left="3" right="3" top="6" bottom="4"/>
    <!-- our mini dot icon showing the state of the file -->
    <s:BitmapImage id="icon"
        source="{data.ico}"
        verticalCenter="0"
        right="3" />
 
</s:ItemRenderer>

This icon is set from the main application where three dot icons are embedded.

[Embed(source="assets/bullet_empty.png")]
private var _icoUploadNotStarted:Class;            
[Embed(source="assets/bullet_green.png")]
private var _icoUploadSucces:Class;            
[Embed(source="assets/bullet_red.png")]
private var _icoUploadFailed:Class;

{data.ico} contains the embedded icon.

Conclusion

AMF is a powerful data protocol and can be used for any kind of transfer. It has lots of advantages and is by far the most parsimonious protocol freely available.

Source files are available at the end of this article. Two zip archives and an fxp file exported from my Flash Builder 4 which contains also the php files (I used Flash Builder 4 with PDT and Zend Debugger).

Resources

http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_05_05_08.pdf
http://www.amfphp.org/
http://www.amfphp.org/docs2/index.html
http://framework.zend.com/manual/en/zend.amf.html
http://www.themidnightcoders.com/products/weborb-for-net/overview.html
http://www.themidnightcoders.com/products/weborb-for-rails/overview.html
http://labs.adobe.com/technologies/flashbuilder4/
http://en.wikipedia.org/wiki/Action_Message_Format
http://www.zend.com/en/products/server-ce/
http://www.apachefriends.org/en/xampp.html
http://www.wampserver.com/en/download.php
http://sourceforge.net/project/showfiles.php?group_id=72483&package_id=257933
http://www.jamesward.com/census/

Share and Enjoy:
  • Twitter
  • Google Buzz
  • LinkedIn
  • Google Bookmarks
  • del.icio.us
  • Digg
  • Sphinn
  • blogmarks
  • Reddit
  • StumbleUpon
  • Facebook
  • DZone
  • FriendFeed
  • Yahoo! Buzz
  • Yahoo! Bookmarks
  • Slashdot
  • MySpace
  • Add to favorites
multiplefileuploadusingamfphp
multiplefileuploadusingamfphp_flex_sources
multiplefileuploadusingamfphp_php_sources




Tags: , , ,

This post was written by Andrei Ionescu

Views: 5371

related

7 Comments

have your say

Add your comment below, or trackback from your own site. Subscribe to these comments.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

:

:


«
»