In the previous article, we looked at how PHP can deliver AMF to Flash with traditional HTTP protocols. Now we are going to look at how Flash can pass AMF data to PHP. Delivering AMF from Flash is just as simple as consuming it from PHP. In fact, it uses practically the same code.
Delivering AMF from Flash using HTTP
Example. 1.1 – main.mxml – Flex Example Delivering AMF
private function init():void { var myFlashObject:Object = { type: 'fruit' }; var ba:ByteArray = new ByteArray(); ba.writeObject(myFlashObject); var request:URLRequest = new URLRequest('http://[YOUR_URL]/amfin.php'); request.method = URLRequestMethod.POST; request.data = ba; var l:URLLoader = new URLLoader(request); l.dataFormat = URLLoaderDataFormat.BINARY; l.addEventListener(Event.COMPLETE, onComplete); } public function onComplete(event:Event):void { var ba:ByteArray = URLLoader(event.target).data as ByteArray; var data:Object = ba.readObject(); if(data.type == "fruit") trace(data.fruit); // 'orange','apple','bannana','lemon' else trace(data.veggies); // 'peas','carrots','legumes' } |
To start, we are still using URLRequest to handle our requests. You will notice that right above the request, we are creating some data. In this example, it is a simple Flash Object type with a single property. But you can include any data type you would like, even custom classes. (We will look at using custom classes in the next example). To serialize our Flash data into AMF we will use ByteArray. All you have to do is create an instance of ByteArray and write the object to it. Simple, isn’t it? To pass data using URLRequest, assign the ByteArray directly on the request.data property.
Once again, remember to set the dataFormat to Binary. If we failed to set this property, the data would be treated as String and would fail.
IMPORTANT: The other day, our team ran up on this. Flash has a class called, URLVariables. I have used this in the past to setup the data I was going to pass to the server. DO NOT use this when passing data in Binary format. It will fail when you have 0 (Zeros) in your data. The Flash Player terminates the data early and will fail because the length of the data will no longer match the length defined by the meta data. If you would like to read more about this from Adobe go here:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/URLRequest.html#data
Finally, in this example, we receive data back from the server, and parse it just like we did in the previous article. Now let’s look at the PHP side of things…
Example 1.2 – amfin.php
// Include the Zend Loader include_once 'Zend/Loader.php'; // Tell the Zend Loader to autoload any classes we need // from the Zend Framwork AMF package Zend_Loader::registerAutoload(); // Get the contents from the stream $amf = file_get_contents('php://input'); // Remove first byte (new line) $amf = substr($amf, 1); // Create a Parser $stream = new Zend_Amf_Parse_InputStream($amf); // Deseriaize string into AMF3 $d = new Zend_Amf_Parse_Amf3_Deserializer($stream); // Read as native PHP object $data = $d->readObject(); if($data->type == 'fruit') $data->fruit = array('orange','apple','bannana','lemon'); else $data->veggies = array('peas','carrots','legumes'); // Create an output stream $out = new Zend_Amf_Parse_OutputStream(); // Serialize data $s = new Zend_Amf_Parse_Amf3_Serializer($out); // Write as AMF data $s->writeObject($data); // Return the content (we have found the newline is needed // in order to process the data correctly on the client side) echo "\n" . $out->getStream(); |
This should also look somewhat familiar. We are using the Zend_Amf package again. We take the contents coming in and remove the “newline” from the beginning before we pass it into be deserialized. What we get back is a native PHP object. We can access everything as we would expect.
I even went one step further and evaluated the data coming in and returned it with additional data. As you can see, we can receive and return AMF data in a single operation.
Delivering Custom Data from Flash Player
Example 2.0 – Contact.as – ActionScript Value Object
package { [RemoteClass(alias="Contact")] [Bindable] public class Contact { public var first:String; public var last:String; public function get name():String { return first + " " + last; } } } |
Example 2.1 – main.mxml – Flex Sending Custom Class in AMF
private function init():void { var contact:Contact = new Contact(); contact.first = "John"; contact.last = "Smith"; var ba:ByteArray = new ByteArray(); ba.writeObject(contact); var request:URLRequest = new URLRequest('http://[YOUR_URL]/amfin2.php'); request.method = URLRequestMethod.POST; request.data = ba; var l:URLLoader = new URLLoader(request); l.dataFormat = URLLoaderDataFormat.BINARY; l.addEventListener(Event.COMPLETE, onComplete); } public function onComplete(event:Event):void { var ba:ByteArray = URLLoader(event.target).data as ByteArray; var o:Object = ba.readObject(); trace(o.message); } |
Example 2.2 – contact.php – Declaring a Value Object in PHP
class Contact { public $first; public $last; public function getName() { return $this->first . ' ' . $this->last; } public function getASClassName() { return get_class($this); // Contact } } |
Example 2.3 – amfin2.php – Consuming AMF with Custom Class
// Include the Zend Loader include_once 'Zend/Loader.php'; // Tell the Zend Loader to autoload any classes we need // from the Zend Framwork AMF package Zend_Loader::registerAutoload(); // Create an instance of Amf Server $server = new Zend_Amf_Server(); // Map PHP Class to Flash Class $server->setClassMap('Contact', 'Contact'); // Get the contents from the stream $amf = file_get_contents('php://input'); // Remove first byte (new line) $amf = substr($amf, 1); // Create a Parser $stream = new Zend_Amf_Parse_InputStream($amf); // Deseriaize string into AMF3 $d = new Zend_Amf_Parse_Amf3_Deserializer($stream); // Read as native PHP object $contact = $d->readObject(); $data = array('message'=>'You created user: ' . $contact->getName()); // Create an output stream $out = new Zend_Amf_Parse_OutputStream(); // Serialize data $s = new Zend_Amf_Parse_Amf3_Serializer($out); // Write as AMF data $s->writeObject($data); // Return the content (we have found the newline is needed // in order to process the data correctly on the client side) echo "\n" . $out->getStream(); |
This example shows how to send data as a custom class to PHP. By mapping the AMF class to our class, PHP received a Contact instance rather than a generic object. It is important to note that although both of our classes have the same name they do not have to match. Refer to the Zend_Amf documentation –
http://framework.zend.com/manual/en/zend.amf.server.html#zend.amf.server.typedobjects.
With the examples from this article and the ones from the previous article, you now have a complete roundtrip solution for passing AMF to and from the server with PHP and Flash.
Great post. I bookmark !
Thank you, very usefull to use.
Hey Rob, thanx for helping me again, i really owe you for digging me out with this!
Best in all
P
Great article!
How would you handle object relational mapping when you are relaying custom objects from PHP via AMF to Flash?
You will see an example of this in Example 2.3
// Create an instance of Amf Server$server = new Zend_Amf_Server();
// Map PHP Class to Flash Class
$server->setClassMap('Contact', 'Contact');
Very interesting!
Are there any downsides? Speed? Security?
AMF data, whether delivered through a NetConnection or through a REST implementation, like I presented here are still exactly the same. They are both use the same HTTP Protocol. The speed and security is not any different between the two. This show a difference in how to deliver the same AMF content between client and server.