AMFEXT
From Teslacore
Contents |
What it is?
Looking for New Maintainer Contact Me
The binary for PHP4 under Windows was not correct. Check the last version
AMFEXT is a PHP extension written in C that implements encoding and decoding of AMF and AMF3 messages for the PHP language. It has been based on some of the experience gained with AMFPP, a native code for encoding and decoding C.
The native encoding and decoding is extremely fast and memory efficient respect existing PHP implementation, and the flexibility has been provided using callbacks to the PHP code.
You can found information about benchmarks Patrick Mineault blog together with the integration with AMFPHP
If you want to support this project, please donate through Sourceforge (AMFPHP) or at Teslacore:Site_support.
Status
24 Jul 2008 - Looking for new maintainer. Version 0.9.2 have been submitted to PECL for approval applying a fix. Encoding documentation updated to 0.9
10 Jan 2008 - Planning a movement to a proper Open Source repository. In particular SourceForge in collaboration with the new maintainer of AMFPHP
The current status is beta 0.8.7b that provides all the features and it has been extensively checked by Patrick, while the beta version 0.9 has been introduced with the support of charset translations. Note also that the code is now in the PECL for becoming an official extension.
22 Oct 2007 - The website is back and I am moving the code to SourceForge or Google Code. I've been contacted by various people for fixing somebugs and at the same time provide a Python version of this extension. I am going to host the code for development on SourceForge while keeping the releases on PEAR.
You can track changes using the feed
here. Note that this is an Appcast Feed
Tested Platforms
- Windows under PHP 5.2.0, 5.1.6, 4.4.4
- Linux PHP 5.1.6 in Fedora Core 5 i386, PHP 4.4.4 in Debian Sarge
Known Issues
- support for Charset conversion should receive testing (0.9)
Features
- AMF and AMF3 (Flex 2) messages
- memory optimization for large data sets
- special encoding of recordsets
- callbacks for custom encoding and decoding of objects, xml and bytearray
Downloads
The binary version contains a bin folder with a subfolder for each system. Currently I am building it under Windows and I've tested the build under Linux using Fedora Core 5. For using the binary version in Linux you should match glibc version (using 'ls /lib/libc*'),PHP minor version (e.g 4.4.x) and platform (i386).
I need help for additional builds on other Operating Systems or configuration. Inspired by the distribution of ZendOptimizer binaries, possible platforms are Linux (glibc 2.1,2.3), Mac OS X/Darwing (universal) and others.
Releases
0.9.2
Released in PECL for approval (23th July 2008)
0.9
Latest source code: amfext-0.9.zip (20th April 2007)
Binaries: amfext-0.9-bin.zip (20th April 2007)
Changes: charset translation
The binary contains builds for: Windows PHP 5.2.x, 5.1.x, 4.4.x
0.8.7b
Latest source code: amfext-0.8.7b.zip (20th April 2007)
Binaries: amfext-0.8.7b-bin.zip (20th April 2007)
Changes: small fix for Linux build
The binary contains builds for: Windows PHP 5.2.x, 5.1.x, 4.4.x
0.8.7a
Latest source code: amfext-0.8.7a.zip (18th February 2007)
Binaries: amfext-0.8.7a-bin.zip (18th February 2007)
Changes: added 'version' to serverInfo for Flash 8 compatibility in recordsets
The binary contains builds for: Windows PHP 5.2.x, 5.1.x, 4.4.x
0.8.7
Source code: amfext-0.8.7.zip (1st February 2007)
Binaries: amfext-0.8.7-bin.zip (1st February 2007)
The binary contains builds for:
- Windows PHP 5.2.x, 5.1.x, 4.4.x
- Linux glibc24 i386 PHP 5.1.6, built on Fedora Core 5
- Linux glibc23 i386 PHP 4.4.4, built on Debian Sarge
Install
Please refer to the INSTALL file in the distribution file, but in general you should put the module in the extension directory of your PHP installation (ext under Windows or /usr/lib/php/modules under Linux).
The the php.ini file should be modified to load the extension (extension=php_amf.dll in Windows or extension=amf.so in Linux)
Building under Linux
You can easily build it as any other PHP extension using the following commands:
- phpize
- configure --enable-amf
- make install
See also in PECL build
Documentation
Documentation can be found here
Encoding and Decoding details
The complete documentation of the encoding and decoding performed by the extension has been documented separately.
See encoding.txt
Optimizations
The encoding has been optimized for speed respect the original PHP implementation:
- object caching
- handling of arrays
- construction of the output string
Object Caching
The AMF encoding manages references to object so it is necessary to store and lookup them. PHP implementations cannot use the object as a key, so they store them in arrays and perform array_search that has a linear time. Instead in the extension is possible to use the object pointer, actually the HashTable pointer, as a key.
In the case of machines with ulong == sizeof(void*) it is possible to use the pointer as a key, otherwise the pointer is converted into string and used as a key. Note that PHP var_serialize uses always the string approach.
Handling of Arrays
When encoding a PHP array into AMF is necessary to identify if the array is a numeric array, a string collection or an array with mixed keys. Typical PHP code scans such array and constructs two separate array. In AMFEXT we are not allocating any memory for that, but simply iterating the array twice.
Output String Optimizaton
The output string of the encoder was initially implemented using PHP smart strings, that are just dynamic sized strings based on emalloc. Performance was good with small data sets but in the case of long strings it was degrading a lot, reaching O(n^2) when dealing with array data sets. Using a PHP memory stream for storing the results was not helping at all.
The first optimization adopted by AMFEXT is that the output string is obtained by a chaining of data block. Such data blocks start with a small allocation size (128 bytes) and every time the size of the block is doubled up to a maximum size. The advantage here respect realloc is that memory gets never copied when the buffer expands.
The second optimization is based on the idea that long PHP strings like data from database or plain XML data should not be copied multiple times by the encoder. Indeed AMFEXT stores just references to them, but only if the size is greater than a certain threshold. We use a threshold because the switch between a raw block and a reference block costs bytes and time, so it is better to do when there is a good reason.
With this second optimization the resulting data structure is made of a single linked list of blocks, in which each block is a vector of raw and reference chunks. Each raw chunk contains the length and the data, while the reference chunk just the reference to a PHP string variable. Finally there is a terminator chunk.
The following figure shows the memory layout:
Note: such approach could be easily applied to the PHP implementations of the encoders
AMF String Builder
The String Builder provided by this module seems interesting, so I am going to provide it as a resource for usage in other cases, or for integration in other extensions.
The resource allows to create an output string made of different string chunks that is readonly and it stores references to long strings for improving memory usage. When the appending operation is finished the StringBuilder can be represented as a string or directly written to standard output or to a file/stream. For improving memory usage is also possible to append_move a StringBuilder to another cleaning the source StringBuilder.
If the extension is not present is possible to keep the same API using provided wrapper functions written in PHP that simply use strings.
For the AMF encoding it is also possible to explicitly use the StringBuilder in amf_encode. The AMF_AS_STRING_BUILDER flag specifies to return the encoding as a StringBuilder, and also a new fourth parameter of amf_encode allows to append the result to the provided StringBuilder. The following example shows how:
$r = amf_encode("hello world",AMF_AS_STRING_BUILDER); // ask to return a SB
echo("returned type: " . $r . "\n");
echo("returned length: " . amf_sb_length($r) . "\n");
$sb1 = amf_sb_new();
amf_sb_append($sb1,"prefix");
amf_encode("hello world",0,"",$sb1); // store the result into the provided SB
echo("returned type: " . $sb1 . "\n");
echo("returned length: " . amf_sb_length($sb1) . "\n");
The functions will be:
- $sb = amf_sb_new() creates a new StringBuilder
- amf_sb_as_string($sb) or amf_sb_flat($sb) returns the string
- amf_sb_length($sb) returns the length
- amf_sb_append($sb,$a1,...,$aN) appends something
- amf_sb_append_move($sb,$aSB) appends a SB to another, and it cleans the source SB $aSB
- amf_sb_write($sb, $file_resource = NULL) writes to a resource as fwrite. If it is not specified it writes to the stdout as echo
Example code:
function w($n)
{
return str_pad("yes",$n,STR_PAD_BOTH);
}
$sb = amf_sb_new();
amf_sb_append($sb,"Hello World SB","Begin",w(1000),"End");
echo("length:" . amf_sb_length($sb) . "\n");
echo("text: " . amf_sb_as_string($sb) . "\n");
echo("text written: ");
amf_sb_write($sb);
echo("\n");
$fp = fopen("test.log","wb");
amf_sb_write($sb,$fp);
fclose($fp);
amf_sb_append($sb,array("Hello","World","Nice",10));
Thanks
To Patrick Mineault for the support, testing and the original suggestion of making the extension
To Mauro di Blasi for the "Dreaming in Code" book
To Joan Garnetfor the support
Elisabetta for the patience
Comments

