AMF (Action Message Format) is a binary data serialization protocol. Simply put, it transforms objects in memory into a binary string, and can reverse this binary string into an object in memory. It can be used just like JSON
, and this library has been build to provide a similar API to that exposed by the JSON
functionality in JavaScript
.
The purpose of this library is to provide a consistent and symmetric implementation of the AMF
specification in both PHP
& JavaScript
.
Well, it's up to you. JSON
is perfectly suited to the web, however it does have some shortcomings which are addressed by AMF
. For starters, JSON
cannot handle complex object graphs with circular references; additionally, it cannot serialize dates & byte arrays - you would need to do some additional work to support these in JSON
(convert date to unix timestamp, byte arrays to base64).
Hells no. JSON
is great; AMF
can simply provide you with some additional functionality which could help you build your web app.
To begin using this library, you will need to install it via Composer:
bower install -S infomaniac-amf.js#latest
This will download the repository for you and make the library available for inclusion. For convenience, a file dist/amf.js
has been compiled for you with all of its dependencies, uglified and browserified. The file is a mere 43kb.
<script src="bower_components/infomaniac-amf.js/dist/amf.js" type="text/javascript"></script>
Here is a simple example of encoding an object to AMF
:
var data = {
any: 'data',
you: 'like!'
};
var encodedData = AMF.stringify(data);
console.log(encodedData);
This will produce a binary string which represents your given data.
If you were to inspect the HTTP traffic of a page that produces AMF
data, using a tool such as Charles Proxy, you would see the following output:
To decode this string, simply do the following:
var data = {
any: 'data',
you: 'like!'
};
var encodedData = AMF.stringify(data);
console.log(AMF.parse(encodedData));
If you were to console.log
this data, it would look identical to the input data given to the AMF.stringify
function.
Object {any: "data", you: "like!"}
AMF
allows you to encode an object and retain some metadata about it; for example, when serializing an instance of a class (not Object
) the library will retain the class' fully qualified namespace name and use it to reconstruct an object of that type upon decoding.
Consider the following class:
var Person = function() {
this.name = 'Bob';
this._classMapping = 'Person';
};
If we encode an instance of this object, by default its class type will be ignored and when the data is decoded, the resulting value will be a plain PHP Object
instance.
var Person = function() {
this._classMapping = 'Person';
};
var data = new Person();
data.name = "Bob";
var encodedData = AMF.stringify(data);
console.log(AMF.parse(encodedData));
...will produce...
Object {name: "Bob"}
In order to retain the class type in AMF
, you will need to add the following:
- an additional flag to the
AMF.stringify
function call - define a
_classMapping
variable on the object(s) being encododed, and - register a "class alias" using
AMF.registerClassAlias
to associate the_classMapping
value to its related class type
var Person = function() {
this._classMapping = 'Person';
};
var data = new Person();
data.name = "Bob";
var encodedData = AMF.stringify(data, AMF.CLASS_MAPPING);
AMF.registerClassAlias('Person', Person);
console.log(AMF.parse(encodedData));
Now, when this data is decoded, the library will attempt to create a new instance of the Person
class and set its public property name
to "Bob"
.
Person {_classMapping: "Person", name: "Bob"}
The AMF
spec allows for the serialization of several different data-types.
Here is a link to the latest specification: AMF3 Spec - January 2013
This library implements 10 of the 18 data-types described in the specification. The reason for the support of only a subset of these types can be seen in two lights: utility and limitation. Here is an exhaustive list of the data-types available:
Data-Type | Included | Reason for exclusion |
---|---|---|
Undefined | ✔ | - |
Null | ✔ | - |
False | ✔ | - |
True | ✔ | - |
Integer | ✔ | - |
Double | ✔ | - |
String | ✔ | - |
XML Document | ✗ | Who needs XML? |
Date | ✔ | - |
Array | ✔ | - |
Object | ✔ | - |
XML | ✗ | Who needs XML? |
ByteArray | ✔ | - |
Vector | ✗ | Not high priority - also, possible browser incompat issue with JS |
Vector | ✗ | Not high priority - also, possible browser incompat issue with JS |
Vector | ✗ | Not high priority - also, possible browser incompat issue with JS |
Vector | ✗ | Not high priority - also, possible browser incompat issue with JS |
Dictionary | ✗ | PHP cannot use objects are array keys |
This project is licensed under the MIT
license.
While writing this library, I used several libraries to validate my progress, and to help me come unstuck. I would like to extend a special thanks to the following libraries and individuals:
- SabreAMF
- AmfPhp
- Charles Proxy's wonderful AMF implementation
- Arseny Vakhrushev (neoxic) for his patience, guidance, advice and help
- Robert Cesaric, Grant McMullin and Andre Venter for their insight and advice
- My esteemed colleagues at Zando