PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/AMF/Parser/AMF0/Serializer.php

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