| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- <?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;
- }
- $clazz = NULL;
- $mappedClass = str_replace('.', '/', $typeIdentifier);
-
- if($typeIdentifier == "flex.messaging.messages.CommandMessage")
- {
- return new CommandMessage();
- }
- if($typeIdentifier == "flex.messaging.messages.RemotingMessage")
- {
- return new RemotingMessage();
- }
-
- if(isset($GLOBALS['amfphp']['incomingClassMappings'][$typeIdentifier]))
- {
- $mappedClass = str_replace('.', '/', $GLOBALS['amfphp']['incomingClassMappings'][$typeIdentifier]);
- }
-
- $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))
- {
- $clazz = new $classname;
- }
- }
-
- return $clazz; // return the object
- }
- }
- ?>
|