PageRenderTime 37ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/aerial/core/amfphp/core/amf/io/AMFBaseDeserializer.php

http://aerial-cms.googlecode.com/
PHP | 421 lines | 230 code | 46 blank | 145 comment | 40 complexity | f3ee747ae21731a07026f4b9ae040e55 MD5 | raw file
  1. <?php
  2. /**
  3. * AMFDeserializer takes the raw amf input stream and converts it PHP objects
  4. * representing the data.
  5. *
  6. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  7. * @copyright (c) 2003 amfphp.org
  8. * @package flashservices
  9. * @subpackage io
  10. * @version $Id$
  11. */
  12. /**
  13. * Required classes
  14. */
  15. require_once(AMFPHP_BASE . "shared/util/MessageBody.php");
  16. require_once(AMFPHP_BASE . "shared/util/MessageHeader.php");
  17. require_once(AMFPHP_BASE . "amf/util/DateWrapper.php");
  18. class AMFBaseDeserializer
  19. {
  20. /**
  21. * The raw data input
  22. *
  23. * @access private
  24. * @var string
  25. */
  26. var $raw_data;
  27. /**
  28. * The current seek cursor of the stream
  29. *
  30. * @access private
  31. * @var int
  32. */
  33. var $current_byte;
  34. /**
  35. * The length of the stream. Since this class is not actually using a stream
  36. * the entire content of the stream is passed in as the initial argument so the
  37. * length can be determined.
  38. *
  39. * @access private
  40. * @var int
  41. */
  42. var $content_length;
  43. /**
  44. * The number of headers in the packet.
  45. *
  46. * @access private
  47. * @var int
  48. */
  49. var $header_count;
  50. /**
  51. * The content of the packet headers
  52. *
  53. * @access private
  54. * @var string
  55. */
  56. var $headers;
  57. /**
  58. * The number of bodys in the packet.
  59. *
  60. * @access private
  61. * @var int
  62. */
  63. var $body_count;
  64. /**
  65. * The content of the body elements
  66. *
  67. * @access private
  68. * @var string
  69. */
  70. var $body;
  71. /**
  72. * The object to store the amf data.
  73. *
  74. * @access private
  75. * @var object
  76. */
  77. var $amfdata;
  78. /**
  79. * The instance of the amfinput stream object
  80. *
  81. * @access private
  82. * @var object
  83. */
  84. var $inputStream;
  85. /**
  86. * metaInfo
  87. */
  88. var $meta;
  89. var $storedStrings;
  90. var $storedObjects;
  91. var $storedDefinitions;
  92. var $amf0storedObjects;
  93. var $native;
  94. /**
  95. * Constructor method for the deserializer. Constructing the deserializer converts the input stream
  96. * content to a AMFObject.
  97. *
  98. * @param object $is The referenced input stream
  99. */
  100. function AMFBaseDeserializer($rd)
  101. {
  102. $this->isBigEndian = AMFPHP_BIG_ENDIAN;
  103. $this->current_byte = 0;
  104. $this->raw_data = $rd; // store the stream in this object
  105. $this->content_length = strlen($this->raw_data); // grab the total length of this stream
  106. $this->charsetHandler = new CharsetHandler('flashtophp');
  107. $this->storedStrings = array();
  108. $this->storedObjects = array();
  109. $this->storedDefinitions = array();
  110. $this->native = $GLOBALS['amfphp']['native'] && function_exists('amf_decode');
  111. $this->decodeFlags = (AMFPHP_BIG_ENDIAN*2) | 4;
  112. }
  113. /**
  114. * deserialize invokes this class to transform the raw data into valid object
  115. *
  116. * @param object $amfdata The object to put the deserialized data in
  117. */
  118. function deserialize (&$amfdata)
  119. {
  120. $time = microtime_float();
  121. $this->amfdata = &$amfdata;
  122. $this->readHeader(); // read the binary header
  123. $this->readBody(); // read the binary body
  124. if($this->decodeFlags & 1 == 1)
  125. {
  126. //AMF3 mode
  127. $GLOBALS['amfphp']['encoding'] = "amf3";
  128. }
  129. global $amfphp;
  130. $amfphp['decodeTime'] = microtime_float() - $time;
  131. }
  132. /**
  133. * returns the built AMFObject from the deserialization operation
  134. *
  135. * @return object The deserialized AMFObject
  136. */
  137. function getAMFObject()
  138. {
  139. return $this->amfdata;
  140. }
  141. /**
  142. * Decode callback is triggered when an object is encountered on decode
  143. */
  144. function decodeCallback($event, $arg)
  145. {
  146. if($event == 1) //Object
  147. {
  148. $type =$arg;
  149. return $this->mapClass($type);
  150. }
  151. else if($event == 2) //Object post decode
  152. {
  153. $obj = $arg;
  154. if(method_exists($obj, 'init'))
  155. {
  156. $obj->init();
  157. }
  158. return $obj;
  159. }
  160. else if($event == 3) //XML post-decode
  161. {
  162. return $arg;
  163. }
  164. else if($event == 4) //Serializable post-decode
  165. {
  166. if($type == 'flex.messaging.io.ArrayCollection' || $type == 'flex.messaging.io.ObjectProxy')
  167. {
  168. return;
  169. }
  170. else
  171. {
  172. trigger_error("Unable to read externalizable data type " . $type, E_USER_ERROR);
  173. return "error";
  174. }
  175. }
  176. else if($event == 5) //ByteArray post decode
  177. {
  178. return new ByteArray($arg);
  179. }
  180. }
  181. /**
  182. * readHeader converts that header section of the amf message into php obects.
  183. * Header information typically contains meta data about the message.
  184. */
  185. function readHeader()
  186. {
  187. $topByte = $this->readByte(); // ignore the first two bytes -- version or something
  188. $secondByte = $this->readByte(); //0 for Flash,
  189. //1 for FlashComm
  190. //Disable debug events for FlashComm
  191. $GLOBALS['amfphp']['isFlashComm'] = $secondByte == 1;
  192. //If firstByte != 0, then the AMF data is corrupted, for example the transmission
  193. //
  194. if(!($topByte == 0 || $topByte == 3))
  195. {
  196. trigger_error("Malformed AMF message, connection may have dropped");
  197. exit();
  198. }
  199. $this->header_count = $this->readInt(); // find the total number of header elements
  200. while ($this->header_count--)
  201. { // loop over all of the header elements
  202. $name = $this->readUTF();
  203. $required = $this->readByte() == 1; // find the must understand flag
  204. //$length = $this->readLong(); // grab the length of the header element
  205. $this->current_byte += 4; // grab the length of the header element
  206. if($this->native)
  207. {
  208. $content = amf_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
  209. }
  210. else
  211. {
  212. $type = $this->readByte(); // grab the type of the element
  213. $content = $this->readData($type); // turn the element into real data
  214. }
  215. $this->amfdata->addHeader(new MessageHeader($name, $required, $content)); // save the name/value into the headers array
  216. }
  217. }
  218. /**
  219. * readBody converts the payload of the message into php objects.
  220. */
  221. function readBody()
  222. {
  223. $this->body_count = $this->readInt(); // find the total number of body elements
  224. while ($this->body_count--)
  225. { // loop over all of the body elements
  226. $this->amf0storedObjects = array();
  227. $this->storedStrings = array();
  228. $this->storedObjects = array();
  229. $this->storedDefinitions = array();
  230. $target = $this->readUTF();
  231. $response = $this->readUTF(); // the response that the client understands
  232. //$length = $this->readLong(); // grab the length of the body element
  233. $this->current_byte += 4;
  234. if($this->native)
  235. $data = amf_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
  236. else
  237. {
  238. $type = $this->readByte(); // grab the type of the element
  239. $data = $this->readData($type); // turn the element into real data
  240. }
  241. $this->amfdata->addBody(new MessageBody($target, $response, $data)); // add the body element to the body object
  242. }
  243. }
  244. /********************************************************************************
  245. * This used to be in AmfInputStream
  246. ********************************************************************************
  247. /**
  248. * readByte grabs the next byte from the data stream and returns it.
  249. *
  250. * @return int The next byte converted into an integer
  251. */
  252. function readByte()
  253. {
  254. return ord($this->raw_data[$this->current_byte++]); // return the next byte
  255. }
  256. /**
  257. * readInt grabs the next 2 bytes and returns the next two bytes, shifted and combined
  258. * to produce the resulting integer
  259. *
  260. * @return int The resulting integer from the next 2 bytes
  261. */
  262. function readInt()
  263. {
  264. return ((ord($this->raw_data[$this->current_byte++]) << 8) |
  265. ord($this->raw_data[$this->current_byte++])); // read the next 2 bytes, shift and add
  266. }
  267. /**
  268. * readUTF first grabs the next 2 bytes which represent the string length.
  269. * Then it grabs the next (len) bytes of the resulting string.
  270. *
  271. * @return string The utf8 decoded string
  272. */
  273. function readUTF()
  274. {
  275. $length = $this->readInt(); // get the length of the string (1st 2 bytes)
  276. //BUg fix:: if string is empty skip ahead
  277. if($length == 0)
  278. {
  279. return "";
  280. }
  281. else
  282. {
  283. $val = substr($this->raw_data, $this->current_byte, $length); // grab the string
  284. $this->current_byte += $length; // move the seek head to the end of the string
  285. return $this->charsetHandler->transliterate($val); // return the string
  286. }
  287. }
  288. /**
  289. * readLong grabs the next 4 bytes shifts and combines them to produce an integer
  290. *
  291. * @return int The resulting integer from the next 4 bytes
  292. */
  293. function readLong()
  294. {
  295. return ((ord($this->raw_data[$this->current_byte++]) << 24) |
  296. (ord($this->raw_data[$this->current_byte++]) << 16) |
  297. (ord($this->raw_data[$this->current_byte++]) << 8) |
  298. ord($this->raw_data[$this->current_byte++])); // read the next 4 bytes, shift and add
  299. }
  300. /**
  301. * readDouble reads the floating point value from the bytes stream and properly orders
  302. * the bytes depending on the system architecture.
  303. *
  304. * @return float The floating point value of the next 8 bytes
  305. */
  306. function readDouble()
  307. {
  308. $bytes = substr($this->raw_data, $this->current_byte, 8);
  309. $this->current_byte += 8;
  310. if ($this->isBigEndian)
  311. {
  312. $bytes = strrev($bytes);
  313. }
  314. $zz = unpack("dflt", $bytes); // unpack the bytes
  315. return $zz['flt']; // return the number from the associative array
  316. }
  317. /**
  318. * readLongUTF first grabs the next 4 bytes which represent the string length.
  319. * Then it grabs the next (len) bytes of the resulting in the string
  320. *
  321. * @return string The utf8 decoded string
  322. */
  323. function readLongUTF()
  324. {
  325. $length = $this->readLong(); // get the length of the string (1st 4 bytes)
  326. $val = substr($this->raw_data, $this->current_byte, $length); // grab the string
  327. $this->current_byte += $length; // move the seek head to the end of the string
  328. return $this->charsetHandler->transliterate($val); // return the string
  329. }
  330. function mapClass($typeIdentifier)
  331. {
  332. //Check out if class exists
  333. if($typeIdentifier == "")
  334. {
  335. return NULL;
  336. }
  337. $class = NULL;
  338. switch($typeIdentifier)
  339. {
  340. case "flex.messaging.messages.CommandMessage":
  341. return new CommandMessage();
  342. break;
  343. case "flex.messaging.messages.RemotingMessage":
  344. return new RemotingMessage();
  345. break;
  346. default:
  347. $packageElements = explode(".", $typeIdentifier);
  348. array_shift($packageElements);
  349. $mappedClass = implode("/", $packageElements);
  350. $include = FALSE;
  351. if(file_exists($GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.php'))
  352. {
  353. $include = $GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.php';
  354. }
  355. elseif(file_exists($GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.class.php'))
  356. {
  357. $include = $GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.class.php';
  358. }
  359. if($include !== FALSE)
  360. {
  361. include_once($include);
  362. $lastPlace = strrpos('/' . $mappedClass, '/');
  363. $classname = substr($mappedClass, $lastPlace);
  364. if(class_exists($classname))
  365. {
  366. $class = new $classname;
  367. }
  368. }
  369. return $class; // return the object
  370. break;
  371. }
  372. }
  373. }
  374. ?>