Php and AMF part 1: Zend_Amf and helper class

Posted on January 8, 2010

4


Action Message Format is a proprietary data format used by FlashPlayer in remoting, streaming, shared objects etc. Its binary nature makes it a very efficient way to transfer data – more compact than xml or json.
Thanks to Zend_AMF it’s easier than ever to serialize/deserialize data objects – it’s now a breeze to handle data as php native objects on the server side, transfer back and forth to the client, and treat them as actionscript objects on the client side.

Below is a simple but useful php helper class that makes it very easy to transfer data back and forth between a php server and a flash/flex/air http client (no messy remoting here). It also makes it possible to save amf data to file in php, for later opening in Air or FlashPlayer 10. More on that in a later post. The functionality is all wrapped in static functions.

Got the ideas and most of the solutions from Robert Taylor’s and Jac Wright’s excellent blogs. Thanx!

<?php

// Developed with Zend Framework v 1.9
require_once 'Zend/Amf/Parse/OutputStream.php';
require_once 'Zend/Amf/Parse/InputStream.php';
require_once 'Zend/Amf/Parse/Amf3/Serializer.php';
require_once 'Zend/Amf/Parse/Amf3/Deserializer.php';
require_once 'Zend/Amf/Constants.php';
require_once 'Zend/Amf/Value/ByteArray.php';

class amf {

	// Translate an php object to an amf stream
	public static function object_to_amf($object) {
		$stream = new Zend_Amf_Parse_OutputStream();
		$serializer = new Zend_Amf_Parse_Amf3_Serializer($stream);
		$serializer->writeObject($object);
		return "\n" . $stream->getStream();
	}

	// Translate an amf stream to an php object
	public static function amf_to_object($amf_data) {
		$amf_data = substr($amf_data, 1);
		$stream = new Zend_Amf_Parse_InputStream($amf_data);
		$d = new Zend_Amf_Parse_Amf3_Deserializer($stream);
		return $d->readObject();
	}

	// Save an amf stream to file
	public static function save_amf_to_file($file_name, $amf_data) {
		file_put_contents($file_name, $amf_data);
	}

	// Opens an amf stream file
	public static function load_amf_from_file($file_name) {
		return file_get_contents($file_name);
	}

	// Serialize an binary file (for example .png) to actionscript bytearray data
	public static function file_to_bytearray($file_name) {
		return new Zend_Amf_Value_ByteArray(file_get_contents($file_name));
	}

	// Deserialize an actionscript bytearray and save it to a file
	public static function bytearray_to_file($bytearray_data, $file_name) {
		$file_bytearray = new Zend_Amf_Value_ByteArray($bytearray_data);
		$file_data = $file_bytearray->getData();
		file_put_contents($file_name, $file_data);
	}

	// get input stream from flash/air app
	public static function amf_input_stream() {
		return file_get_contents('php://input');
	}

}

Here’s a very simple php server script. It takes the amf input sent from client (if any), creates an output object, adds some test data to it (including mirroring the indata sent from the client, just for fun/debugging).

<?php

require_once 'helpers/amf.php';

//*******************************************
// Get indata (if any)
$indata = null;
$amf_input = amf::amf_input_stream();
if ($amf_input) {
	$indata = amf::amf_to_object($amf_input);
} else {
	$indata = (object) $_REQUEST;
}

//*******************************************
// Create outdata object
$outdata = new StdClass();

// Add anything to $outdata object, 
// for example database query result objects...
$outdata->name = 'John';
$outdata->testarray = array('abc', '123');

// Reflect inputdata, just for debugging/fun...
$outdata->indata = $indata;

//********************************************
// Serialize and send to client
$amf_data = amf::object_to_amf($outdata);
echo $amf_data;

And here’s the basic code for making a request to the server above from a flex/air client:

private function init():void {
	// create a test object for sending to the server, and serialize to bytearray
	var dataObject:Object = {test:'Data sent from the client!'};
	var byteArray:ByteArray = new ByteArray();
	byteArray.writeObject(dataObject);
	
	var urlRequest:URLRequest=new URLRequest('url/to/phpamfserver.php');
	urlRequest.method = URLRequestMethod.POST;
	urlRequest.data = byteArray;
	
	var urlLoader:URLLoader=new URLLoader(urlRequest);
	urlLoader.dataFormat=URLLoaderDataFormat.BINARY;
	urlLoader.addEventListener(Event.COMPLETE, onComplete);
}

public function onComplete(event:Event):void {
	var byteArray:ByteArray=URLLoader(event.target).data as ByteArray;
	var data:Object=byteArray.readObject();
	// Trace the return data object sent from the php server
	trace(ObjectUtil.toString(data)); 
}
Advertisements