SabreAMF 0.3 released + more info on class mappings

Renaun Erickson recently wrote an article on how to use SabreAMF with Flex 2’s services.xml configuration file..

He had some positive critique and also made me realize I made a mistake in confusing the ‘source’ and ‘destination’ properties in Flex’ RemoteObject. I updated the CallBackServer as soon as I could to fix that.. Be sure to download the updated version.

Also, take a look at the article, as its quite complete in explaining how to setup Flex/FDS to communicate with SabreAMF.

The extended version

Renaun modified the CallBackServer a bit to work more like AMFPHP. I understand the need for this and I might add in an extra class to support this behaviour.. It would definitely an optional one.

The most important change was that his CallBackServer now constructs classes based on the destination and automatically invokes methods. He also added in support for AMFPHP’s _explicitType attribute to automatically convert arrays and objects to a Flash/Flex class.

First thing I should note is that his implementation only works for the AMF3 part.. the AMF0 part does not have his extended behaviour. If he would have created a new class which constructed a CallBackServer instead, and listened to the onInvokeService this would work for both AMF0 and AMF3. I listed below how I could recommend extending the system. Most of the code is copy-pasted from Renauns version, except that I moved it into a separate class.


// Warning, untested

require_once 'SabreAMF/CallbackServer.php';

class ServiceMapper {

   private $server;
   private $baseClassPath;

   function __construct() {

      //Construct the server
      $this->server = new SabreAMF_CallbackServer();
      // Listen to the event
      $this->server->onInvokeService = array($this,'invokeService');


   function invokeService($service,$method,$arguments) {

     $dirname = realpath("./" . $this->baseClassPath);

     //Does the classpath exist    

     if (is_dir($dirname)) {
     } else {
       throw new Exception('Could not locate base class path: ' . $this->baseClassPath);

     $classpath = $dirname . str_replace('.','/',$service) . '.php';

     //Can we actually open the file?

     if (!is_readable($classpath)) {
       throw new Exception('Could not open file: ' . $classpath);

     require_once $classpath;

     $classname = str_replace('.','_',$source);

     if (!class_exists($classname)) {
        throw new Exception('Class not found: ' . $classname);

     $serviceInstance = new $class;

     // Invoking the method

     return call_user_func_array(array($serviceInstance,$method),$arguments);


   function setBaseClassPath($classPath = 'services/') {
      $this->baseClassPath = $classPath;

   function exec() {

      return $this->server->exec();



$server = new ServiceMapper();




I will probably add this class to the source (under a different name) when this is well tested.

Second thing is the _explicitType part. While this works easily if you have an AMFPHP background, SabreAMF has a more OOP equivalent for this. There are 3 different ways to map classes (force types).


$data = array(
   'prop1' => 'val1',
   'prop2' => 'val2',

// If want to force a flash class in AMFPHP you would add in:

$data['_explicitType'] = 'FlashClass';

// The SabreAMF equivalent:

// Be sure this class is included in your application
require_once 'SabreAMF/TypedObject.php';

$data = new SabreAMF_TypedObject('FlashClass',$data);


If you are making classes on the PHP backend which are replicas of Flash/Flex classes there is an even easier way to do it, using the classmapper.


//This is done on the beginning of the application, as this is usually a global thing and only has to be done at 1 point

require_once 'SabreAMF/ClassMapper.php';



This will work in both directions, so if you make a request with a certain flex class, it will also be translated to the PHP class.

There is a third way to map classes, this is mostly useful if you already have a set of classes in your framework and you want to do extra modifications to the data before it gets sent back to the flashplayer. This is done through the ITypedObject interface..

require_once 'SabreAMF/ITypedObject.php';

class MyClass implements SabreAMF_ITypedObject {

  public $property1;
  public $property2;
  public $secretProperty;

  function getAMFClassName() {

     return 'org.rooftop.MyFlexClass';


  function getAMFData() {

     return array(
        'property1' => $this->property1;
        'property2' => $this->property2;




Web mentions


  • Evert


    UPDATE: fixed coding bugs
  • tom

    thanks for the update!
  •   [NikO]



    Really great work here !

    i try to use the Client.php to test a amfphp gateway, but it seems there is difference in AMF0 sends by Flash and your serialised data :

    In Flash AMF0 data : After the /1 there is nothing :
    2F 31 00 00
    In your serialisez data, after the /1 there is that :
    2F 31 FF FF

    So, the methods i call return the good answer value, but the mysql query is not apply

    Do you have an issue ?

  • Evert


    Hi Niko,

    The difference between flash' serialized data and mine is that I don't supply the proper length for the body, instead I submit FF FF FF FF.. This property is generally ignored (haven't seen a system that needed this to be correct).

    If problems arise because of this I will definitely fix this..

    I dont really understand the other issue you are having.. can you elobate?

  • [ NikO ]

    [ NikO ]


    Thanks for your replay, i understand now what means these hexa numbers :)

    For the other problems, it s my fault, i look at data send in a second query, and see that the first query is send too, so i do some modification in a MyClientAMF.php to have it to work as i want, you can take a look here :

  • Evert



    Although I feel like your comment might be generated by a spam bot, at least you're not leaving any links and I'm just gonna say.. thanks very much :)