Zikko's Resources


Client-server communication with Flash : Common pitfalls

Flash offers several great ways to communicate with a web server. But there are some things about them, small but critical things, that I must say could be better documented. Here they are.

Getting the POSTed XML data into PHP

When sending XML data to a PHP script, it's likely you'll want to do it via HTTP POST, since it could be a rather long string. PHP automaticaly parses incoming POST data as key-value pairs, populating the $_POST array. The incoming data is expected to be in the format

key=value&something=other&...

But this is not how a XML string is formatted, not at all. So what PHP puts into $_POST is useless to you - you want the unparsed POST data. There are two ways to get this, one of which I discovered only recently - this one:

$post_data = file_get_contents('php://input');

The other way seems more clean to me, but requires a change in a php.ini directive. The first one is also more memory efficient according to PHP documentation. Anyway, I'll give you this other one too in case the first one isn't supported by some early version of PHP, haven't looked into the compability side of this. This is what you need in php.ini:

always_populate_raw_post_data = On

Once you have this, you can go:

$post_data = $HTTP_RAW_POST_DATA;

Some characters (like Swedish ones, åäöÅÄÖ), get mangled

Oh yes. And it is only a sign of health in the developer's brain to instinctively assume that this must have something to do with character encoding. And it does. But it will not matter how many funky xml meta tags you put in there. The hangup is that the Flash player interprets all incoming data as UTF8 by default. What you want is ASCII. Just put this into your ActionScript:

System.useCodepage = true;

That's it. You probably won't even need any meta tags.

Parsing the XML string into a usable data structure with PHP

PHP's build-in functions for parsing XML could be better. This is why I am sure there are plenty of good ones, probably better than this one that I wrote and like to use. But if you want to, you can have it too. Use it at your own risk, it's nowhere near complete. I tried to make it as similar to the structure you have in ActionScript as possible. Use it by creating an instance of the class xmlnode, passing the xml string as a parameter, like so.

$xml = new xmlnode( $post_data );

Each node has a type property, this can be either 'tag' or 'text'. Attributes are stored in the associative array attributes, and the tag name in the name property. Child nodes are in a linear array property called children, and can be traversed like so:

foreach($xml->children as $child)
{
    ...
}

And the code...

<?


class xmlnode
{
var $type;
var $name;
var $attributes;
var $children;
var $text;

function xmlnode( $string='' )
{
global $xml_parse_string;

if($string)
$xml_parse_string = trim( $string );

if($xml_parse_string[0]=='<')
{
$this->type = 'tag';

$xml_parse_string = substr($xml_parse_string,1);

$i1 = strpos($xml_parse_string,' ');
$i2 = strpos($xml_parse_string,'>');

if($i1===false or $i1>$i2)
{
$this->name = substr($xml_parse_string,0,$i2);
$xml_parse_string = substr($xml_parse_string,$i2);
}
else
{
$this->name = substr($xml_parse_string,0,$i1);
$xml_parse_string = substr($xml_parse_string,$i1);

$this->attributes = array();

while($xml_parse_string)
{
$string = ltrim($xml_parse_string);
$i1 = strpos($xml_parse_string,'=');
$i2 = strpos($xml_parse_string,'>');

if($i1===false or $i1>$i2)
break;

$attribute_name = trim(substr($xml_parse_string,0,$i1));
$xml_parse_string = substr($xml_parse_string,$i1+1);
$xml_parse_string = ltrim($xml_parse_string);
$xml_parse_string = substr($xml_parse_string,1);

$i = strpos($xml_parse_string,'"');

$attribute_value = substr($xml_parse_string,0,$i);
$xml_parse_string = substr($xml_parse_string,$i+1);
$xml_parse_string = ltrim($xml_parse_string);

$this->attributes[$attribute_name]=$attribute_value;
}
}

$xml_parse_string=ltrim($xml_parse_string);

if($this->name[0]=='/')
{
$xml_parse_string=substr($xml_parse_string,1);

$this->type='closing tag';
}
else
{
$this->children = array();

if($xml_parse_string[0]=='/')
{
$xml_parse_string=substr($xml_parse_string,1);
$xml_parse_string=ltrim($xml_parse_string);
$xml_parse_string=substr($xml_parse_string,1);
}
else
{
$xml_parse_string=substr($xml_parse_string,1);

while($xml_parse_string)
{
$child = new xmlnode();
if($child->type=='empty')
;
else if($child->type=='closing tag')
break;
else
$this->children[]=$child;
}
}
}
}
else
{

$i=strpos($xml_parse_string,'<');
if($i===false)
{
$this->text = $xml_parse_string;
$xml_parse_string = '';
}
else
{
$this->text = substr($xml_parse_string,0,$i);
$xml_parse_string = substr($xml_parse_string,$i);
}

$this->text=trim($this->text);

if(!$this->text)
$this->type = 'empty';
else
$this->type='text';
}
}

function getText()
{
if($this->type=='text')
return $this->text;

if(count($this->children)==0)
return '';

$firstChild = $this->children[0];

if($firstChild->type!='text')
return '';

return $firstChild->text;
}
    
    function getXML()
    {
        if( $this->type=='text' )
            return $this->text;
            
        $xml = '<'.$this->name;

        if( isset($this->attributes) )
        if( is_array($this->attributes) )
        {
            reset( $this->attributes );
            
            while(list($name,$value)=each($this->attributes))
                $xml .= ' '.$name.'="'.$value.'"';
        }
        
        if( !count( $this->children ) )
            $xml .= '/>';
        else
        {
            $xml .= '>';
            
            foreach($this->children as $childNode)
                $xml .= $childNode->getXML();
            
            $xml .= '</'.$this->name.'>';
        }
        
        return $xml;
    }
}
    


?>


All content on these pages may be used, copied and modifed freely. Questions or comments may be sent to . Also visit zikko.se.