Upload Files in Adobe AIR with Zend AMF and Flex

This example shows how to upload files in an Adobe AIR application to a server using Zend AMF and Flex. It’s based off a blog post by Leonardo França. I found getting started with Zend AMF a bit confusing, this tutorial by Ryan Stewart was very helpful.

On the server we need to upload the Zend Framework (minimal) and create some files. This is how the file structure will end up looking:

server file structure

Create index.php (the gateway):

<?php 
error_reporting(E_ALL|E_STRICT);
ini_set("display_errors", "on");

require('Zend/Amf/Server.php');
require_once('vo/FileVO.php');
require_once('service/UploadService.php');

$server = new Zend_Amf_Server();
$server->setClass("UploadService");
$server->setClassMap("FileVO","FileVO");

echo($server->handle());
?>

In the service directory create UploadService.php:

<?php
require_once($_SERVER['DOCUMENT_ROOT'].'/chaosm/air/ex2_uploadamf/vo/FileVO.php');
class UploadService
{
	public function __construct() {}
	
	public function upload(FileVO $data)
	{
		try
		{
			$fileData = $data->fileData;
			file_put_contents($_SERVER['DOCUMENT_ROOT'].'/chaosm/air/ex2_uploadamf/uploads/'.$data->fileName,$fileData);
			return true;
		}
		catch (Exception $e)
		{
			throw new Exception($e->getMessage());
		}
	}
}
?>

In the vo directory create FileVO.php (the value object for the file):

<?php
class FileVO
{
	public $fileName;
	public $fileData;
	
	function __construct() {}
}
?>

In services-config.xml change the endpoint uri (line 17) to the location of the gateway on your server:

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
            <destination id="zendamf">
                <channels>
                    <channel ref="zend-amf-channel"/>
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    <channels>
        <channel-definition id="zend-amf-channel" class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://www.chaosm.net/air/ex2_uploadamf/" class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
    </channels>
</services-config>

Finally make a directory called uploads. This is where files will be written to, so it needs to have the required permissions (such as 777).

In Flash Builder create a new Flex project called UploadAMF (or import my .fxp file). This is how the file structure will end up looking:

flash builder file structure

Right-click on the project and select Properties. Include the services-config.xml under additional compiler arguments like this:

flash builder additional argument

Right-click on the src folder and create a new package called vo. In the vo package create a new ActionScript class called FileVO (notice that it has the same properties as the php value object on the server):

package vo
{
	import flash.utils.ByteArray;

	[RemoteClass(alias="FileVO")]
	[Bindable]
	public class FileVO
	{
		public var fileName:String;
		public var fileData:ByteArray;
	}
}

The main application file UploadAMF.mxml is where everything happens. A remote object is created, the user selects an image to upload and the upload method is called. When the upload is complete an Alert box is shown to the user.

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
					   xmlns:s="library://ns.adobe.com/flex/spark"
					   xmlns:mx="library://ns.adobe.com/flex/mx">
	<fx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.events.FlexEvent;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			
			import vo.FileVO;
			
			private var fileRef:FileReference;
			private var fileTypes:FileFilter = new FileFilter("Images (*.jpg, *.jpeg)", "*.jpg; *.jpeg");
			private var allTypes:Array = new Array(fileTypes)
			
			protected function selectButton_clickHandler(event:MouseEvent):void
			{
				fileRef = new FileReference();
				fileRef.addEventListener(Event.SELECT,selectHandler);
				fileRef.browse(allTypes);
			}
			
			protected function selectHandler(event:Event):void
			{
				fileTextInput.text = fileRef.name;
				fileRef.load();
			}
			
			protected function uploadButton_clickHandler(event:MouseEvent):void
			{
				var data:ByteArray = new ByteArray();
				fileRef.data.readBytes(data,0,fileRef.data.length);
				var fileVO:FileVO = new FileVO();
				fileVO.fileName = fileRef.name;
				fileVO.fileData = data;
				upload.token = ro.upload(fileVO);
				selectButton.enabled = false;
				uploadButton.enabled = false;
			}
			
			protected function upload_faultHandler(event:FaultEvent):void
			{
				Alert.show(event.fault.faultString,"Error");
				selectButton.enabled = true;
				uploadButton.enabled = true;
			}
			
			protected function upload_resultHandler(event:ResultEvent):void
			{
				if (Boolean(event.message.body))
				{
					Alert.show("File uploaded.","Success");
				}
				else
				{
					Alert.show("Unable to upload file.","Error");
				}
				selectButton.enabled = true;
				uploadButton.enabled = true;
			}
			
		]]>
	</fx:Script>
	<fx:Declarations>
		<s:RemoteObject id="ro" destination="zendamf" source="UploadService"/>
		<s:CallResponder id="upload" fault="upload_faultHandler(event)"
						 result="upload_resultHandler(event)"/>
	</fx:Declarations>
	<s:Form x="10" y="10">
		<s:FormItem label="File">
			<s:HGroup>
				<s:TextInput id="fileTextInput"/>
				<s:Button id="selectButton" label="Select" click="selectButton_clickHandler(event)"/>
				<s:Button id="uploadButton" label="Upload" click="uploadButton_clickHandler(event)"/>
			</s:HGroup>
		</s:FormItem>
	</s:Form>
</s:WindowedApplication>

Download the source files.

This entry was posted in Uncategorized. Bookmark the permalink.
  • Lionel

    Very useful. Thanks !

  • Kamatchi G

    Hi,
    can u tel how to upload file and read file using carringrom framework remoteobject

    Thanks in advance…………..