PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Amf/Parser/Amf0/Serializer.php

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