Php and AMF part 1: Zend_Amf and helper class
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));
}
JQuery delayedObserver plugin
I’ve never liked javascript programming. I’ve done some efforts, but found that its just as boring as it is hard.
Well, you can’t get around it, can you..?
I was fiddling with some ajax prototyping for a searchfield the other day. You know, the stupidly basic inputfield onchange=”callsomefunction()” stuff… Or was it onkeypress=”callsomefunction()”?
Luckily, a Stack Overflow question on this subject led me to JQuery Utils and the delayedObserver plugin.
Below a very simple example. An a delayedObserver callback function (“testfunction”) is set to the input field, with 1 second delay. This means that one second after finishing writing in the text field, the callback function (testfunction()) is executed. Simple and elegant!
<input type="text" id="input1" />
<script type="text/javascript">
$(document).ready(function(){
// Register the callback function with 1 sec delay
$('input#input1').delayedObserver(testfunction, 1);
});
//******************************************************
// Callback function
function testfunction(value, object) {
alert($('input#input1').val());
}
</script>
Thank you, haineault!
MySql: The power of Views (or Better late than never)
I sometimes get the sour feeling of “there’s something fundamentally wrong with this! It works, but nevertheless…” It happens in all aspects of life, including programming. Some of (not always!) the times this feeling causes curiosity and energy to strive for a new perspective, new knowledge, new ways of facing the problem. Aspects of inutition and creativity, I guess…
In my current project there’s an awful lot of SQL going on. Lots of connected tables, nestled selects etc. In the preparation for the next level of full text searchability, I stumbled upon the concept of Views in MySql. I can’t believe that I didn’t know this beauty before!
In short, a View is a virtual database table where the content is a result of a underlying sql statement. It can be accessed by normal queries just like any table – a view can build its content depending on tables as well as other views.
For a good introduction of MySql Views, check this Techtopia blogpost out.
Creating a View in PhpMyAdmin is a breeze, there’s a Create View link in the right bottom of any table view:

I haven’t found any button to retrieving the underlaying View sql though. However, it can be done by using a normal “SHOW CREATE VIEW tablename” sql statement.
The concept of views will ease my further development a lot! I’m glad I did listen to that feeling…
The quest for client-side search query language
…just led me to CQL (Contextual Query Language). Thanks StackOverflow and njk for showing the way!
(Please note that since version 1.2, “Contextual Query Language” is changed from former “Common Query Language”)
This lets the user write advanced searches using logical operators, indexes, even proximities… So, let’s create a search for all the cql-to-php-to-sql libraries laying around waiting for to be implemented…
Imagemagick: Pdf to bitmap density quirk
When converting bitmapcontained pdfs to bitmaps using the imagemagick convert method, beware the parameter order! The density parameter sets the resolution of the bitmap conversion before resizing – therefore, the higher density value, the better resulting quality.
So, the followning should work, but doesnt:
convert source.pdf -resize 630×891 -density 300 result%04d.png
By some reason the -density parameter has to be set before the source file name. This works:
convert -resize 630×891 -density 300 source.pdf result%04d.png
By the way, the “%04d” tag in the resulting file name gives an autonumbering with leading zeros, in this case 4 digits in total. Thus:
page0000.png
page0001.png
page0002.png
etc.
Kohana 2.x code completion in Eclipse PDT
Things are about to change with Kohana 3 just released…
Meanwhile, the Eclipse PDT editor can’t really cope with Kohanas class namings and folder structure. But of course there is a solution: Peter Bowyer’s zend_autocomplete (works in all Eclipse PDT implementations including my boosted FlexBuilder 3, not just Zend Studio!). Put it in your controller directory, run it – and it creates a file in the cache containing all Kohana system classes as well as your own application classes! This is what Eclipse needs to give you well-working code completion!

Thank you, Peter!
Kohana, Formo and many-to-many relations (“habtm”)
Just got the solution for how to handle many-to-many relations in Formo. Thank you, Ben!
Three tables, groups (id, name), users (id, name) and the pivot table groups_users(group_id, user_id).
class User_Model extends ORM {
protected $has_and_belongs_to_many = array('groups');
}
class Group_Model extends ORM {
protected $has_and_belongs_to_many = array('users');
}
And here’s how to in the controller handle display of an user form, complete with checkbuttons for toggling connections to groups:
public function user($id = false) {
$user = new User_Model($id);
$form = Formo::factory()
->orm($user)
->habtm('user', 'group')
->add('Submit');
if ($form->validate()) $form->save();
echo $form;
}
This gives the following form. The magic lies in the habtm plugin (has to be active either by Formo config or by Formo::factory()->plugin(‘habtm’). Not one single sql line, not one line of deadly tedious form populating and deriving…

Ok, not pretty, but that’s another story.
Soo proud. Just struck me what “habtm” stands for.
Na na, won’t tell ya!
Kohana PHP with ORM and Formo – db made easy!
After some days prototyping with Kohana, I start to realize the strength and beauty!
One of the every-day needs in my world is to coordinate different database tables to get things to work. Most of the time this is done by hand, using PhpMyAdmin. For basic stuff, this works fine, but very often there’s the bad feeling of should-have-a-real-admin-interface-for-this…
No bad feelings no more!
The combination of Kohana’s Object Relational Mapping library (ORM) and the Formo module makes it super-easy to create a table-admin-interface, including related tables. No SQL at all, no defining form layouts at all! (Ok, there can be a need for some validation information, some styling etc.)
Here’s an example, based on two tables, schools and students:
schools: <- Note: Table name in plural id:int autoincrement name:varchar students: <- Note: Table name in plural id:int autoincrement school_id:int <- Note! Referred table as singular + "_id" name:varchar
Two models for those tables:
// models/student.php
class Student_Model extends ORM {
protected $belongs_to = array("school");
// Defines the connection to school - "each student belonst to a school"
}
// models/school.php
class School_Model extends ORM {
protected $has_many = array("students");
// Defines the connection to students - "each school has many students"
}
So for the controller. Here’s the real beauty: In the listAll action below the schools are fetched, and ORM handles automatically the relationship and fetches all connected students as well!
// controllers/controllername.php
public function listAll() {
$schoolModel = new School_Model();
$schools = $schoolModel->find_all();
foreach ($schools as $school) {
echo "<br/><b>$school->name - ".html::anchor("controllername/school/{$school->id}", "edit")."</b>";
foreach ($school->students as $student) {
echo "<br/>- $student->name - ".html::anchor("controllername/student/{$student->id}", "edit");
}
}
}
The actions below handle both creation and editing of posts. The super-handy Formo library maps out a complete form – including dropselect for selecting a school for the students!
Kind of magic!
// controllers/ormtest.php
public function school($id = false) {
$school = new School_Model($id);
$form = Formo::factory()->orm($school)->add("Submit");
echo $form;
if ($form->validate()) {
$form->save();
}
}
public function student($id = false) {
$student = new Student_Model($id);
$form = Formo::factory()
->orm($student)
->add("Submit");
if ($form->validate()) $form->save();
echo $form;
}
The only “tricky” part is that you have to get the table names and references to them right according to the ORM naming conventions. Here’s a short summary:
- Table names should be plural
(“schools”, “students” – this makes sense because the table is a list with many items) - Referring field names should be singular plus “_id”
(“school_id” – logically because a single student belongs to one single school) - Model names should be singular.
(The model file for a student is named “student.php”, and the class is named “class Student_Model extends ORM”. A model most of the time represent one single item: one student or one school. The exception is when we want a listing of all items in the table. Have a look at the listAll code above.)
The models need to include information about the relations.
- The student belongs to one of many schools, therefore we use
protected $belongs_to = array(’schools’);
with plural in “schools” - The school has one or many students, thus
protected $has_many = array(’students’);
Note that this relates to a one-to-many relationship.
Happy crudding with Kohana
Another superb Kohana solution: CRUD Scaffold (projects.nathanbentley.com/projects/show/crudscaffold) by Nathan Bentley. Just install, write some controller and model lines, and you have a nice JQuery-driven table editor – just the way it should be!:

Thank you, Nathan!
Now, there’s just left to sort out how to handle related tables…
Comments (2)