web/lib/Zend/Amf/Parse/Amf0/Serializer.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Amf
       
    17  * @subpackage Parse_Amf0
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: Serializer.php 21968 2010-04-22 03:53:34Z matthew $
       
    21  */
       
    22 
       
    23 /** Zend_Amf_Constants */
       
    24 require_once 'Zend/Amf/Constants.php';
       
    25 
       
    26 /** @see Zend_Amf_Parse_Serializer */
       
    27 require_once 'Zend/Amf/Parse/Serializer.php';
       
    28 
       
    29 /**
       
    30  * Serializer PHP misc types back to there corresponding AMF0 Type Marker.
       
    31  *
       
    32  * @uses       Zend_Amf_Parse_Serializer
       
    33  * @package    Zend_Amf
       
    34  * @subpackage Parse_Amf0
       
    35  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    36  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    37  */
       
    38 class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
       
    39 {
       
    40     /**
       
    41      * @var string Name of the class to be returned
       
    42      */
       
    43     protected $_className = '';
       
    44 
       
    45     /**
       
    46      * An array of reference objects
       
    47      * @var array
       
    48      */
       
    49     protected $_referenceObjects = array();
       
    50 
       
    51     /**
       
    52      * Determine type and serialize accordingly
       
    53      *
       
    54      * Checks to see if the type was declared and then either
       
    55      * auto negotiates the type or relies on the user defined markerType to
       
    56      * serialize the data into amf
       
    57      *
       
    58      * @param  mixed $data
       
    59      * @param  mixed $markerType
       
    60      * @param  mixed $dataByVal
       
    61      * @return Zend_Amf_Parse_Amf0_Serializer
       
    62      * @throws Zend_Amf_Exception for unrecognized types or data
       
    63      */
       
    64     public function writeTypeMarker(&$data, $markerType = null, $dataByVal = false)
       
    65     {
       
    66         // Workaround for PHP5 with E_STRICT enabled complaining about "Only 
       
    67         // variables should be passed by reference" 
       
    68         if ((null === $data) && ($dataByVal !== false)) {
       
    69             $data = &$dataByVal;
       
    70         }
       
    71         if (null !== $markerType) {
       
    72             //try to reference the given object
       
    73             if (!$this->writeObjectReference($data, $markerType)) {
       
    74                 // Write the Type Marker to denote the following action script data type
       
    75                 $this->_stream->writeByte($markerType);
       
    76                 switch($markerType) {
       
    77                     case Zend_Amf_Constants::AMF0_NUMBER:
       
    78                         $this->_stream->writeDouble($data);
       
    79                         break;
       
    80                     case Zend_Amf_Constants::AMF0_BOOLEAN:
       
    81                         $this->_stream->writeByte($data);
       
    82                         break;
       
    83                     case Zend_Amf_Constants::AMF0_STRING:
       
    84                         $this->_stream->writeUTF($data);
       
    85                         break;
       
    86                     case Zend_Amf_Constants::AMF0_OBJECT:
       
    87                         $this->writeObject($data);
       
    88                         break;
       
    89                     case Zend_Amf_Constants::AMF0_NULL:
       
    90                         break;
       
    91                     case Zend_Amf_Constants::AMF0_REFERENCE:
       
    92                         $this->_stream->writeInt($data);
       
    93                         break;
       
    94                     case Zend_Amf_Constants::AMF0_MIXEDARRAY:
       
    95                         // Write length of numeric keys as zero.
       
    96                         $this->_stream->writeLong(0);
       
    97                         $this->writeObject($data);
       
    98                         break;
       
    99                     case Zend_Amf_Constants::AMF0_ARRAY:
       
   100                         $this->writeArray($data);
       
   101                         break;
       
   102                     case Zend_Amf_Constants::AMF0_DATE:
       
   103                         $this->writeDate($data);
       
   104                         break;
       
   105                     case Zend_Amf_Constants::AMF0_LONGSTRING:
       
   106                         $this->_stream->writeLongUTF($data);
       
   107                         break;
       
   108                     case Zend_Amf_Constants::AMF0_TYPEDOBJECT:
       
   109                         $this->writeTypedObject($data);
       
   110                         break;
       
   111                     case Zend_Amf_Constants::AMF0_AMF3:
       
   112                         $this->writeAmf3TypeMarker($data);
       
   113                         break;
       
   114                     default:
       
   115                         require_once 'Zend/Amf/Exception.php';
       
   116                         throw new Zend_Amf_Exception("Unknown Type Marker: " . $markerType);
       
   117                 }
       
   118             }
       
   119         } else {
       
   120             if (is_resource($data)) {
       
   121                 $data = Zend_Amf_Parse_TypeLoader::handleResource($data);
       
   122             }
       
   123             switch (true) {
       
   124                 case (is_int($data) || is_float($data)):
       
   125                     $markerType = Zend_Amf_Constants::AMF0_NUMBER;
       
   126                     break;
       
   127                 case (is_bool($data)):
       
   128                     $markerType = Zend_Amf_Constants::AMF0_BOOLEAN;
       
   129                     break;
       
   130                 case (is_string($data) && (strlen($data) > 65536)):
       
   131                     $markerType = Zend_Amf_Constants::AMF0_LONGSTRING;
       
   132                     break;
       
   133                 case (is_string($data)):
       
   134                     $markerType = Zend_Amf_Constants::AMF0_STRING;
       
   135                     break;
       
   136                 case (is_object($data)):
       
   137                     if (($data instanceof DateTime) || ($data instanceof Zend_Date)) {
       
   138                         $markerType = Zend_Amf_Constants::AMF0_DATE;
       
   139                     } else {
       
   140 
       
   141                         if($className = $this->getClassName($data)){
       
   142                             //Object is a Typed object set classname
       
   143                             $markerType = Zend_Amf_Constants::AMF0_TYPEDOBJECT;
       
   144                             $this->_className = $className;
       
   145                         } else {
       
   146                             // Object is a generic classname
       
   147                             $markerType = Zend_Amf_Constants::AMF0_OBJECT;
       
   148                         }
       
   149                         break;
       
   150                     }
       
   151                     break;
       
   152                 case (null === $data):
       
   153                     $markerType = Zend_Amf_Constants::AMF0_NULL;
       
   154                     break;
       
   155                 case (is_array($data)):
       
   156                     // check if it is an associative array
       
   157                     $i = 0;
       
   158                     foreach (array_keys($data) as $key) {
       
   159                         // check if it contains non-integer keys
       
   160                         if (!is_numeric($key) || intval($key) != $key) {
       
   161                             $markerType = Zend_Amf_Constants::AMF0_OBJECT;
       
   162                             break;
       
   163                             // check if it is a sparse indexed array
       
   164                          } else if ($key != $i) {
       
   165                              $markerType = Zend_Amf_Constants::AMF0_MIXEDARRAY;
       
   166                              break;
       
   167                          }
       
   168                          $i++;
       
   169                     }
       
   170                     // Dealing with a standard numeric array
       
   171                     if(!$markerType){
       
   172                         $markerType = Zend_Amf_Constants::AMF0_ARRAY;
       
   173                         break;
       
   174                     }
       
   175                     break;
       
   176                 default:
       
   177                     require_once 'Zend/Amf/Exception.php';
       
   178                     throw new Zend_Amf_Exception('Unsupported data type: ' . gettype($data));
       
   179             }
       
   180 
       
   181             $this->writeTypeMarker($data, $markerType);
       
   182         }
       
   183         return $this;
       
   184     }
       
   185 
       
   186     /**
       
   187      * Check if the given object is in the reference table, write the reference if it exists,
       
   188      * otherwise add the object to the reference table
       
   189      *
       
   190      * @param mixed $object object reference to check for reference
       
   191      * @param $markerType AMF type of the object to write
       
   192      * @param mixed $objectByVal object to check for reference
       
   193      * @return Boolean true, if the reference was written, false otherwise
       
   194      */
       
   195     protected function writeObjectReference(&$object, $markerType, $objectByVal = false) 
       
   196     {
       
   197         // Workaround for PHP5 with E_STRICT enabled complaining about "Only 
       
   198         // variables should be passed by reference"
       
   199         if ((null === $object) && ($objectByVal !== false)) {
       
   200             $object = &$objectByVal;
       
   201         }
       
   202 
       
   203         if ($markerType == Zend_Amf_Constants::AMF0_OBJECT 
       
   204             || $markerType == Zend_Amf_Constants::AMF0_MIXEDARRAY 
       
   205             || $markerType == Zend_Amf_Constants::AMF0_ARRAY 
       
   206             || $markerType == Zend_Amf_Constants::AMF0_TYPEDOBJECT 
       
   207         ) {
       
   208             $ref = array_search($object, $this->_referenceObjects, true);
       
   209             //handle object reference
       
   210             if($ref !== false){
       
   211                 $this->writeTypeMarker($ref,Zend_Amf_Constants::AMF0_REFERENCE);
       
   212                 return true;
       
   213             }
       
   214 
       
   215             $this->_referenceObjects[] = $object;
       
   216         }
       
   217 
       
   218         return false;
       
   219     }
       
   220 
       
   221     /**
       
   222      * Write a PHP array with string or mixed keys.
       
   223      *
       
   224      * @param object $data
       
   225      * @return Zend_Amf_Parse_Amf0_Serializer
       
   226      */
       
   227     public function writeObject($object)
       
   228     {
       
   229         // Loop each element and write the name of the property.
       
   230         foreach ($object as $key => &$value) {
       
   231             // skip variables starting with an _ private transient
       
   232             if( $key[0] == "_") continue;
       
   233             $this->_stream->writeUTF($key);
       
   234             $this->writeTypeMarker($value);
       
   235         }
       
   236 
       
   237         // Write the end object flag
       
   238         $this->_stream->writeInt(0);
       
   239         $this->_stream->writeByte(Zend_Amf_Constants::AMF0_OBJECTTERM);
       
   240         return $this;
       
   241     }
       
   242 
       
   243     /**
       
   244      * Write a standard numeric array to the output stream. If a mixed array
       
   245      * is encountered call writeTypeMarker with mixed array.
       
   246      *
       
   247      * @param array $array
       
   248      * @return Zend_Amf_Parse_Amf0_Serializer
       
   249      */
       
   250     public function writeArray(&$array)
       
   251     {
       
   252         $length = count($array);
       
   253         if (!$length < 0) {
       
   254             // write the length of the array
       
   255             $this->_stream->writeLong(0);
       
   256         } else {
       
   257             // Write the length of the numeric array
       
   258             $this->_stream->writeLong($length);
       
   259             for ($i=0; $i<$length; $i++) {
       
   260                 $value = isset($array[$i]) ? $array[$i] : null;
       
   261                 $this->writeTypeMarker($value);
       
   262             }
       
   263         }
       
   264         return $this;
       
   265     }
       
   266 
       
   267     /**
       
   268      * Convert the DateTime into an AMF Date
       
   269      *
       
   270      * @param  DateTime|Zend_Date $data
       
   271      * @return Zend_Amf_Parse_Amf0_Serializer
       
   272      */
       
   273     public function writeDate($data)
       
   274     {
       
   275         if ($data instanceof DateTime) {
       
   276             $dateString = $data->format('U');
       
   277         } elseif ($data instanceof Zend_Date) {
       
   278             $dateString = $data->toString('U');
       
   279         } else {
       
   280             require_once 'Zend/Amf/Exception.php';
       
   281             throw new Zend_Amf_Exception('Invalid date specified; must be a DateTime or Zend_Date object');
       
   282         }
       
   283         $dateString *= 1000;
       
   284 
       
   285         // Make the conversion and remove milliseconds.
       
   286         $this->_stream->writeDouble($dateString);
       
   287 
       
   288         // Flash does not respect timezone but requires it.
       
   289         $this->_stream->writeInt(0);
       
   290 
       
   291         return $this;
       
   292     }
       
   293 
       
   294     /**
       
   295      * Write a class mapped object to the output stream.
       
   296      *
       
   297      * @param  object $data
       
   298      * @return Zend_Amf_Parse_Amf0_Serializer
       
   299      */
       
   300     public function writeTypedObject($data)
       
   301     {
       
   302         $this->_stream->writeUTF($this->_className);
       
   303         $this->writeObject($data);
       
   304         return $this;
       
   305     }
       
   306 
       
   307     /**
       
   308      * Encountered and AMF3 Type Marker use AMF3 serializer. Once AMF3 is
       
   309      * encountered it will not return to AMf0.
       
   310      *
       
   311      * @param  string $data
       
   312      * @return Zend_Amf_Parse_Amf0_Serializer
       
   313      */
       
   314     public function writeAmf3TypeMarker(&$data)
       
   315     {
       
   316         require_once 'Zend/Amf/Parse/Amf3/Serializer.php';
       
   317         $serializer = new Zend_Amf_Parse_Amf3_Serializer($this->_stream);
       
   318         $serializer->writeTypeMarker($data);
       
   319         return $this;
       
   320     }
       
   321 
       
   322     /**
       
   323      * Find if the class name is a class mapped name and return the
       
   324      * respective classname if it is.
       
   325      *
       
   326      * @param object $object
       
   327      * @return false|string $className
       
   328      */
       
   329     protected function getClassName($object)
       
   330     {
       
   331         require_once 'Zend/Amf/Parse/TypeLoader.php';
       
   332         //Check to see if the object is a typed object and we need to change
       
   333         $className = '';
       
   334         switch (true) {
       
   335             // the return class mapped name back to actionscript class name.
       
   336             case Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object)):
       
   337                 $className = Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object));
       
   338                 break;
       
   339                 // Check to see if the user has defined an explicit Action Script type.
       
   340             case isset($object->_explicitType):
       
   341                 $className = $object->_explicitType;
       
   342                 break;
       
   343                 // Check if user has defined a method for accessing the Action Script type
       
   344             case method_exists($object, 'getASClassName'):
       
   345                 $className = $object->getASClassName();
       
   346                 break;
       
   347                 // No return class name is set make it a generic object
       
   348             case ($object instanceof stdClass):
       
   349                 $className = '';
       
   350                 break;
       
   351         // By default, use object's class name
       
   352             default:
       
   353         $className = get_class($object);
       
   354                 break;
       
   355         }
       
   356         if(!$className == '') {
       
   357             return $className;
       
   358         } else {
       
   359             return false;
       
   360         }
       
   361     }
       
   362 }