Category Archives: Flex

Always on top Webcam

I’m going to be doing a video critique of some source code later on today and the people being critiqued wanted to have my mug showing so they could see the looks of incredulity (I am kidding, of course).  So I did some looking around to find something that would keep the webcam software on top of the other windows.  Turns out there’s not much there or there was some kind pay mechanism and I really didn’t want to pay money to see myself in a webcam window that stayed above the other windows.

So, me being me, I decided to use our Flash Builder for PHP IDE and write what I needed.  It’s nice and simple.  Here’s the code.

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
 xmlns:s="library://ns.adobe.com/flex/spark" 
 xmlns:mx="library://ns.adobe.com/flex/mx"
 alwaysInFront="true"
 creationComplete="initCamera()">
 <fx:Script>
 <![CDATA[
 import mx.collections.ArrayCollection;
 import mx.rpc.events.ResultEvent;
 
 protected var video : Video;
 protected var resolutions : Array = [{
 height: 480, width: 640
 },{
 height: 600, width: 800
 },{
 height: 768, width: 1024
 },{
 height: 720, width: 1280
 }
 ];
 
 protected function initCamera() : void {
 if (video) {
 videoDisplay.removeChild(video);
 }
 var camWidth : int = resolutions[cameraRes.value]["width"]; 
 var camHeight : int = resolutions[cameraRes.value]["height"]; 
 video = new Video(camWidth, camHeight);
 var camera : Camera = Camera.getCamera();
 camera.setMode(camWidth, camHeight, 30, true);
 video.attachCamera(camera);
 videoDisplay.addChild(video);
 width = camera.width;
 height = camera.height;
 }
 ]]>
 </fx:Script>
 <s:VideoDisplay x="0" y="0" width="100%" height="100%" id="videoDisplay" />
 <s:HSlider bottom="10" width="17%" change="initCamera()" horizontalCenter="-1" maximum="4"
 minimum="0" value="0" id="cameraRes"/>
</s:WindowedApplication>

Here’s the AIR file.  If you have AIR installed you can easily run it.  Here it is with a Windows installer.

Authentication using Zend_Amf

I forget why, but a few days ago I started doing some digging around with authentication in Zend_Amf_Server.  I had figured that I would add an adapter to the Zend_Amf_Server::setAuth() method and that would be it.

But I was wrong.

AMF allows for multiple request bodies to be sent at the same time.  Of those there are several “special” types of commands.  One of those commands is logging in.  What this means is that you don’t need a method that logs someone in for you.  Zend_Amf_Server handles authentication separately from your service classes.

Authentication for Zend_Amf_Server will generally use a combination of Zend_Auth and Zend_Acl components.  Zend_Auth is used to provide the credential verification while Zend_Acl is used to validate that the current user user can access the requested service method.  It is actually a relatively trivial task to restrict access to non-logged in users using the method that I will describe here.

The first step in the process is to create an authentication adapter.  It really doesn’t matter what you’re using.  What matters is that the adapter returns an identity object with a property called “role”.  The built in ACL handle expects this to be part of the identity object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Auth extends Zend_Amf_Auth_Abstract
{
	const LOGGEDIN_ROLE = 'loggedin';
 
	public function authenticate()
	{
		$identity = new stdClass();
		$result = Zend_Auth_Result::FAILURE;
 
		// Do a proper login, y'all
		if ($this->_username == 'test' && $this->_password == 'test') {
			$identity->role = self::LOGGEDIN_ROLE;
			$result = Zend_Auth_Result::SUCCESS;
		} else {
			$identity->role = Zend_Amf_Constants::GUEST_ROLE;
		}
 
		return new Zend_Auth_Result($result, $identity);
	}
}

The Auth class extends Zend_Amf_Auth_Abstract because Flex seems to require username and passwords as being the only mechanism for passing credentials.  The abstract class defines a method that hooks in with the special commands and passes the special credentials to the special adapter.  Clearly your authentication mechanism should be better than the one that I put in here, but you’ll get the idea.  The most important part is adding the role property to the identity object and passing it to the Zend_Auth_Result object.

Then in your gateway you need to add this adapter as well as create an simple ACL.

1
2
3
4
5
6
7
8
9
10
11
12
$server = new Zend_Amf_Server();
$server->addDirectory(realpath(__DIR__.'/../services'));
 
$acl = new Zend_Acl();
$acl->addRole(Auth::LOGGEDIN_ROLE);
$acl->allow(Auth::LOGGEDIN_ROLE);
$server->setAcl($acl);
 
$auth = new Auth();
$server->setAuth($auth);
 
echo $server->handle();

This adds the new Auth role to the ACL and says that it has access to everything.  Since there is no place where I allow guest access (denoted by Zend_Amf_Constants::GUEST_ROLE in the adapter) guest requests will be denied.

With just this little bit of code you now have a mechanism that will provide restricted access to all of your service objects.

Passing typed ActionScript objects to Flex using PHP and a message queue

Last week I wrote up a few blog posts (here, here and here) about creating a Flex based dashboard that utilized message queues to pass data.  It was a really fun example to write but there was one thing I did not get to implement.  What I wanted to do was use the sales notification mechanism to pass PHP objects to Flex using the message queue.  But I could not get the unserialization mechanism to work and so I had to settle for passing a simple message that a sale had been made.

However, because you can pass typed objects back and forth between PHP and ActionScript over HTTP using Zend_Amf_Server I figured that there MUST be a way of doing it automatically.  The first thing I did was create a valueObject class called Boogers (I descend into adolescence while trying new things) and called it in ActionScript so I could see the bytes that were created.  The class Boogers had a property called “nutso” (again, adolescence) to which I assigned the value of “what?”.  The code looked something like this

1
2
3
4
5
6
7
8
9
10
var bgrs : Boogers = new Boogers;
bgrs.nutso = "what?";
var baobj : ByteArray = new ByteArray;
baobj.writeObject(bgrs);
var ints2 : String = new String();
baobj.position = 0;
for (var i : uint = 0; i < baobj.length; i++) {
  var b : uint = baobj.readByte();
  ints2 +=  b + " " ;
}

This resulted in the bytes

1
10 19 41 118 97 108 117 101 79 98 106 101 99 116 115 46 66 111 111 103 101 114 115 11 110 117 116 115 111 6 11 119 104 97 116 63

Then I wrote some PHP code that created a PHP object called valueObjects\Boogers, serialize it and then output the bytes so I could compare it with the ActionScript output.  Note  that the class name follows the same namespace definition as the ActionScript class.  I wanted to have direct 1:1 relationships between PHP and ActionScript.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace valueObjects;
$b = new Boogers();
$b->nutso = "what?";
 
$stream = new \Zend_Amf_Parse_OutputStream();
$ser = new \Zend_Amf_Parse_Amf3_Serializer($stream);
$ser->writeObject($b);
$output = (string)$stream->getStream();
 
$a = '';
for ($i = 0; $i < strlen($output); $i++) {
  $a .= ord($output[$i]) . ' ';
}
echo $a;

 

The end result were the bytes

1
19 41 118 97 108 117 101 79 98 106 101 99 116 115 92 66 111 111 103 101 114 115 11 110 117 116 115 111 6 11 119 104 97 116 63

It was missing char 10.  But I found out that you needed to do a newline character for AMF to work properly, so I just prepended it to my output

1
$output = "\n" . (string)$stream->getStream();

So the next thing I wanted to do was send it to a message queue where ActionScript could read it using Stomp.

1
2
3
$stomp = new \Zend_Queue_Adapter_Activemq(array());
$stomp->setQueue(new \Zend_Queue(array('name' => '/queue/data')));
$stomp->send($output);

I ran the code and it sent the message to the message queue.  On the ActionScript side I set up a Stomp handler like I did in my webinar demo and was able to receive the message.  Reading the message is done by creating a method that responds to a message event generated by the Stomp library.

1
2
3
public function processMessage(msg : MessageEvent) : void {
  var obj : * = msg.message.body.readObject();
}

But the problem I ran into was that the typing of obj was always a generic Object.  So I proceeded to try and figure out how to get a properly typed object passed into ActionScript.  I tried several different methods but the craziest was that I tried was trying to implement a sort of null RPC call that would call com.adobe.serializers.utility.TypeUtility.convertResultHandler to do the unserializing.  But no matter what, none of the methods I tried would yield a properly type ActionScript object.  So I looked at the text output of the PHP output.

1
)valueObjects\Boogersnutsowhat?

Oh.

Notice anything?

Yep.  PHP namespace separator.  What did ActionScript use?  Yep, a period.

To solve it I added one line to the ActionScript processMessage() method.

1
2
3
4
public function processMessage(msg : MessageEvent) : void {
  flash.net.registerClassAlias("valueObjects\\Boogers", valueObjects.Boogers);
  var obj : * = msg.message.body.readObject();
}

Now when it is run I get a properly typed ActionScript object that I can work on in my Flex application.

Connecting PHP to ActionScript and Flex using Stomp

In yesterday’s post I talked a little bit about some of the details on how I used messaging to connect a front end on demand request to a back end scheduled data processing mechanism.  In this post we’re going to talk about how to send data from a web page to a running Flex application without using HTTP.  It is really quite easy.

First up you need a message queue that supports Stomp.  Stomp is a text-based message queue protocol that a good number of message queue applications support.  I chose ActiveMQ, mostly because of authentication issues I was running into with RabbitMQ that I didn’t have time to solve.  Stomp isn’t turned on automatically so you need to change some config settings.  I have details at my first post on how to do that.

In my demo I wanted to have real time notifications of when a sale came in from a Magento application.  So the first thing to do would be to create a queue endpoint in ActiveMQ that you can send the data to.  That’s the easy part.  Next I needed to create an observer that would be triggered when a sale is made.  Magento uses an event based system and so hooking in to that was relatively easy.  The observer looked like this:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use vo\SaleItem;
use vo\Sale;
use log\Logger;
 
class Zend_Dashboard_Model_Observer
{
 
  public function logSale(Varien_Event_Observer $observer)
  {
 
    $session = Mage::getSingleton('checkout/session');
    $orderId = $session->getLastOrderId();
    $order = Mage::getModel('sales/order')->load($orderId);
    $items = $order->getAllItems();
 
    $sale = new Sale();
    $sale->date = time();
    $sale->total = $order->getTotalDue();
    foreach ($items as $item) {
      $sItem = new SaleItem();
      $sItem->name = $item->getData('name');
      $sItem->price = $item->getData('price');
      $sItem->qty	 = $item->getData('qty_ordered');
      $sale->items[] = $sItem;
    }
    $logger = new Logger();
    $logger->registerSale($sale);
  }
}

 

The Logger class that it calls is where the messaging occurs.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace log;
 
use vo\Sale;
 
class Logger
{
 
  private static $queues = array();
 
  /**
  *
  * Retrieves a queue object based on the name
  * @param string $queue
  * @return \Zend_Queue_Adapter_Activemq
  * @throws Exception
  */
 
  public function getQueue($queue)
  {
    if (!isset(self::$queues[$queue])) {
      $config = new \Zend_Config_Ini(__DIR__ . '/../../etc/config.ini');
      if (!isset($config->mq->$queue)) {
        throw new Exception('Undefined queue configuration');
      }
 
      $stomp = new \Zend_Queue_Adapter_Activemq(array());
      $stomp->setQueue(
        new \Zend_Queue(
          array(
            'name'=> $config->mq->$queue->endpoint
          )
        )
      );
 
      self::$queues[$queue] = $stomp;
 
    }
    return self::$queues[$queue];
  }
 
  public function registerSale(Sale $sale)
  {
    $queue = $this->getQueue('sales');
 
    $date = new \Zend_Date();
    $date->setTimestamp($sale->date);
 
    $output = sprintf(
      "%s Total: \$%s Items: %d",
      $date->toString(\Zend_Date::DATETIME_MEDIUM),
      $sale->total,
      count($sale->items)
    );
    // Send notification
    $queue->send($output);
  }
}

 

The workings of the logger and the configuration are described in yesterday’s post.  For this notification all I needed was a simple text message stating that a purchase was made and how much.  I want to figure out how to send an AMF serialized object to a Flash front end but I haven’t had time to do that yet.  So a simple text message will do.

Once the message is in the queue we now need to retrieve it in our Flex application.  I used AS3Stomp for the connection.  What I did was create a VGroup which could pretty much be inserted on any visual component. In there I created a list element that would be populated with the individual messages that were received from the queue.  The data provider for the list is a simple array of the individual messages which had been received.

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    width="100%" height="100%" horizontalAlign="center"
    creationComplete="vgroup1_creationCompleteHandler(event)"
    xmlns:stomp="org.codehaus.stomp.*">
    <fx:Script>
    <![CDATA[
    import flashx.textLayout.elements.ListElement;
    import mx.events.FlexEvent;
    import org.codehaus.stomp.Stomp;
    import org.codehaus.stomp.event.MessageEvent;
    import valueObjects.Sale;
 
    protected function vgroup1_creationCompleteHandler( event : FlexEvent ) : void {
      stomp.connect();
      stomp.subscribe("/queue/sales");
    }
 
    protected function stomp_messageHandler( event : MessageEvent ) : void {
      var str : String = event.message.body.readUTFBytes(event.message.body.length);
      var data : Object = new Object;
      data.label = str;
      salesMessages.addItem(data);
    }
  ]]>
 
  </fx:Script>
  <fx:Declarations>
    <stomp:Stomp id="stomp" message="stomp_messageHandler(event)" />
    <s:ArrayCollection id="salesMessages" />
  </fx:Declarations>
 
  <s:Label text="Sales"/>
  <s:List id="saleList" width="100%" height="100%" color="#000000" dataProvider="{salesMessages}" fontSize="13"></s:List>
 
</s:VGroup>

The stomp object was provided as a declaration with a method associated with it’s “message” event which is thrown every time a new message comes in.  When a new message comes in the event is fired and the messageHandler() method is called where we read the message data into a string and attach it to an object with a label property.  Then we add it to the data provider at which point the list will update itself with the new value.

Easy.

Details on building a Flex-based dashboard with a PHP backend

Yesterday (June 1st) I wrote a blog post on how to set up an example application that I did for a webinar with Adobe and building a Flash based dashboard application (I would suggest watching it) connecting into to PHP.  Today I would like to provide some of the details of how I did all that.  I was a bit pressed for time while building the example app, and I did my standard thing, taking the Mythbusters motto to it’s logical conclusion.  But in the end I think it worked out well.  The example is complicated but a dashboard is intended to aggregate data from multiple different places and so while it was complex I also think that the attendees were able to see how and why data was processed as it was.

The dashboard application was a Flex-based app that could get summary information and batched information from a Magento based e-commerce site.  It would display a traffic summary, slightly delayed sales information (which products were selling best) and realtime notification of sales that occurred.

The way it worked was that all of the information that was going to be displayed in the dashboard was sent into one of three message queues.  That’s right.  The PHP application did not use a database. Well, it did, later on, but the actual registering of data was not done in the standard PHP way of doing a database insert.

Heresy!  No, actually I think there are a lot of problems that PHP developers solve with SQL that should be solved with message queues.  In this case, there were three things that I wanted.  I wanted traffic information, notification of a sale and the details of that sale.  But I really didn’t need to keep that information once it was processed and I didn’t care about ACID compliance or anything like that.  I basically wanted to throw data somewhere where I could get it later.  That’s where the message queue came in.

I chose ActiveMQ as my message queue.  I tried RabbitMQ but I ran into authentication issues that I didn’t have time to solve.  It was quicker to install ActiveMQ.  ActiveMQ has a feature that it shares with RabbitMQ and that is the Stomp interface.  Most message queues have some kind of binary protocol that they use to initiate communication.  But Stomp is a text based protocol.  What that means is that it is a) easy to build adapters for, and b) very easy to hack if you need one built for you.

Zend Framework has a Stomp interface, which requires some messing around with, but it also has an ActiveMQ interface that uses Stomp.  What that means is that it uses the Stomp interface but makes sure that it’s working with ActiveMQ with any “special” things that needs to be done.  ActionScript, the Flash-based programming language, also has a Stomp based interface available via a third party.  What this meant is that I could connect to a message queue and both the front end and the back end were able to interact with it.

What I wanted to do was send data into the queue that I was either going to a) retrieve directly using the dashboard, or b) pass to a PHP job for batch processing.  Messages are simple unstructured text.  A) was simple because I was just passing a notification.  B) was more problematic because I wanted to pass structured data, i.e. a log object.  But wait!  A serialized object is unstructured text!  So passing the object was no problem.  To do this I created a logger class that understood a few different classes.  We’ll start with those.

First the LogItem class

1
2
3
4
5
6
7
8
namespace log;
 
class LogItem
{
public $title;
public $url;
public $timestamp;
}

Now let’s take a look at the Logger class. (I am omitting the sales portion)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace log;
 
class Logger
{
 
private static $queues = array();
 
public function getQueue($queue)
{
    if (!isset(self::$queues[$queue])) {
        $config = new \Zend_Config_Ini(__DIR__ . '/../../etc/config.ini');
        if (!isset($config->mq->$queue)) {
            throw new Exception('Undefined queue configuration');
        }
 
        $stomp = new \Zend_Queue_Adapter_Activemq(array());
        $stomp->setQueue(
            new \Zend_Queue(
                array(
                   'name'=> $config->mq->$queue->endpoint
                )
            )
        );
 
        self::$queues[$queue] = $stomp;
 
    }
    return self::$queues[$queue];
}
 
public function log($queue, LogItem $log)
{
    $this->getQueue($queue)->send(serialize($log));
}
}

 

This class works in conjunction with a config file like this

1
2
3
4
mq.traffic.endpoint = /queue/traffic
mq.traffic.scheme = tcp
mq.traffic.host = localhost
mq.traffic.port = 61613

The Logger object receives a request to log a LogItem object on a specific queue.  It then calls getQueue() which looks to see if a configuration exists for that queue.  If it does it creates a new ActiveMQ adapter object, sets its queue name and returns it.  Then the log() method serializes the $log object and passes it to the send() method of the ActiveMQ.

At this point the data is in the message queue and you’re done, right?

Nope.  Now you need to pull it out of the queue.  On the PHP side it is pretty much the same as queuing it.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$stomp = new \Zend_Queue_Adapter_Activemq(array());
$stomp->setQueue(
  new \Zend_Queue(
    array(
      'name'=> $config->mq->$queue->endpoint
    )
  )
);
 
while (true) {
  $msgs = $stomp->receive();
 
  foreach ($msgs as $msg) {
    /* @var $msg Zend_Queue_Message */
    $logItem = unserialize($msg->body);
    // Do your thing
  }
}

 

In here we create our connection to the queue daemon and state the queue name.  Then, in this loop, we state that we want to receive data from the queue by calling the receive() method.  Generally a message queue will allow a connection to sit idle indefinitely until there is data on the queue.  But for PHP, since most are not long running programs, you will want to have a timeout.  Leaving the first argument null on the receive() call will set the timeout to be the default, but you probably should set it relatively low.  The receive() method will return an object of Zend_Queue_Message_Iterator which implements Iterator which means it can be used in a foreach loop.  Each item in the object returned will be an instance of Zend_Queue_Message which contains your data along with some meta data.  I didn’t care about the meta data so all I did was unserialized the body of the message which then gives the instance of the object that I had passed in to the queue earlier.

That covers about 1/8th of what I still have left to talk about concerning the webinar I did with Adobe.  But one of the more interesting things I did was use a message queue to communicate between a front end PHP application, a back end PHP application and a front end Flex application (which I didn’t get to).  I personally think that PHP developers should spend a little time looking at asynchronous communication and examining whether their applications could use it.  Perhaps this will help you get on your way.

Web Analytics