/aerial/core/amfphp/core/amf/io/AMFBaseDeserializer.php
PHP | 421 lines | 230 code | 46 blank | 145 comment | 40 complexity | f3ee747ae21731a07026f4b9ae040e55 MD5 | raw file
- <?php
- /**
- * AMFDeserializer takes the raw amf input stream and converts it PHP objects
- * representing the data.
- *
- * @license http://opensource.org/licenses/gpl-license.php GNU Public License
- * @copyright (c) 2003 amfphp.org
- * @package flashservices
- * @subpackage io
- * @version $Id$
- */
-
- /**
- * Required classes
- */
- require_once(AMFPHP_BASE . "shared/util/MessageBody.php");
- require_once(AMFPHP_BASE . "shared/util/MessageHeader.php");
- require_once(AMFPHP_BASE . "amf/util/DateWrapper.php");
-
- class AMFBaseDeserializer
- {
- /**
- * The raw data input
- *
- * @access private
- * @var string
- */
- var $raw_data;
-
- /**
- * The current seek cursor of the stream
- *
- * @access private
- * @var int
- */
- var $current_byte;
-
- /**
- * The length of the stream. Since this class is not actually using a stream
- * the entire content of the stream is passed in as the initial argument so the
- * length can be determined.
- *
- * @access private
- * @var int
- */
- var $content_length;
-
- /**
- * The number of headers in the packet.
- *
- * @access private
- * @var int
- */
- var $header_count;
-
- /**
- * The content of the packet headers
- *
- * @access private
- * @var string
- */
- var $headers;
-
- /**
- * The number of bodys in the packet.
- *
- * @access private
- * @var int
- */
- var $body_count;
-
- /**
- * The content of the body elements
- *
- * @access private
- * @var string
- */
- var $body;
-
- /**
- * The object to store the amf data.
- *
- * @access private
- * @var object
- */
- var $amfdata;
-
- /**
- * The instance of the amfinput stream object
- *
- * @access private
- * @var object
- */
- var $inputStream;
-
- /**
- * metaInfo
- */
- var $meta;
-
- var $storedStrings;
- var $storedObjects;
- var $storedDefinitions;
- var $amf0storedObjects;
-
- var $native;
-
- /**
- * Constructor method for the deserializer. Constructing the deserializer converts the input stream
- * content to a AMFObject.
- *
- * @param object $is The referenced input stream
- */
- function AMFBaseDeserializer($rd)
- {
- $this->isBigEndian = AMFPHP_BIG_ENDIAN;
- $this->current_byte = 0;
- $this->raw_data = $rd; // store the stream in this object
- $this->content_length = strlen($this->raw_data); // grab the total length of this stream
- $this->charsetHandler = new CharsetHandler('flashtophp');
- $this->storedStrings = array();
- $this->storedObjects = array();
- $this->storedDefinitions = array();
- $this->native = $GLOBALS['amfphp']['native'] && function_exists('amf_decode');
- $this->decodeFlags = (AMFPHP_BIG_ENDIAN*2) | 4;
- }
-
- /**
- * deserialize invokes this class to transform the raw data into valid object
- *
- * @param object $amfdata The object to put the deserialized data in
- */
- function deserialize (&$amfdata)
- {
- $time = microtime_float();
- $this->amfdata = &$amfdata;
- $this->readHeader(); // read the binary header
- $this->readBody(); // read the binary body
- if($this->decodeFlags & 1 == 1)
- {
- //AMF3 mode
- $GLOBALS['amfphp']['encoding'] = "amf3";
- }
- global $amfphp;
- $amfphp['decodeTime'] = microtime_float() - $time;
- }
- /**
- * returns the built AMFObject from the deserialization operation
- *
- * @return object The deserialized AMFObject
- */
- function getAMFObject()
- {
- return $this->amfdata;
- }
-
- /**
- * Decode callback is triggered when an object is encountered on decode
- */
- function decodeCallback($event, $arg)
- {
- if($event == 1) //Object
-
- {
- $type =$arg;
- return $this->mapClass($type);
- }
- else if($event == 2) //Object post decode
-
- {
- $obj = $arg;
- if(method_exists($obj, 'init'))
- {
- $obj->init();
- }
- return $obj;
- }
- else if($event == 3) //XML post-decode
-
- {
- return $arg;
- }
- else if($event == 4) //Serializable post-decode
-
- {
- if($type == 'flex.messaging.io.ArrayCollection' || $type == 'flex.messaging.io.ObjectProxy')
- {
- return;
- }
- else
- {
- trigger_error("Unable to read externalizable data type " . $type, E_USER_ERROR);
- return "error";
- }
- }
- else if($event == 5) //ByteArray post decode
-
- {
- return new ByteArray($arg);
- }
- }
-
- /**
- * readHeader converts that header section of the amf message into php obects.
- * Header information typically contains meta data about the message.
- */
- function readHeader()
- {
-
- $topByte = $this->readByte(); // ignore the first two bytes -- version or something
- $secondByte = $this->readByte(); //0 for Flash,
- //1 for FlashComm
- //Disable debug events for FlashComm
- $GLOBALS['amfphp']['isFlashComm'] = $secondByte == 1;
-
- //If firstByte != 0, then the AMF data is corrupted, for example the transmission
- //
- if(!($topByte == 0 || $topByte == 3))
- {
- trigger_error("Malformed AMF message, connection may have dropped");
- exit();
- }
- $this->header_count = $this->readInt(); // find the total number of header elements
- while ($this->header_count--)
- { // loop over all of the header elements
- $name = $this->readUTF();
- $required = $this->readByte() == 1; // find the must understand flag
- //$length = $this->readLong(); // grab the length of the header element
- $this->current_byte += 4; // grab the length of the header element
- if($this->native)
- {
- $content = amf_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
- }
- else
- {
- $type = $this->readByte(); // grab the type of the element
- $content = $this->readData($type); // turn the element into real data
- }
-
- $this->amfdata->addHeader(new MessageHeader($name, $required, $content)); // save the name/value into the headers array
- }
-
- }
-
- /**
- * readBody converts the payload of the message into php objects.
- */
- function readBody()
- {
- $this->body_count = $this->readInt(); // find the total number of body elements
- while ($this->body_count--)
- { // loop over all of the body elements
-
- $this->amf0storedObjects = array();
- $this->storedStrings = array();
- $this->storedObjects = array();
- $this->storedDefinitions = array();
-
- $target = $this->readUTF();
- $response = $this->readUTF(); // the response that the client understands
-
- //$length = $this->readLong(); // grab the length of the body element
- $this->current_byte += 4;
-
- if($this->native)
- $data = amf_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
- else
- {
- $type = $this->readByte(); // grab the type of the element
- $data = $this->readData($type); // turn the element into real data
- }
-
- $this->amfdata->addBody(new MessageBody($target, $response, $data)); // add the body element to the body object
-
- }
- }
-
- /********************************************************************************
- * This used to be in AmfInputStream
- ********************************************************************************
-
- /**
- * readByte grabs the next byte from the data stream and returns it.
- *
- * @return int The next byte converted into an integer
- */
- function readByte()
- {
- return ord($this->raw_data[$this->current_byte++]); // return the next byte
- }
-
- /**
- * readInt grabs the next 2 bytes and returns the next two bytes, shifted and combined
- * to produce the resulting integer
- *
- * @return int The resulting integer from the next 2 bytes
- */
- function readInt()
- {
- return ((ord($this->raw_data[$this->current_byte++]) << 8) |
- ord($this->raw_data[$this->current_byte++])); // read the next 2 bytes, shift and add
- }
-
- /**
- * readUTF first grabs the next 2 bytes which represent the string length.
- * Then it grabs the next (len) bytes of the resulting string.
- *
- * @return string The utf8 decoded string
- */
- function readUTF()
- {
- $length = $this->readInt(); // get the length of the string (1st 2 bytes)
- //BUg fix:: if string is empty skip ahead
- if($length == 0)
- {
- return "";
- }
- else
- {
- $val = substr($this->raw_data, $this->current_byte, $length); // grab the string
- $this->current_byte += $length; // move the seek head to the end of the string
- return $this->charsetHandler->transliterate($val); // return the string
- }
- }
-
- /**
- * readLong grabs the next 4 bytes shifts and combines them to produce an integer
- *
- * @return int The resulting integer from the next 4 bytes
- */
- function readLong()
- {
- return ((ord($this->raw_data[$this->current_byte++]) << 24) |
- (ord($this->raw_data[$this->current_byte++]) << 16) |
- (ord($this->raw_data[$this->current_byte++]) << 8) |
- ord($this->raw_data[$this->current_byte++])); // read the next 4 bytes, shift and add
- }
-
- /**
- * readDouble reads the floating point value from the bytes stream and properly orders
- * the bytes depending on the system architecture.
- *
- * @return float The floating point value of the next 8 bytes
- */
- function readDouble()
- {
- $bytes = substr($this->raw_data, $this->current_byte, 8);
- $this->current_byte += 8;
- if ($this->isBigEndian)
- {
- $bytes = strrev($bytes);
- }
- $zz = unpack("dflt", $bytes); // unpack the bytes
- return $zz['flt']; // return the number from the associative array
- }
-
- /**
- * readLongUTF first grabs the next 4 bytes which represent the string length.
- * Then it grabs the next (len) bytes of the resulting in the string
- *
- * @return string The utf8 decoded string
- */
- function readLongUTF()
- {
- $length = $this->readLong(); // get the length of the string (1st 4 bytes)
- $val = substr($this->raw_data, $this->current_byte, $length); // grab the string
- $this->current_byte += $length; // move the seek head to the end of the string
- return $this->charsetHandler->transliterate($val); // return the string
- }
-
- function mapClass($typeIdentifier)
- {
- //Check out if class exists
- if($typeIdentifier == "")
- {
- return NULL;
- }
- $class = NULL;
-
- switch($typeIdentifier)
- {
- case "flex.messaging.messages.CommandMessage":
- return new CommandMessage();
- break;
- case "flex.messaging.messages.RemotingMessage":
- return new RemotingMessage();
- break;
- default:
- $packageElements = explode(".", $typeIdentifier);
- array_shift($packageElements);
-
- $mappedClass = implode("/", $packageElements);
-
- $include = FALSE;
- if(file_exists($GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.php'))
- {
- $include = $GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.php';
- }
- elseif(file_exists($GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.class.php'))
- {
- $include = $GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.class.php';
- }
-
- if($include !== FALSE)
- {
- include_once($include);
- $lastPlace = strrpos('/' . $mappedClass, '/');
- $classname = substr($mappedClass, $lastPlace);
- if(class_exists($classname))
- {
- $class = new $classname;
- }
- }
-
- return $class; // return the object
- break;
- }
- }
- }
-
- ?>