On a few recent projects I have needed to access various server side functions including database records and files from Flash. The server environment dictated that PHP would be the server side language to use. I’m sure many of you have integrated Flash/Flex with PHP, it’s pretty easy to do. Create a PHP file, have it echo out some text. In Flash use a URLLoader to pass down any variables and then load the resulting data. That method has been around since Flash 5/6, pretty bullet proof.
What I wanted to do on the server side was setup something that was a little more robust and service oriented. Instead of having to create a separate PHP file for each server function I wanted a single point of entry to the server and a simple interface for sending and receiving data, something more akin to RPC or REST.
The other criteria was that I wanted something super lightweight. I could have used AMF on the server, either WebOrb PHP or AMFPHP. I have used both and they work great, however in this case the amount of data being sent back and forth would not really benefit from AMF and I didn’t want the headaches of trying to get the server admin to approve setting it up on the server (which really isn’t a huge deal).
What I came up with is a single PHP class that acts as the API. It accepts incoming calls, checks the variables, handles any errors, and returns the data (or any faults) in a simple, structured format. Let’s walk through the PHP first and then we can deal with how to consume it from Flash or Flex.
The first step is to create a file called Api.php and then setup a function to catch any php exceptions so that we can correctly deal with them and send a structured response to the client instead of some cryptic PHP error message. One thing to note in the code is that this does not work for errors thrown from the mysql functions, or other db functions for that matter. We need to do something special in the mysql calls, but I’ll get to that later.
//function for catching php excpetions
//this won't work with mysql calls so we need to catch
//mysql errors and rethrow the error
function exception_error_handler($errno, $errstr, $errfile, $errline )
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
Now we get into the meat of the solution, the Api class. The constructor essentially consists of two pieces. A switch statement to deal with each method that can be called and then echoing out whatever the response from said method is. The whole thing is wrapped in a try/catch so we can deal with any errors that crop up.
class Api
{
private $eol = "
";
function __construct()
{
try
{
switch ($_REQUEST['method'])
{
case 'helloWorld':
$response = $this->helloWorld();
break;
case 'addValues':
$response = $this->addValues($_REQUEST['value1'], $_REQUEST['value2']);
break;
case 'getRecords':
$response = $this->getRecords();
break;
default:
$response = new Response();
$response->status = "error";
$response->data = '<![CDATA[Method does not exist]]>';
break;
}
}
catch (Exception $e)
{
$response = new Response();
$response->status = "error";
$response->code = -1;
}
echo $response->toXmlString();
}
}
The next piece is creating the Response class. This class gets used to return any data or exceptions to the client. It provides a simple xml structure that can be easily read by actionscript. The benefit of using something structured like xml is you can easily deal with any type of returned data, it’s flexible, and you have a nice standardized format for communicating between the server and client.
class Response
{
public $status = "ok";
public $code = 0;
public $data = "";
private $eol = "
";
public function toXmlString()
{
$response = '<result status="' . $this->status .'" code="' . $this->code .'">' . $this->eol;
$response .= $this->data . $this->eol;
$response .= '</result>';
return $response;
}
}
As you can see, it’s a pretty simple little class. Three properties and one function. The status can be set to either ‘ok’ or ‘error’ for my purposes. The code is any particular error code I want to return to the client. I can use the code on the client side to look up any particular error message I may want to display, separate from whatever the server returns. Finally, the data property which will contain any output from the called method. The toXmlString method is called from the Api class constructor and it simply formats the Response class values in clean xml text that php can echo out.
That is the basic framework of the Api, the next step is filling in the methods. I have three samples to give an idea of what you can do. These two are really basic, a simple hello world and adding two values together. They simply show how the Response class is used to set the data to be returned.
private function helloWorld()
{
$response = new Response();
$response->data = '<![CDATA[Hello World]]>';
return $response;
}
private function addValues($v1, $v2)
{
$response = new Response();
$response->data = $v1 + $v2;
return $response;
}
The final method is a little more involved. It is reading records from a database and then returning the values. A few things to note. First, I use a conditional if statement to determine whether or not the mysql_query actually worked. If it returns false, then I purposely throw an Exception and then allow the try/catch and error handling we setup at the top deal with it. Second, I use the htmlspecialcharacters to escape any problem characters in the xml attributes. I could have used a CDATA to store the name but that tends to bloat the xml more than necessary, it’s something totally dependent on the situation.
private function getRecords()
{
try
{
$query = "SELECT user_id, user FROM users LIMIT 0,5";
if ($result = mysql_query($query))
{
$response = new Response();
$response->data = "<users>" . $this->eol;
while ($row = mysql_fetch_assoc($result))
{
$response->data .= '<user id="' . $row['user_id'] . '" user="'. htmlspecialchars($row['user']) .'"/>' . $this->eol;
}
$response->data .= '</users>';
}
else
{
throw new Exception("mysql error", 0);
}
}
catch (Exception $e)
{
$response = new Response();
$response->status = "error";
$response->code = $e->getCode();
$response->data = '<![CDATA[' . $e->getMessage() .']]>';
}
return $response;
}
Next up, accessing the php class from Actionscript. I’ll step through two different approaches, the Flash way and the Flex way. The Flash way would work in Flex, however with Flex you get a few little goodies for handling rpc that make it a little cleaner.
The Flash way. Use a URLLoader, very straight forward implementation here. Create an instance of the URLLoader and URLRequest classes. Point the URLRequest at the php file. Create an instance of the URLVariables class and set the properties you intend to pass down. The critical property is the method property which the switch statement on the php side uses to determine what to do. Finally, add a result handler and you are good to go.
private function addValues():void
{
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest("http://local.test.com/api.php");
//add the required variables
var data:URLVariables = new URLVariables();
data.method = "addValues";
data.value1 = value1Txt.text;
data.value2 = value2Txt.text;
request.data = data;
loader.addEventListener(Event.COMPLETE, handleLoaderResult);
loader.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
loader.load(request);
}
The result handler is called after the php script echoes out the response. Here we grab the data from the loader, check the status attribute to make sure it’s all good, and then display the result, or show the error message.
private function handleLoaderResult(event:Event):void
{
var loader:URLLoader = event.target as URLLoader;
var data:XML = new XML(loader.data);
if (data.@status == "ok")
{
Alert.show(data, "Result");
}
else
{
Alert.show("ERROR: [" + data.@code + "]" + data.toString(), "Error");
}
}
That’s it for Flash, it’s simply a matter of parsing the xml returned in the loader and then doing whatever you need with it.
And finally, the Flex version. The Flex framework includes a whole host of classes for working with RPC. For these purposes I’ll use the HTTPService, AsyncToken and Responder. In the Flash version, you would need to create a URLLoader each time you wanted to call the php api. Flex simplifies this by allowing you to create an instance of the HTTPService class that can get reused. You can define the service in MXML, give it an id and point it at the url you wish to call. The other really nice thing is you can define what format the result will be returned in. For this sample I set it as e4x so I don’t need to worry about parsing the data to xml when it comes back from the server.
<mx:HTTPService id="api" url="http://local.test.com/api.php" resultFormat="e4x"/> Once the service is setup we can create the functions to use the service. A few differences from the Flash version. First we can simply access the instance of the HTTPService via the api variable. Second, we create an instance of the Responder class and add result and fault handlers to it. If the remote service executes correctly (or throws and handles an exception it has been coded to deal with) the result handler gets called. If something blows up, the fault handler gets used. In this sample I use the same result and fault handler for each call. In reality you would likely use different result handlers for each rpc call, in order to deal with the returned data in the correct fashion.
private function helloWorld():void
{
api.request.method = "helloWorld";
var token:AsyncToken = api.send();
var responder:mx.rpc.Responder = new mx.rpc.Responder(handleResult, handleFault);
token.addResponder(responder);
}
private function addValues():void
{
api.request.method = "addValues";
api.request.value1 = value1Txt.text;
api.request.value2 = value2Txt.text;
var token:AsyncToken = api.send();
var responder:mx.rpc.Responder = new mx.rpc.Responder(handleResult, handleFault);
token.addResponder(responder);
}
private function getUsers():void
{
api.request.method = "getRecords";
var token:AsyncToken = api.send();
var responder:mx.rpc.Responder = new mx.rpc.Responder(handleResult, handleFault);
token.addResponder(responder);
}
And here are the result and fault handlers. Again, very generic. The only thing of note, in the result hanlder, since we defined the result format for the service as e4x, we can directly access the event.result property as an XML instance without parsing it like we needed to in the Flash only version.
private function handleResult(event:ResultEvent):void
{
if (event.result.@status == "ok")
{
Alert.show(event.result, "Result");
}
else
{
Alert.show("ERROR: " + event.result.toString(), "Error");
}
}
private function handleFault(event:FaultEvent):void
{
Alert.show(event.fault.message, "Fault");
}
I hope you found this helpful, nothing like some PHP/Actionscript/XML talk to pep up the day. You can download the sample files here if you are interested.
thank you very much, is this very important information for a site that had left
Thanks for putting this together, Derrick!
Thanks to this article, I’ve just created my own php api!
This will serve my flash based blog development well. My previous approach was to use a bunch of different php pages. I knew I wanted to create an api to streamline my process and so that is how I discovered your article.
Good stuff!
FYI, this code only works in PHP 5+. I ran into some issues with “ErrorException” while first trying this code in PHP 4. Turns out that function is only available in PHP 5+.
thank you for this information, im newbie on php