File indexing completed on 2024-06-23 05:55:01

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Amf
0017  * @subpackage Parse_Amf0
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /** Zend_Amf_Constants */
0024 // require_once 'Zend/Amf/Constants.php';
0025 
0026 /** @see Zend_Amf_Parse_Serializer */
0027 // require_once 'Zend/Amf/Parse/Serializer.php';
0028 
0029 /**
0030  * Serializer PHP misc types back to there corresponding AMF0 Type Marker.
0031  *
0032  * @uses       Zend_Amf_Parse_Serializer
0033  * @package    Zend_Amf
0034  * @subpackage Parse_Amf0
0035  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0036  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0037  */
0038 class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
0039 {
0040     /**
0041      * @var string Name of the class to be returned
0042      */
0043     protected $_className = '';
0044 
0045     /**
0046      * An array of reference objects
0047      * @var array
0048      */
0049     protected $_referenceObjects = array();
0050 
0051     /**
0052      * Determine type and serialize accordingly
0053      *
0054      * Checks to see if the type was declared and then either
0055      * auto negotiates the type or relies on the user defined markerType to
0056      * serialize the data into amf
0057      *
0058      * @param  mixed $data
0059      * @param  mixed $markerType
0060      * @param  mixed $dataByVal
0061      * @return Zend_Amf_Parse_Amf0_Serializer
0062      * @throws Zend_Amf_Exception for unrecognized types or data
0063      */
0064     public function writeTypeMarker(&$data, $markerType = null, $dataByVal = false)
0065     {
0066         // Workaround for PHP5 with E_STRICT enabled complaining about "Only
0067         // variables should be passed by reference"
0068         if ((null === $data) && ($dataByVal !== false)) {
0069             $data = &$dataByVal;
0070         }
0071         if (null !== $markerType) {
0072             //try to reference the given object
0073             if (!$this->writeObjectReference($data, $markerType)) {
0074                 // Write the Type Marker to denote the following action script data type
0075                 $this->_stream->writeByte($markerType);
0076                 switch($markerType) {
0077                     case Zend_Amf_Constants::AMF0_NUMBER:
0078                         $this->_stream->writeDouble($data);
0079                         break;
0080                     case Zend_Amf_Constants::AMF0_BOOLEAN:
0081                         $this->_stream->writeByte($data);
0082                         break;
0083                     case Zend_Amf_Constants::AMF0_STRING:
0084                         $this->_stream->writeUTF($data);
0085                         break;
0086                     case Zend_Amf_Constants::AMF0_OBJECT:
0087                         $this->writeObject($data);
0088                         break;
0089                     case Zend_Amf_Constants::AMF0_NULL:
0090                         break;
0091                     case Zend_Amf_Constants::AMF0_REFERENCE:
0092                         $this->_stream->writeInt($data);
0093                         break;
0094                     case Zend_Amf_Constants::AMF0_MIXEDARRAY:
0095                         // Write length of numeric keys as zero.
0096                         $this->_stream->writeLong(0);
0097                         $this->writeObject($data);
0098                         break;
0099                     case Zend_Amf_Constants::AMF0_ARRAY:
0100                         $this->writeArray($data);
0101                         break;
0102                     case Zend_Amf_Constants::AMF0_DATE:
0103                         $this->writeDate($data);
0104                         break;
0105                     case Zend_Amf_Constants::AMF0_LONGSTRING:
0106                         $this->_stream->writeLongUTF($data);
0107                         break;
0108                     case Zend_Amf_Constants::AMF0_TYPEDOBJECT:
0109                         $this->writeTypedObject($data);
0110                         break;
0111                     case Zend_Amf_Constants::AMF0_AMF3:
0112                         $this->writeAmf3TypeMarker($data);
0113                         break;
0114                     default:
0115                         // require_once 'Zend/Amf/Exception.php';
0116                         throw new Zend_Amf_Exception("Unknown Type Marker: " . $markerType);
0117                 }
0118             }
0119         } else {
0120             if (is_resource($data)) {
0121                 $data = Zend_Amf_Parse_TypeLoader::handleResource($data);
0122             }
0123             switch (true) {
0124                 case (is_int($data) || is_float($data)):
0125                     $markerType = Zend_Amf_Constants::AMF0_NUMBER;
0126                     break;
0127                 case (is_bool($data)):
0128                     $markerType = Zend_Amf_Constants::AMF0_BOOLEAN;
0129                     break;
0130                 case (is_string($data) && (($this->_mbStringFunctionsOverloaded ? mb_strlen($data, '8bit') : strlen($data)) > 65536)):
0131                     $markerType = Zend_Amf_Constants::AMF0_LONGSTRING;
0132                     break;
0133                 case (is_string($data)):
0134                     $markerType = Zend_Amf_Constants::AMF0_STRING;
0135                     break;
0136                 case (is_object($data)):
0137                     if (($data instanceof DateTime) || ($data instanceof Zend_Date)) {
0138                         $markerType = Zend_Amf_Constants::AMF0_DATE;
0139                     } else {
0140 
0141                         if($className = $this->getClassName($data)){
0142                             //Object is a Typed object set classname
0143                             $markerType = Zend_Amf_Constants::AMF0_TYPEDOBJECT;
0144                             $this->_className = $className;
0145                         } else {
0146                             // Object is a generic classname
0147                             $markerType = Zend_Amf_Constants::AMF0_OBJECT;
0148                         }
0149                         break;
0150                     }
0151                     break;
0152                 case (null === $data):
0153                     $markerType = Zend_Amf_Constants::AMF0_NULL;
0154                     break;
0155                 case (is_array($data)):
0156                     // check if it is an associative array
0157                     $i = 0;
0158                     foreach (array_keys($data) as $key) {
0159                         // check if it contains non-integer keys
0160                         if (!is_numeric($key) || intval($key) != $key) {
0161                             $markerType = Zend_Amf_Constants::AMF0_OBJECT;
0162                             break;
0163                             // check if it is a sparse indexed array
0164                          } else if ($key != $i) {
0165                              $markerType = Zend_Amf_Constants::AMF0_MIXEDARRAY;
0166                              break;
0167                          }
0168                          $i++;
0169                     }
0170                     // Dealing with a standard numeric array
0171                     if(!$markerType){
0172                         $markerType = Zend_Amf_Constants::AMF0_ARRAY;
0173                         break;
0174                     }
0175                     break;
0176                 default:
0177                     // require_once 'Zend/Amf/Exception.php';
0178                     throw new Zend_Amf_Exception('Unsupported data type: ' . gettype($data));
0179             }
0180 
0181             $this->writeTypeMarker($data, $markerType);
0182         }
0183         return $this;
0184     }
0185 
0186     /**
0187      * Check if the given object is in the reference table, write the reference if it exists,
0188      * otherwise add the object to the reference table
0189      *
0190      * @param mixed  $object object reference to check for reference
0191      * @param string $markerType AMF type of the object to write
0192      * @param mixed  $objectByVal object to check for reference
0193      * @return Boolean true, if the reference was written, false otherwise
0194      */
0195     protected function writeObjectReference(&$object, $markerType, $objectByVal = false)
0196     {
0197         // Workaround for PHP5 with E_STRICT enabled complaining about "Only
0198         // variables should be passed by reference"
0199         if ((null === $object) && ($objectByVal !== false)) {
0200             $object = &$objectByVal;
0201         }
0202 
0203         if ($markerType == Zend_Amf_Constants::AMF0_OBJECT
0204             || $markerType == Zend_Amf_Constants::AMF0_MIXEDARRAY
0205             || $markerType == Zend_Amf_Constants::AMF0_ARRAY
0206             || $markerType == Zend_Amf_Constants::AMF0_TYPEDOBJECT
0207         ) {
0208             $ref = array_search($object, $this->_referenceObjects, true);
0209             //handle object reference
0210             if($ref !== false){
0211                 $this->writeTypeMarker($ref,Zend_Amf_Constants::AMF0_REFERENCE);
0212                 return true;
0213             }
0214 
0215             $this->_referenceObjects[] = $object;
0216         }
0217 
0218         return false;
0219     }
0220 
0221     /**
0222      * Write a PHP array with string or mixed keys.
0223      *
0224      * @param object $data
0225      * @return Zend_Amf_Parse_Amf0_Serializer
0226      */
0227     public function writeObject($object)
0228     {
0229         // Loop each element and write the name of the property.
0230         foreach ($object as $key => &$value) {
0231             // skip variables starting with an _ private transient
0232             if( $key[0] == "_") continue;
0233             $this->_stream->writeUTF($key);
0234             $this->writeTypeMarker($value);
0235         }
0236 
0237         // Write the end object flag
0238         $this->_stream->writeInt(0);
0239         $this->_stream->writeByte(Zend_Amf_Constants::AMF0_OBJECTTERM);
0240         return $this;
0241     }
0242 
0243     /**
0244      * Write a standard numeric array to the output stream. If a mixed array
0245      * is encountered call writeTypeMarker with mixed array.
0246      *
0247      * @param array $array
0248      * @return Zend_Amf_Parse_Amf0_Serializer
0249      */
0250     public function writeArray(&$array)
0251     {
0252         $length = count($array);
0253         if (!$length < 0) {
0254             // write the length of the array
0255             $this->_stream->writeLong(0);
0256         } else {
0257             // Write the length of the numeric array
0258             $this->_stream->writeLong($length);
0259             for ($i=0; $i<$length; $i++) {
0260                 $value = isset($array[$i]) ? $array[$i] : null;
0261                 $this->writeTypeMarker($value);
0262             }
0263         }
0264         return $this;
0265     }
0266 
0267     /**
0268      * Convert the DateTime into an AMF Date
0269      *
0270      * @param  DateTime|Zend_Date $data
0271      * @return Zend_Amf_Parse_Amf0_Serializer
0272      */
0273     public function writeDate($data)
0274     {
0275         if ($data instanceof DateTime) {
0276             $dateString = $data->format('U');
0277         } elseif ($data instanceof Zend_Date) {
0278             $dateString = $data->toString('U');
0279         } else {
0280             // require_once 'Zend/Amf/Exception.php';
0281             throw new Zend_Amf_Exception('Invalid date specified; must be a DateTime or Zend_Date object');
0282         }
0283         $dateString *= 1000;
0284 
0285         // Make the conversion and remove milliseconds.
0286         $this->_stream->writeDouble($dateString);
0287 
0288         // Flash does not respect timezone but requires it.
0289         $this->_stream->writeInt(0);
0290 
0291         return $this;
0292     }
0293 
0294     /**
0295      * Write a class mapped object to the output stream.
0296      *
0297      * @param  object $data
0298      * @return Zend_Amf_Parse_Amf0_Serializer
0299      */
0300     public function writeTypedObject($data)
0301     {
0302         $this->_stream->writeUTF($this->_className);
0303         $this->writeObject($data);
0304         return $this;
0305     }
0306 
0307     /**
0308      * Encountered and AMF3 Type Marker use AMF3 serializer. Once AMF3 is
0309      * encountered it will not return to AMf0.
0310      *
0311      * @param  string $data
0312      * @return Zend_Amf_Parse_Amf0_Serializer
0313      */
0314     public function writeAmf3TypeMarker(&$data)
0315     {
0316         // require_once 'Zend/Amf/Parse/Amf3/Serializer.php';
0317         $serializer = new Zend_Amf_Parse_Amf3_Serializer($this->_stream);
0318         $serializer->writeTypeMarker($data);
0319         return $this;
0320     }
0321 
0322     /**
0323      * Find if the class name is a class mapped name and return the
0324      * respective classname if it is.
0325      *
0326      * @param object $object
0327      * @return false|string $className
0328      */
0329     protected function getClassName($object)
0330     {
0331         // require_once 'Zend/Amf/Parse/TypeLoader.php';
0332         //Check to see if the object is a typed object and we need to change
0333         $className = '';
0334         switch (true) {
0335             // the return class mapped name back to actionscript class name.
0336             case Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object)):
0337                 $className = Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object));
0338                 break;
0339                 // Check to see if the user has defined an explicit Action Script type.
0340             case isset($object->_explicitType):
0341                 $className = $object->_explicitType;
0342                 break;
0343                 // Check if user has defined a method for accessing the Action Script type
0344             case method_exists($object, 'getASClassName'):
0345                 $className = $object->getASClassName();
0346                 break;
0347                 // No return class name is set make it a generic object
0348             case ($object instanceof stdClass):
0349                 $className = '';
0350                 break;
0351         // By default, use object's class name
0352             default:
0353         $className = get_class($object);
0354                 break;
0355         }
0356         if(!$className == '') {
0357             return $className;
0358         } else {
0359             return false;
0360         }
0361     }
0362 }