Viewing file: Deserializer.php (15.24 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Amf * @subpackage Parse_Amf3 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id: Deserializer.php 18951 2009-11-12 16:26:19Z alexander $ */
/** Zend_Amf_Parse_Deserializer */ require_once 'Zend/Amf/Parse/Deserializer.php';
/** Zend_Amf_Parse_TypeLoader */ require_once 'Zend/Amf/Parse/TypeLoader.php';
/** * Read an AMF3 input stream and convert it into PHP data types. * * @todo readObject to handle Typed Objects * @todo readXMLStrimg to be implemented. * @todo Class could be implmented as Factory Class with each data type it's own class. * @package Zend_Amf * @subpackage Parse_Amf3 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Amf_Parse_Amf3_Deserializer extends Zend_Amf_Parse_Deserializer { /** * Total number of objects in the referenceObject array * @var int */ protected $_objectCount;
/** * An array of reference objects per amf body * @var array */ protected $_referenceObjects = array();
/** * An array of reference strings per amf body * @var array */ protected $_referenceStrings = array();
/** * An array of reference class definitions per body * @var array */ protected $_referenceDefinitions = array();
/** * Read AMF markers and dispatch for deserialization * * Checks for AMF marker types and calls the appropriate methods * for deserializing those marker types. markers are the data type of * the following value. * * @param integer $typeMarker * @return mixed Whatever the corresponding PHP data type is * @throws Zend_Amf_Exception for unidentified marker type */ public function readTypeMarker($typeMarker = null) { if(null === $typeMarker) { $typeMarker = $this->_stream->readByte(); }
switch($typeMarker) { case Zend_Amf_Constants::AMF3_UNDEFINED: return null; case Zend_Amf_Constants::AMF3_NULL: return null; case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE: return false; case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE: return true; case Zend_Amf_Constants::AMF3_INTEGER: return $this->readInteger(); case Zend_Amf_Constants::AMF3_NUMBER: return $this->_stream->readDouble(); case Zend_Amf_Constants::AMF3_STRING: return $this->readString(); case Zend_Amf_Constants::AMF3_DATE: return $this->readDate(); case Zend_Amf_Constants::AMF3_ARRAY: return $this->readArray(); case Zend_Amf_Constants::AMF3_OBJECT: return $this->readObject(); case Zend_Amf_Constants::AMF3_XML: case Zend_Amf_Constants::AMF3_XMLSTRING: return $this->readXmlString(); case Zend_Amf_Constants::AMF3_BYTEARRAY: return $this->readString(); default: require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Unsupported type marker: ' . $typeMarker); } }
/** * Read and deserialize an integer * * AMF 3 represents smaller integers with fewer bytes using the most * significant bit of each byte. The worst case uses 32-bits * to represent a 29-bit number, which is what we would have * done with no compression. * - 0x00000000 - 0x0000007F : 0xxxxxxx * - 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx * - 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx * - 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx * - 0x40000000 - 0xFFFFFFFF : throw range exception * * 0x04 -> integer type code, followed by up to 4 bytes of data. * * Parsing integers on OSFlash for the AMF3 integer data format: * @link http://osflash.org/amf3/parsing_integers * @return int|float */ public function readInteger() { $count = 1; $intReference = $this->_stream->readByte(); $result = 0; while ((($intReference & 0x80) != 0) && $count < 4) { $result <<= 7; $result |= ($intReference & 0x7f); $intReference = $this->_stream->readByte(); $count++; } if ($count < 4) { $result <<= 7; $result |= $intReference; } else { // Use all 8 bits from the 4th byte $result <<= 8; $result |= $intReference;
// Check if the integer should be negative if (($result & 0x10000000) != 0) { //and extend the sign bit $result |= ~0xFFFFFFF; } } return $result; }
/** * Read and deserialize a string * * Strings can be sent as a reference to a previously * occurring String by using an index to the implicit string reference table. * Strings are encoding using UTF-8 - however the header may either * describe a string literal or a string reference. * * - string = 0x06 string-data * - string-data = integer-data [ modified-utf-8 ] * - modified-utf-8 = *OCTET * * @return String */ public function readString() { $stringReference = $this->readInteger();
//Check if this is a reference string if (($stringReference & 0x01) == 0) { // reference string $stringReference = $stringReference >> 1; if ($stringReference >= count($this->_referenceStrings)) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Undefined string reference: ' . $stringReference); } // reference string found return $this->_referenceStrings[$stringReference]; }
$length = $stringReference >> 1; if ($length) { $string = $this->_stream->readBytes($length); $this->_referenceStrings[] = $string; } else { $string = ""; } return $string; }
/** * Read and deserialize a date * * Data is the number of milliseconds elapsed since the epoch * of midnight, 1st Jan 1970 in the UTC time zone. * Local time zone information is not sent to flash. * * - date = 0x08 integer-data [ number-data ] * * @return Zend_Date */ public function readDate() { $dateReference = $this->readInteger(); if (($dateReference & 0x01) == 0) { $dateReference = $dateReference >> 1; if ($dateReference>=count($this->_referenceObjects)) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Undefined date reference: ' . $dateReference); } return $this->_referenceObjects[$dateReference]; }
$timestamp = floor($this->_stream->readDouble() / 1000);
require_once 'Zend/Date.php'; $dateTime = new Zend_Date((int) $timestamp); $this->_referenceObjects[] = $dateTime; return $dateTime; }
/** * Read amf array to PHP array * * - array = 0x09 integer-data ( [ 1OCTET *amf3-data ] | [OCTET *amf3-data 1] | [ OCTET *amf-data ] ) * * @return array */ public function readArray() { $arrayReference = $this->readInteger(); if (($arrayReference & 0x01)==0){ $arrayReference = $arrayReference >> 1; if ($arrayReference>=count($this->_referenceObjects)) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Unknow array reference: ' . $arrayReference); } return $this->_referenceObjects[$arrayReference]; }
// Create a holder for the array in the reference list $data = array(); $this->_referenceObjects[] =& $data; $key = $this->readString();
// Iterating for string based keys. while ($key != '') { $data[$key] = $this->readTypeMarker(); $key = $this->readString(); }
$arrayReference = $arrayReference >>1;
//We have a dense array for ($i=0; $i < $arrayReference; $i++) { $data[] = $this->readTypeMarker(); }
return $data; }
/** * Read an object from the AMF stream and convert it into a PHP object * * @todo Rather than using an array of traitsInfo create Zend_Amf_Value_TraitsInfo * @return object|array */ public function readObject() { $traitsInfo = $this->readInteger(); $storedObject = ($traitsInfo & 0x01)==0; $traitsInfo = $traitsInfo >> 1;
// Check if the Object is in the stored Objects reference table if ($storedObject) { $ref = $traitsInfo; if (!isset($this->_referenceObjects[$ref])) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Unknown Object reference: ' . $ref); } $returnObject = $this->_referenceObjects[$ref]; } else { // Check if the Object is in the stored Definistions reference table $storedClass = ($traitsInfo & 0x01) == 0; $traitsInfo = $traitsInfo >> 1; if ($storedClass) { $ref = $traitsInfo; if (!isset($this->_referenceDefinitions[$ref])) { require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Unknows Definition reference: '. $ref); } // Populate the reference attributes $className = $this->_referenceDefinitions[$ref]['className']; $encoding = $this->_referenceDefinitions[$ref]['encoding']; $propertyNames = $this->_referenceDefinitions[$ref]['propertyNames']; } else { // The class was not in the reference tables. Start reading rawdata to build traits. // Create a traits table. Zend_Amf_Value_TraitsInfo would be ideal $className = $this->readString(); $encoding = $traitsInfo & 0x03; $propertyNames = array(); $traitsInfo = $traitsInfo >> 2; }
// We now have the object traits defined in variables. Time to go to work: if (!$className) { // No class name generic object $returnObject = new stdClass(); } else { // Defined object // Typed object lookup agsinst registered classname maps if ($loader = Zend_Amf_Parse_TypeLoader::loadType($className)) { $returnObject = new $loader(); } else { //user defined typed object require_once 'Zend/Amf/Exception.php'; throw new Zend_Amf_Exception('Typed object not found: '. $className . ' '); } }
// Add the Object ot the reference table $this->_referenceObjects[] = $returnObject;
$properties = array(); // clear value // Check encoding types for additional processing. switch ($encoding) { case (Zend_Amf_Constants::ET_EXTERNAL): // Externalizable object such as {ArrayCollection} and {ObjectProxy} if (!$storedClass) { $this->_referenceDefinitions[] = array( 'className' => $className, 'encoding' => $encoding, 'propertyNames' => $propertyNames, ); } $returnObject->externalizedData = $this->readTypeMarker(); break; case (Zend_Amf_Constants::ET_DYNAMIC): // used for Name-value encoding if (!$storedClass) { $this->_referenceDefinitions[] = array( 'className' => $className, 'encoding' => $encoding, 'propertyNames' => $propertyNames, ); } // not a refrence object read name value properties from byte stream do { $property = $this->readString(); if ($property != "") { $propertyNames[] = $property; $properties[$property] = $this->readTypeMarker(); } } while ($property !=""); break; default: // basic property list object. if (!$storedClass) { $count = $traitsInfo; // Number of properties in the list for($i=0; $i< $count; $i++) { $propertyNames[] = $this->readString(); } // Add a refrence to the class. $this->_referenceDefinitions[] = array( 'className' => $className, 'encoding' => $encoding, 'propertyNames' => $propertyNames, ); } foreach ($propertyNames as $property) { $properties[$property] = $this->readTypeMarker(); } break; }
// Add properties back to the return object. foreach($properties as $key=>$value) { if($key) { $returnObject->$key = $value; } }
}
if($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) { if(isset($returnObject->externalizedData)) { $returnObject = $returnObject->externalizedData; } else { $returnObject = get_object_vars($returnObject); } }
return $returnObject; }
/** * Convert XML to SimpleXml * If user wants DomDocument they can use dom_import_simplexml * * @return SimpleXml Object */ public function readXmlString() { $xmlReference = $this->readInteger(); $length = $xmlReference >> 1; $string = $this->_stream->readBytes($length); return simplexml_load_string($string); } }
|