RSS
 

AMFPHP Class Mapping Primer [1.9 beta]

01 Jul

Thought I’d post a simple AMFPHP class mapping primer.

I ran into a wall after re-arranging my VO / DAO package structure on the server, learned a few things in the process and thought I’d post .

I’m assuming your using AMFPHP 1.9 beta.

Class mapping allows your php backend and actionscript frontend to pass strongly typed variables back and forth. The benefits are obvious so I won’t cover them here.

If your not after any detailed information here’s a quick set of samples classes to get you going.

PHP


// LoginVO.php is saved as {$voPath}/com/dl/app/LoginVO.php
class LoginVO
{
   var $_explicitType="com.dl.app.LoginVO";
   public $username;
   public $password;
}

AS

package com.dl.common.Login.model.vo
{
   [RemoteClass(alias="com.dl.app.LoginVO")]
   public class LoginVO
   {
      public var username:String;
      public var password:String;
   }
}

That’s it. If your after more options and detailed info, keep reading.

Sending Strongly Typed Objects from PHP to ActionScript via AMFPHP

In PHP

You have a few options (choose one).

  • Your class can declare a variable named $_explicitType;
  • The most common approach is to use the $_explicitType class member:

    class LoginVO
    {
       var $_explicitType="com.dl.app.LoginVO";
       public $username;
       public $password;
    }
    
  • You can set $GLOBALS['amfphp']['outgoingClassMappings']['localclass'] = ‘remoteclassAlias‘;
  • e.g.

    $GLOBALS['amfphp']['outgoingClassMappings']['myclass'] = "com.dl.myapp.MyClass";

    Note that the local class name associative key (‘myclass’ above) must be in lowercase with the current release of AMFPHP.

  • Rely on the reflection class (PHP 5+)
  • If your install of PHP has the ReflectionAPI you can let AMFPHP do the work *for* you. I found a few cavets using this approach on servers who’s OS uses backslashes natively. If this is the case, AMFPHP will only send the name of the class and not include any package info. There are two simple code changes you can make in AMFPHP to get around this, just drop me a line if your interested (hopefully they’ll be commited in the next release of AMFPHP).

    In actionscript

    Here to, you have a some options,

  • Use [RemoteClass] metadata tag to specify the remote class alias
  • package com.dl.common.Login.model.vo
    {
       [RemoteClass(alias="com.dl.app.LoginVO")]
       public class LoginVO
       {
          public var username:String;
          public var password:String;
       }
    }
  • Use registerClassAlias()
  • registerClassAlias(“com.dl.app.LoginVO”,LoginVO);

    Make sure your actionscript project contains a reference to the class. See my previous post for more info.


    Sending Strongly Typed Objects from ActionScript to PHP via AMFPHP

    In PHP

    Rely on the class having been registed in ActionScript with the server’s correct package [directory] structure (relative to AMFPHP’s VO base path $GLOBALS['amfphp']['customMappingsPath']). If this is the case you, your all set.

    Note: If you haven’t already you’ll need to make sure $voPath is pointing to the correct directory in AMFPHPs global.php

    Define $GLOBALS['amfphp']['incomingClassMappings']['remoteclassAlias'] = ‘localclassPackage‘. (e.g. $GLOBALS['amfphp']['incomingClassMappings']['com.dl.as3.userVO'] = ‘com.dl.userVO’);

    In ActionScript

    Again, you’ll need to use one of the two following…

  • Use [RemoteClass] metadata tag to specify the remote class alias
  • Use registerClassAlias()

    For more info check out

    AMFBaseSerializer.php’s getClassName() function

    AMFBaseDeserializer.php’s mapClass() function




     

    AMFPHP Complex Classes – Yeah I knew that

    19 Jun

    Just blew half an hour tracking down something I *knew* I’d done before. Thought I’d post here for future ‘lapses.’

    To return a typed object from PHP to the flashplayer the process is simple, declare a variable called $_expicitType in your PHP class
    e.g.
    class SummaryVO
    {
    var $_explicitType = "com.dl.SummaryVO";
    $standards = array();
    $levels = array()
    }

    In your corresponding ActionScript class use the RemoteClass metadata tag

    package com.dl
    {
    [RemoteClass(alias="com.dl.SummaryVO")]
    public class SummaryVO
    {
    public var standards:Array;
    public var levels:Array;
    }
    }

    Note the values for $_explicitType and alias are arbitrary, they can be what ever you’d like, as long as their the same in AS and PHP (provided your only conerned with PHP=>AS mapping).

    Okay, so what happens when you have ‘complex classes’ you’d like to return? Complex meaning a class who’s members are made up of other ‘custom’ class instances.

    Let’s say, for example, that in our later code example ‘standards’ was an array of ‘StandardVO.’ The problem I ran into was that I was getting a typed ‘SummaryVO’ back from AMFPHP, however my class members were not typed, just generic objects. I checked and I had taken the necessary steps to use strongly typed SummaryVO and StandardVO classes, yet the StandardVO was coming back as a plain old Object.

    We’ll it turned out in my development flurry I hadn’t used a reference to the ‘StandardVO’ class yet!! Simply declaring an instance of StandardVO did the trick (i.e. var placeHolder:StandardVO). You could also you the includes class [...] compiler option.

    Moral of the story, be sure the complier includes a reference to any class you want strongly typed from your RPCs.

     

    Pipe Demo: Mortgage App

    17 Jun

    I’ve posted a pipes version of the mortgage app.

    Things to note:

    You can load / unload the modules dynamically.

    A junction mediator is defined for each ‘player.’ In the mortgage app context that’s a mediator for the application itself, the Acme widget and the Foo widget.

    ApplicationJunctionMediator
    ModuleJunctionMediator (Acme)
    ModuleJunctionMediator (Foo)

    To make our lives easier when it comes time to unload the module, the module caches the app’s pipe fitting it’s connected to. This allows the module to easily ‘cleanup’ (disconnect our fittings) should we want to unload the module. You may find a cleaner approach to this, feel free to post in comments – the ‘caching approach’ was simple and thus the road taken for the demo.

     
     

    Understanding PureMVC Pipes

    15 Jun

    Disclaimer: This a bit of a longer post!!

    The pipes utility is newer to PureMVC and as such, I’ve seen questions on the blogosphere regarding it’s use.

    The plumbing metaphor should help wrap you head around this utility and it’s use. Keep in mind that a pipe allows for one-way message flow.

    So let’s take a look at how the utility can be used.

    One great features of ‘Pipes’ is that they can use used on top of an existing app. That is, you’ll simply need to define a JunctionMediator at/for each integration point.

    Let’s look at the simplest case, an application that loads and communicates with a module. We’ll assume that at some point you’ll want to use this same app to use multiple modules down the road. You’ll need to create a JunctionMediator for the application and a JunctionMediator for the module. We’ll dive into the details for those mediators but at a high level, that’s it – we simply define a ‘JunctionMediator’ for each ‘player.’

    Here’s a simple diagram

    Simple Pipe

    Our JunctionMediator’s will be connected together with pipes. We’ll have one pipe that allows for application-to-module message flows and another pipe that allows for module-to-application flows.

    On the receiving end of a pipe, we’ll want a pipe listener (you’ll have only one pipe listener for a given pipe). We’ll use pipe listeners to handle incoming pipe messages.

    To send messages down a pipeline, we’ll normally use the Junction’s ‘sendMessage’ function.

    Back to our simple example, our app’s JunctionMediator would be responsible for creating the app’s pipe fittings, creating pipes to connect to those fittings to the module.

    So the first thing our app’s JunctionMediator would do would be to create a new junction at creation.


    public class ApplicationJunctionMediator extends JunctionMediator
    {
    public function ApplicationJunctionMediator()
    {
    super(NAME, new Junction());
    }

    Once this mediator is registered with our facade, we’d want to create the PipeFittings. We’ll use a TeeSplit for outgoing and TeeMerge for incoming. The TeeSplit will allow us to connect to multiple modules for outbound messages. The TeeMerge will allow multiple modules to send messages up to our main app. We’ll also want to add a pipe listener on our TeeMerge. This listener will allow us to handle the messages being sent up from the modules to the app.


    override public function onRegister():void
    {
    junction.registerPipe( PipeAwareModule.APP_TO_MODULE_PIPE, Junction.OUTPUT, new TeeSplit() );
    junction.registerPipe( PipeAwareModule.MODULE_TO_APP_PIPE, Junction.INPUT, new TeeMerge() );
    junction.addPipeListener( PipeAwareModule.MODULE_TO_APP_PIPE, this, handlePipeMessage );
    }

    Our handlePipeMessage function is responsible for handling the messages coming up from our modules to our app.


    function handlePipeMessage(message:IPipeMessage):void

    Being a Mediator, we can define what application-level notifications we’re interested in and how to handle those notifications. That is, we’ll want to utilize listNotificationInterests() and handleNotification(note:INotification). We’ll use these to listen for notifications and turn desired notifications into messages to pass down our pipes.

    For example, our Mortgage App would listens for request for loan notifications and turn those notifications into messages.


    override public function handleNotification(note:INotification):void
    {

    switch( note.getName() )
    {
    case MortgageAppEventNames.REQUEST_FOR_LOAN:
    var loanMessage:Message = new Message(MortgageAppEventNames.REQUEST_FOR_LOAN,null,note);
    junction.sendMessage(PipeAwareModule.APP_TO_MODULE_PIPE,loanMessage);
    break;
    }
    }

    Our application JunctionMediator will also typically listen for a notification that a module has been loaded. Our app’s JunctionMediator will then create new pipes to connect the app’s junctionMediator to the modules junctionMediator. Something along the lines of…


    override public function handleNotification(note:INotification):void
    {

    switch( note.getName() )
    {
    case MortgageAppEventNames.REQUEST_FOR_LOAN:
    var loanMessage:Message = new Message(MortgageAppEventNames.REQUEST_FOR_LOAN,null,note);
    junction.sendMessage(PipeAwareModule.APP_TO_MODULE_PIPE,loanMessage);
    break;

    case ModuleEvents.CONNECT_MODULE_JUNCTION:
    var module:IPipeAwareModule = note.getBody() as IPipeAwareModule;

    // Create the pipe
    var moduleToApp:Pipe = new Pipe();
    // Connect the pipe to our module
    module.acceptOutputPipe(PipeAwareModule.MODULE_TO_APP_PIPE, moduleToApp);

    // Connect the pipe to our app
    var appIn:TeeMerge = junction.retrievePipe(PipeAwareModule.MODULE_TO_APP_PIPE) as TeeMerge;
    appIn.connectInput(moduleToApp);

    // Create the pipe
    var appToModule:Pipe = new Pipe();
    // Connect the pip to our module
    module.acceptInputPipe(PipeAwareModule.APP_TO_MODULE_PIPE,appToModule);

    // Connect the pipe to our app
    var appOut:TeeSplit = junction.retrievePipe(PipeAwareModule.APP_TO_MODULE_PIPE) as TeeSplit;
    appOut.connect(appToModule);

    break;

    // And let super handle the rest (ACCEPT_OUTPUT_PIPE, ACCEPT_INPUT_PIPE, SEND_TO_LOG)
    default:
    super.handleNotification(note);

    }
    }

    Finally our application’s JunctionMediator will handle the incoming pipe messages.


    override public function handlePipeMessage(message:IPipeMessage):void
    {
    // Handle our Module->Application integration
    trace(message);
    var note:INotification = message.getBody() as INotification;

    switch(note.getName())
    {
    case MortgageAppEventNames.LOAN_QUOTE_READY:
    sendNotification(note.getName(),note.getBody(),note.getType());
    break;
    default:
    sendNotification(note.getName(),note.getBody(),note.getType());
    break;
    }
    }

    That covers the basic responsibilities for our app’s JunctionMediator.

    Our module’s JunctionMediator would listen for messages coming in on the APP_TO_MODULE named pipe and send [outbound] messages on the MODULE_TO_APP pipe.


    override public function handleNotification(note:INotification):void
    {
    // Handle our Module->Application integration
    switch( note.getName() )
    {
    case ModuleFacade.QUOTE_GENERATED:
    // convert our *local* notification into the application format
    var quoteMessage:Message = new Message(MortgageAppEventNames.LOAN_QUOTE_READY,null,
    new Notification(MortgageAppEventNames.LOAN_QUOTE_READY,note.getBody(),note.getType()));
    junction.sendMessage(PipeAwareModule.MODULE_TO_APP_PIPE,quoteMessage);
    break;
    }
    }

    override public function handlePipeMessage( message:IPipeMessage ):void
    {
    // Handle our Application->Module integration
    var note:INotification = message.getBody() as INotification;
    switch(note.getName())
    {
    case MortgageAppEventNames.REQUEST_FOR_LOAN:
    sendNotification(ModuleFacade.QUOTE_REQUESTED,note.getBody(),note.getType());
    break;
    }

    }

    If the app was to load another module our diagram would become…
    Pipes App with Two Modules

    If your still have questions – just ask :)

     
     

    Loaded Module Dimensions – Width / Height

    13 Jun

    Ran across a problem regarding the display size of dynamically loaded modules today. The module was a subclass of ModuleLoader. The module would size to the minWidth / minHeight I had specified but would ignore width=”100%” for height=”100%”.

    This Adobe Tech note states that your module should use ‘percentWidth’ and ‘percentHeight.’ I set that for the module and still no luck (probably because I subclassed ModuleLoader not Module for the time being).

    What did work was to set the percentWidth / percentHeight in actionscript before I call addChild().


    module.percentHeight = 100;
    module.percentWidth = 100;
    this.addChild(module);

     
    No Comments

    Posted in Modules

     

    Pipe Architecture

    13 Jun

    Here’s a working architecture for modular applications utilizing PureMVC pipes.

    Pipe Architecture

    This allows you to have modules that load modules that load modules, etc. The modules communicate to each other via Pipes.

    The sample diagram illustrates a parent, child, grandchild relationship (An app that loads a module that loads module). You can of course, have multiple siblings.

     

    PureMVC Pipes

    12 Jun

    I had a chance to work with Cliff Hall’s PureMVC ‘Pipes’ utility this week. Highly recommended.

    If your interested in utilizing modules in your PureMVC projects, you owe it to yourself to take a look at the Pipes utility.

    What’s needed to integrate a module?

    The requirements are very light. You module should:

    Implement IPipeAware
    Create a JunctionMediator.

    Thats it.

    I took some time and refactored the Mortgage app to use the Pipes utility.

    I ran into a small bump after unloading widgets. If I unloaded a widget and then clicked “Quotes”, I still received a loan quote from what should have been an unloaded module. I ended up subclassing the ‘TeeSplit’ class to allow disconnecting a single known IPipeFitting. This allowed me to ‘cleanup’ the dynamic modules properly.

    That aside, the utility was very easy to work with – the plumbing metaphors really make things clear.

    I found the utility to be quite flexible as well. I just wrapped up working on some utility classes that allow modules to load modules that load modules etc. Getting this to work with direct core to core communications was at best ‘messy.’ Using the pipes made this very clean and simple.

     
     

    PureMVC + Lazily [late] Instantiated Components

    06 Jun

    One small caveat when working with PureMVC – If your [view] component is defined at design time, but not created at application startup you’ll need to defer the

    facade.registerMediator( )

    This might happen, for example, when your component resides in a viewstack.

    A simple work around is to dispatch an event (make sure it bubbles) on the component’s creationCompelete.

    creationComplete="dispatchEvent(new Event(CommonEvents.COMPONENT_INITIALIZED,true))"

    In the ‘application level’ mediator, create an event listener for this event

    viewComponent.addEventListener(
    CommonEvents.COMPONENT_INITIALIZED,onComponentReady,false,0,true);

    When the event is picked up you’ll have to determine which [lazy] component is ready

    public function onComponentReady(event:Event):void
    {
    var comp:UIComponent = event.target as UIComponent;

    switch(comp.id)
    {
    case "userSearch":
    facade.registerMediator(new UserSearchMediator(comp));
    break;
    case "serviceRecord":
    facade.registerMediator(new ServiceRecordMediator(comp));
    break;
    case "appToolbar":
    facade.registerMediator(new AppToolbarMediator(comp));
    break;
    }

    }

    So, in short, we simply defer creating the component’s mediator until the view component is ready :)

     
     

    Securing AMFPHP 1.9 via Authentication

    03 Jun

    With the loss of the methodTable in AMFPHP 1.9, comes a loss of the easily defined ‘roles.’

    Background

    Roles, for those of you who aren’t familiar, allow you to ‘protect’ who can invoke your AMFPHP services. For example, you probably wouldn’t want the following function accessible to everyone


    public function SetEmployeeSalary($amount)

    Users are ‘authenticated’ in AMFPHP via a call to


    Authenticate::login($username,$roles);

    Where $roles is a comma delimited set of roles for the user. If you open up \core\shared\util\Authenticate.php you’ll find the login method


    function login($name, $roles) {
    if(!session_id())
    {
    session_start();
    }
    $_SESSION['amfphp_username'] = $name;
    $_SESSION['amfphp_roles'] = $roles;
    }

    Authentication in AMFPHP 1.9

    To utilize authentication in 1.9, create a function with the following signature in your service (class).


    public function beforeFilter($function_called)

    A quick peek in /core/shared/app/BasicActions.php and you’ll see that, should your service (class) define this function, AMFPHP will call it before invoking your function. If beforeFilter returns true, the function is invoked, otherwise a security error is thrown.

    Here’s the simple approach I’ve taken..


    public function beforeFilter($function_called)
    {
    $memberName = $function_called."Roles";
    return (@$this->$memberName) ? Authenticate::isUserInRole($this->$memberName) : true;
    }

    So to secure any function, I simply define a member variable with the roles required.


    var $SetEmployeeSalaryRoles = "admin,hr";
    public function SetEmployeeSalary($amount)

    My beforeFilter function looks to see if functionNameRoles exists, if it does, than the user must have a role found in functionNameRoles. If functionNameRoles does not exist, no authentication is required.

     
    13 Comments

    Posted in AMFPHP

     

    Two must haves for those ‘rigorous’ developers out there.

    02 Jun

    I’ve come across two [free] tools I find indispensable when working under the Windows platform.

    Task Arrange
    Aqua Dock

    Task arrange
    Task Arrange
    Task arrange allows you to change up, on the fly, the order of programs listed on the taskbar.

    Aqua Dock
    Aqua Dock Desktop
    I’ve moved all of my desktop icons off my desktop and onto the dock. No need to worry about my icons being shuffled around after hooking up to a digital projector for presentations :)

     
    No Comments

    Posted in RIA

     

    AS3 PureMVC Dynamic Modules

    24 May

    Okay, I’ve had some questions on refactoring my PureMVC dynamic modules classes to support AS3 projects (i.e. no flex).

    I’ve posted a sample app that does just that.

    I threw this together off the cuff, so don’t expect too much :)

    The app (10K) simply loads 6 modules dynamically, 3 “RedTint” modules and 3 “GreenTint” modules (4k each). The app sends a notification every second containing a random color. The loaded modules pick up on this notification and display the color – each with their corresponding tint.

    Keep a close eye on Cliff’s Pipe utility as these classes may soon be obsolete :) Until that time, I hope you might find this useful – if you do, drop me a line and let me know.

    I’ve got some time between projects if anyone is looking for some RIA development…

     

    Adobe AIR on MAC

    23 May

    While wrapping up a project for a client, I ran into a problem that one of my AIR apps didn’t work on the client’s Mac. This particular project consisted of a ‘suite’ of applications, two AIR apps and one Flex app. The other two apps in the suite worked great, however the problematic AIR app just displayed a gray screen. In case anyone else runs into this – it turned out to be due to the omission of the ‘height’ parameter in the WindowedApplication tag.

     
    No Comments

    Posted in AIR

     

    Dynamic Modules … General Tips

    21 May

    Okay, for those of you getting ready to work with dynamic modules, I thought I’d share a few minor points I picked up on this past week.
    Your application must include a reference to any interfaces the module implements.

    <mx:Moudule implements"com.company.project.SomeInterface">

    You’d want a reference to com.company.project.SomeInterface in your main app.
    Likewise if the module has subclassed Module

    public class MyModule extends Module

    You’ll need a reference to MyModule in your main app as well.

    There are compiler options to include these references, however I find it easiest to just declare a variable of the corresponding type.

    i.e. var interfaceDef:ICustomInterface

    If you find yourself wanting to create your own ‘View’ class in PureMVC it’s pretty straightforward. Just ensure that you subclass the controller as well.

    Here’s a sample facade utilizing a custom view class…

    protected override function initializeController( ):void
    {
    if ( controller != null )
    return;
    controller = CustomController.getInstance( multitonKey );
    }

    // Our custom View subclass in action
    protected override function initializeView( ):void
    {
    if ( view != null )
    return;
    view = CustomView.getInstance( multitonKey );
    }

    And the custom controller…

    public static function getInstance( key:String ) : IController
    {
    if ( instanceMap[ key ] == null )
    instanceMap[ key ] = new CustomController( key );
    return instanceMap[ key ];
    }

    override protected function initializeController( ) : void
    {
    view = CustomView.getInstance(multitonKey);
    }

    Finally, our custom View

    public static function getInstance( key:String ) : IView
    {
    if ( instanceMap[ key ] == null )
    instanceMap[ key ] = new CustomView( key );
    return instanceMap[ key ];
    }

    In practice the view in initialized in the controller’s initializeController() method, so without subclassing your Controller you still maintain the standard View.

     
     

    Dynamic Flex Modules with PureMVC

    19 May

    I’m rolling out a large project, and I wanted to utilize dynamic modules for scalability.

    For those who aren’t familiar will modules, basically, there a great way to encapsulate “pieces” of your application. A trivial example would be a small ‘shell application’ that once the user logs in, loaded the appropriate use-case module. If your working in a team environment modules make for an easy project divide-and-conquer approach.

    I’ve been using the PureMVC framework lately and figured adding support for dynamic modules wouldn’t be too difficult as Cliff and the gang have already been hard at working getting the framework changes in place to make this possible (replacing singletons with multitons etc).

    Well after some working laying this out, I’m glad to say I’ve got it working. Check out this sample app Dynamic Mortgage Demo.

    The demo allows the user to get loan quotes from [fictional] banks. The demo allows the user to dynamically load / unload bank “modules.”

    The application and modules are very well encapsulated. Here’s whats required from each party…

    Application:

    Must compile with…

    A reference to any interfaces the modules loaded at runtime implement (ILoadableModule in our case).

    A reference to any subclasses of mx:Module the modules are using (PureMVCLoadableModule in our case). This is only necessary if your subclassing mx:Module.

    That’s it.

    Here’s the integration point on the modules end…

    The modules facade implements an “InitializeMapping” function which maps application notification names to local (module) notification names [inbound mapping]. The function also defines module notification name to application notification name [outbound] mappings.

    Here’s an example

    override public function initializeMappings():void
    {
    outboundMappings:Array = new Array();
    outboundMappings[QUOTE_GENERATED] = EventNames.LOAN_QUOTE_READY;

    inboundMappings = new Array();
    inboundMappings[EventNames.REQUEST_FOR_LOAN] = QUOTE_REQUESTED;
    }

    And thats the extent of what our application and modules know of each other. The rest of the ‘work’ is done automatically by a few interfaces / subclasses I wrote on top of PureMVC to make this possible. (i.e. your modules facade subclasses ModuleFacadeBase etc). No framework changes we’re required just some subclassing here and there.

     

    Flex Canvas – Rounded Corners & cornerRadius

    04 Mar

    After struggling to get my custom components (based on canvas) to render with rounded corners, I found this link.

    Problem
    Even after utilizing the cornerRadius property, my containers were not rendering with rounded corners.

    Solution
    You simply need to ensure that borderStyle property is set to solid. If a border is not desired, set the borderThickness to zero.

     
    9 Comments

    Posted in Flex

     

    Adobe AIR Accent [mood] Light

    18 Feb

    I’m posting a small AIR project I did a while back. In fact, this was my first AIR app. To that end, there’s no reason this couldn’t be compiled as a Flex app, the use case made more sense as a desktop app and I wanted to get my feet wet with AIR.

    Source Code for AirRGB

    The application allows the user to select the color displayed of some attached (via serial connection) tri-color LEDs. The program also has the ability to randomly pick two colors and “transition” from one color to the next over a user specified amount of time.

    Flash / Air doesn’t allow read / writing to serial ports. The program uses a serial proxy by by Stefano Busti(1999) and David A. Mellis(2005) found at http://www.arduino.cc/en/Main/Software to make this possible. The AIR app then can utilize a socket connection to the proxy.

    For those interested here’s a list of the parts used for the light itself:

    Arduino USB Board $34.95
    LED Light Bar (Tri-Color) $4.95
    Darlington Driver 8-Channel ULN2803 DIP $1.95
    USB Cable A-B $6.95

     

    PHPbb over 443 (https)

    14 Feb

    Quick heads up for anyone having trouble getting phpbb to working under a secure (https) installation. You may have to manually go in and change cookie_secure from 0 to 1 in the database table `_config`.

     
    No Comments

    Posted in PHP, PHPbb

     

    403 Forbidden Error with Adobe AIR app.

    13 Feb

    Here’s another issue I recently ran across. I was porting an existing (working) Flex 3 project to AIR. Under AIR my RPC calls (via AMFPHP) stopped working, and would return a 403 Permission denied error.

    Using ethereal verified the 403 error. The were minor differences in the headers sent when executing the NetConnection.call() from Flex and AIR. One of those differences happened to be the “user-agent.” My gateway is hosted on a shared webhost, so this was my first guess as to what might be the problem.

    I launched charles, and sure enough, the server would reject (via 403) any POSTs made with a user-agent of “Shockwave Flash.” Changing the user-agent (via charles) to pretty much anything else fixed the problem.

    I contacted both Adobe and my webhost. The Adobe engineers stated the default user-agent has been changed for the final release of air. My webhost was gracious enough the give me a line to add to my .htacess to revoke this “filter”

    Everything is now working.

     
    3 Comments

    Posted in AIR, AMFPHP

     

    Client.Data.UnderFlow

    13 Feb

    I ran across the following error today, Client.Data.UnderFlow undefined? I’m using AMFPHP to enable my RPC calls. As it turns out, I the variable I was returning was of a different type than I had declared in my methodTable.

     
    No Comments

    Posted in AMFPHP, Flex

     

    PHP – Large File Uploads

    05 Feb

    Okay, here’s a quick check list of php.ini variables that may need tweeking for allowing large file uploads…

    file_uploads (You’ll want this set to “On”)
    upload_max_filesize (2MB default)
    post_max_size (8MB default)
    max_execution_time
    max_input_time
    memory_limit

    My $_FILES array kept turning up empty, turned out to be the post_max_size still set at 8MB.

     
    No Comments

    Posted in PHP