PageRenderTime 71ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/include/XML/Unserializer.php

https://github.com/radicaldesigns/amp
PHP | 856 lines | 399 code | 80 blank | 377 comment | 83 complexity | 3cb382e44de0e7979424fcd61b4b71e9 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, AGPL-1.0
  1. <?PHP
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * XML_Unserializer
  5. *
  6. * Parses any XML document into PHP data structures.
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * LICENSE: This source file is subject to version 3.0 of the PHP license
  11. * that is available through the world-wide-web at the following URI:
  12. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  13. * the PHP License and are unable to obtain it through the web, please
  14. * send a note to license@php.net so we can mail you a copy immediately.
  15. *
  16. * @category XML
  17. * @package XML_Serializer
  18. * @author Stephan Schmidt <schst@php.net>
  19. * @copyright 1997-2005 The PHP Group
  20. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  21. * @version CVS: $Id: Unserializer.php,v 1.39 2005/09/28 11:19:56 schst Exp $
  22. * @link http://pear.php.net/package/XML_Serializer
  23. * @see XML_Unserializer
  24. */
  25. /**
  26. * uses PEAR error managemt
  27. */
  28. require_once 'PEAR.php';
  29. /**
  30. * uses XML_Parser to unserialize document
  31. */
  32. require_once 'XML/Parser.php';
  33. /**
  34. * option: Convert nested tags to array or object
  35. *
  36. * Possible values:
  37. * - array
  38. * - object
  39. * - associative array to define this option per tag name
  40. */
  41. define('XML_UNSERIALIZER_OPTION_COMPLEXTYPE', 'complexType');
  42. /**
  43. * option: Name of the attribute that stores the original key
  44. *
  45. * Possible values:
  46. * - any string
  47. */
  48. define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute');
  49. /**
  50. * option: Name of the attribute that stores the type
  51. *
  52. * Possible values:
  53. * - any string
  54. */
  55. define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute');
  56. /**
  57. * option: Name of the attribute that stores the class name
  58. *
  59. * Possible values:
  60. * - any string
  61. */
  62. define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute');
  63. /**
  64. * option: Whether to use the tag name as a class name
  65. *
  66. * Possible values:
  67. * - true or false
  68. */
  69. define('XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME', 'tagAsClass');
  70. /**
  71. * option: Name of the default class
  72. *
  73. * Possible values:
  74. * - any string
  75. */
  76. define('XML_UNSERIALIZER_OPTION_DEFAULT_CLASS', 'defaultClass');
  77. /**
  78. * option: Whether to parse attributes
  79. *
  80. * Possible values:
  81. * - true or false
  82. */
  83. define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE', 'parseAttributes');
  84. /**
  85. * option: Key of the array to store attributes (if any)
  86. *
  87. * Possible values:
  88. * - any string
  89. * - false (disabled)
  90. */
  91. define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY', 'attributesArray');
  92. /**
  93. * option: string to prepend attribute name (if any)
  94. *
  95. * Possible values:
  96. * - any string
  97. * - false (disabled)
  98. */
  99. define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND', 'prependAttributes');
  100. /**
  101. * option: key to store the content, if XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE is used
  102. *
  103. * Possible values:
  104. * - any string
  105. */
  106. define('XML_UNSERIALIZER_OPTION_CONTENT_KEY', 'contentName');
  107. /**
  108. * option: map tag names
  109. *
  110. * Possible values:
  111. * - associative array
  112. */
  113. define('XML_UNSERIALIZER_OPTION_TAG_MAP', 'tagMap');
  114. /**
  115. * option: list of tags that will always be enumerated
  116. *
  117. * Possible values:
  118. * - indexed array
  119. */
  120. define('XML_UNSERIALIZER_OPTION_FORCE_ENUM', 'forceEnum');
  121. /**
  122. * option: Encoding of the XML document
  123. *
  124. * Possible values:
  125. * - UTF-8
  126. * - ISO-8859-1
  127. */
  128. define('XML_UNSERIALIZER_OPTION_ENCODING_SOURCE', 'encoding');
  129. /**
  130. * option: Desired target encoding of the data
  131. *
  132. * Possible values:
  133. * - UTF-8
  134. * - ISO-8859-1
  135. */
  136. define('XML_UNSERIALIZER_OPTION_ENCODING_TARGET', 'targetEncoding');
  137. /**
  138. * option: Callback that will be applied to textual data
  139. *
  140. * Possible values:
  141. * - any valid PHP callback
  142. */
  143. define('XML_UNSERIALIZER_OPTION_DECODE_FUNC', 'decodeFunction');
  144. /**
  145. * option: whether to return the result of the unserialization from unserialize()
  146. *
  147. * Possible values:
  148. * - true
  149. * - false (default)
  150. */
  151. define('XML_UNSERIALIZER_OPTION_RETURN_RESULT', 'returnResult');
  152. /**
  153. * option: set the whitespace behaviour
  154. *
  155. * Possible values:
  156. * - XML_UNSERIALIZER_WHITESPACE_KEEP
  157. * - XML_UNSERIALIZER_WHITESPACE_TRIM
  158. * - XML_UNSERIALIZER_WHITESPACE_NORMALIZE
  159. */
  160. define('XML_UNSERIALIZER_OPTION_WHITESPACE', 'whitespace');
  161. /**
  162. * Keep all whitespace
  163. */
  164. define('XML_UNSERIALIZER_WHITESPACE_KEEP', 'keep');
  165. /**
  166. * remove whitespace from start and end of the data
  167. */
  168. define('XML_UNSERIALIZER_WHITESPACE_TRIM', 'trim');
  169. /**
  170. * normalize whitespace
  171. */
  172. define('XML_UNSERIALIZER_WHITESPACE_NORMALIZE', 'normalize');
  173. /**
  174. * option: whether to ovverride all options that have been set before
  175. *
  176. * Possible values:
  177. * - true
  178. * - false (default)
  179. */
  180. define('XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS', 'overrideOptions');
  181. /**
  182. * option: list of tags, that will not be used as keys
  183. */
  184. define('XML_UNSERIALIZER_OPTION_IGNORE_KEYS', 'ignoreKeys');
  185. /**
  186. * option: whether to use type guessing for scalar values
  187. */
  188. define('XML_UNSERIALIZER_OPTION_GUESS_TYPES', 'guessTypes');
  189. /**
  190. * error code for no serialization done
  191. */
  192. define('XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION', 151);
  193. /**
  194. * XML_Unserializer
  195. *
  196. * class to unserialize XML documents that have been created with
  197. * XML_Serializer. To unserialize an XML document you have to add
  198. * type hints to the XML_Serializer options.
  199. *
  200. * If no type hints are available, XML_Unserializer will guess how
  201. * the tags should be treated, that means complex structures will be
  202. * arrays and tags with only CData in them will be strings.
  203. *
  204. * <code>
  205. * require_once 'XML/Unserializer.php';
  206. *
  207. * // be careful to always use the ampersand in front of the new operator
  208. * $unserializer = new XML_Unserializer();
  209. *
  210. * $unserializer->unserialize($xml);
  211. *
  212. * $data = $unserializer->getUnserializedData();
  213. * <code>
  214. *
  215. *
  216. * @category XML
  217. * @package XML_Serializer
  218. * @author Stephan Schmidt <schst@php.net>
  219. * @copyright 1997-2005 The PHP Group
  220. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  221. * @version Release: @package_version@
  222. * @link http://pear.php.net/package/XML_Serializer
  223. * @see XML_Serializer
  224. */
  225. class XML_Unserializer extends PEAR
  226. {
  227. /**
  228. * list of all available options
  229. *
  230. * @access private
  231. * @var array
  232. */
  233. var $_knownOptions = array(
  234. XML_UNSERIALIZER_OPTION_COMPLEXTYPE,
  235. XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY,
  236. XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE,
  237. XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS,
  238. XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME,
  239. XML_UNSERIALIZER_OPTION_DEFAULT_CLASS,
  240. XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE,
  241. XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY,
  242. XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND,
  243. XML_UNSERIALIZER_OPTION_CONTENT_KEY,
  244. XML_UNSERIALIZER_OPTION_TAG_MAP,
  245. XML_UNSERIALIZER_OPTION_FORCE_ENUM,
  246. XML_UNSERIALIZER_OPTION_ENCODING_SOURCE,
  247. XML_UNSERIALIZER_OPTION_ENCODING_TARGET,
  248. XML_UNSERIALIZER_OPTION_DECODE_FUNC,
  249. XML_UNSERIALIZER_OPTION_RETURN_RESULT,
  250. XML_UNSERIALIZER_OPTION_WHITESPACE,
  251. XML_UNSERIALIZER_OPTION_IGNORE_KEYS,
  252. XML_UNSERIALIZER_OPTION_GUESS_TYPES
  253. );
  254. /**
  255. * default options for the serialization
  256. *
  257. * @access private
  258. * @var array
  259. */
  260. var $_defaultOptions = array(
  261. XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array', // complex types will be converted to arrays, if no type hint is given
  262. XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey', // get array key/property name from this attribute
  263. XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type', // get type from this attribute
  264. XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class', // get class from this attribute (if not given, use tag name)
  265. XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME => true, // use the tagname as the classname
  266. XML_UNSERIALIZER_OPTION_DEFAULT_CLASS => 'stdClass', // name of the class that is used to create objects
  267. XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => false, // parse the attributes of the tag into an array
  268. XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY => false, // parse them into sperate array (specify name of array here)
  269. XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND => '', // prepend attribute names with this string
  270. XML_UNSERIALIZER_OPTION_CONTENT_KEY => '_content', // put cdata found in a tag that has been converted to a complex type in this key
  271. XML_UNSERIALIZER_OPTION_TAG_MAP => array(), // use this to map tagnames
  272. XML_UNSERIALIZER_OPTION_FORCE_ENUM => array(), // these tags will always be an indexed array
  273. XML_UNSERIALIZER_OPTION_ENCODING_SOURCE => null, // specify the encoding character of the document to parse
  274. XML_UNSERIALIZER_OPTION_ENCODING_TARGET => null, // specify the target encoding
  275. XML_UNSERIALIZER_OPTION_DECODE_FUNC => null, // function used to decode data
  276. XML_UNSERIALIZER_OPTION_RETURN_RESULT => false, // unserialize() returns the result of the unserialization instead of true
  277. XML_UNSERIALIZER_OPTION_WHITESPACE => XML_UNSERIALIZER_WHITESPACE_TRIM, // remove whitespace around data
  278. XML_UNSERIALIZER_OPTION_IGNORE_KEYS => array(), // List of tags that will automatically be added to the parent, instead of adding a new key
  279. XML_UNSERIALIZER_OPTION_GUESS_TYPES => false // Whether to use type guessing
  280. );
  281. /**
  282. * current options for the serialization
  283. *
  284. * @access public
  285. * @var array
  286. */
  287. var $options = array();
  288. /**
  289. * unserialized data
  290. *
  291. * @access private
  292. * @var string
  293. */
  294. var $_unserializedData = null;
  295. /**
  296. * name of the root tag
  297. *
  298. * @access private
  299. * @var string
  300. */
  301. var $_root = null;
  302. /**
  303. * stack for all data that is found
  304. *
  305. * @access private
  306. * @var array
  307. */
  308. var $_dataStack = array();
  309. /**
  310. * stack for all values that are generated
  311. *
  312. * @access private
  313. * @var array
  314. */
  315. var $_valStack = array();
  316. /**
  317. * current tag depth
  318. *
  319. * @access private
  320. * @var int
  321. */
  322. var $_depth = 0;
  323. /**
  324. * XML_Parser instance
  325. *
  326. * @access private
  327. * @var object XML_Parser
  328. */
  329. var $_parser = null;
  330. /**
  331. * constructor
  332. *
  333. * @access public
  334. * @param mixed $options array containing options for the unserialization
  335. */
  336. function XML_Unserializer($options = null)
  337. {
  338. if (is_array($options)) {
  339. $this->options = array_merge($this->_defaultOptions, $options);
  340. } else {
  341. $this->options = $this->_defaultOptions;
  342. }
  343. }
  344. /**
  345. * return API version
  346. *
  347. * @access public
  348. * @static
  349. * @return string $version API version
  350. */
  351. function apiVersion()
  352. {
  353. return '@package_version@';
  354. }
  355. /**
  356. * reset all options to default options
  357. *
  358. * @access public
  359. * @see setOption(), XML_Unserializer(), setOptions()
  360. */
  361. function resetOptions()
  362. {
  363. $this->options = $this->_defaultOptions;
  364. }
  365. /**
  366. * set an option
  367. *
  368. * You can use this method if you do not want to set all options in the constructor
  369. *
  370. * @access public
  371. * @see resetOption(), XML_Unserializer(), setOptions()
  372. */
  373. function setOption($name, $value)
  374. {
  375. $this->options[$name] = $value;
  376. }
  377. /**
  378. * sets several options at once
  379. *
  380. * You can use this method if you do not want to set all options in the constructor
  381. *
  382. * @access public
  383. * @see resetOption(), XML_Unserializer(), setOption()
  384. */
  385. function setOptions($options)
  386. {
  387. $this->options = array_merge($this->options, $options);
  388. }
  389. /**
  390. * unserialize data
  391. *
  392. * @access public
  393. * @param mixed $data data to unserialize (string, filename or resource)
  394. * @param boolean $isFile data should be treated as a file
  395. * @param array $options options that will override the global options for this call
  396. * @return boolean $success
  397. */
  398. function unserialize($data, $isFile = false, $options = null)
  399. {
  400. $this->_unserializedData = null;
  401. $this->_root = null;
  402. // if options have been specified, use them instead
  403. // of the previously defined ones
  404. if (is_array($options)) {
  405. $optionsBak = $this->options;
  406. if (isset($options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS]) && $options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS] == true) {
  407. $this->options = array_merge($this->_defaultOptions, $options);
  408. } else {
  409. $this->options = array_merge($this->options, $options);
  410. }
  411. } else {
  412. $optionsBak = null;
  413. }
  414. $this->_valStack = array();
  415. $this->_dataStack = array();
  416. $this->_depth = 0;
  417. $this->_createParser();
  418. if (is_string($data)) {
  419. if ($isFile) {
  420. $result = $this->_parser->setInputFile($data);
  421. if (PEAR::isError($result)) {
  422. return $result;
  423. }
  424. $result = $this->_parser->parse();
  425. } else {
  426. $result = $this->_parser->parseString($data,true);
  427. }
  428. } else {
  429. $this->_parser->setInput($data);
  430. $result = $this->_parser->parse();
  431. }
  432. if ($this->options[XML_UNSERIALIZER_OPTION_RETURN_RESULT] === true) {
  433. $return = $this->_unserializedData;
  434. } else {
  435. $return = true;
  436. }
  437. if ($optionsBak !== null) {
  438. $this->options = $optionsBak;
  439. }
  440. if (PEAR::isError($result)) {
  441. return $result;
  442. }
  443. return $return;
  444. }
  445. /**
  446. * get the result of the serialization
  447. *
  448. * @access public
  449. * @return string $serializedData
  450. */
  451. function getUnserializedData()
  452. {
  453. if ($this->_root === null) {
  454. return $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.', XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
  455. }
  456. return $this->_unserializedData;
  457. }
  458. /**
  459. * get the name of the root tag
  460. *
  461. * @access public
  462. * @return string $rootName
  463. */
  464. function getRootName()
  465. {
  466. if ($this->_root === null) {
  467. return $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.', XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
  468. }
  469. return $this->_root;
  470. }
  471. /**
  472. * Start element handler for XML parser
  473. *
  474. * @access private
  475. * @param object $parser XML parser object
  476. * @param string $element XML element
  477. * @param array $attribs attributes of XML tag
  478. * @return void
  479. */
  480. function startHandler($parser, $element, $attribs)
  481. {
  482. if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]])) {
  483. $type = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]];
  484. $guessType = false;
  485. } else {
  486. $type = 'string';
  487. if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
  488. $guessType = true;
  489. } else {
  490. $guessType = false;
  491. }
  492. }
  493. if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
  494. $attribs = array_map($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $attribs);
  495. }
  496. $this->_depth++;
  497. $this->_dataStack[$this->_depth] = null;
  498. if (is_array($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP]) && isset($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element])) {
  499. $element = $this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element];
  500. }
  501. $val = array(
  502. 'name' => $element,
  503. 'value' => null,
  504. 'type' => $type,
  505. 'guessType' => $guessType,
  506. 'childrenKeys' => array(),
  507. 'aggregKeys' => array()
  508. );
  509. if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE] == true && (count($attribs) > 0)) {
  510. $val['children'] = array();
  511. $val['type'] = $this->_getComplexType($element);
  512. $val['class'] = $element;
  513. if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
  514. $attribs = $this->_guessAndSetTypes($attribs);
  515. }
  516. if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY] != false) {
  517. $val['children'][$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY]] = $attribs;
  518. } else {
  519. foreach ($attribs as $attrib => $value) {
  520. $val['children'][$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND].$attrib] = $value;
  521. }
  522. }
  523. }
  524. $keyAttr = false;
  525. if (is_string($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
  526. $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY];
  527. } elseif (is_array($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
  528. if (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element])) {
  529. $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element];
  530. } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['#default'])) {
  531. $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['#default'];
  532. } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['__default'])) {
  533. // keep this for BC
  534. $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['__default'];
  535. }
  536. }
  537. if ($keyAttr !== false && isset($attribs[$keyAttr])) {
  538. $val['name'] = $attribs[$keyAttr];
  539. }
  540. if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]])) {
  541. $val['class'] = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]];
  542. }
  543. array_push($this->_valStack, $val);
  544. }
  545. /**
  546. * Try to guess the type of several values and
  547. * set them accordingly
  548. *
  549. * @access private
  550. * @param array array, containing the values
  551. * @return array array, containing the values with their correct types
  552. */
  553. function _guessAndSetTypes($array)
  554. {
  555. foreach ($array as $key => $value) {
  556. $array[$key] = $this->_guessAndSetType($value);
  557. }
  558. return $array;
  559. }
  560. /**
  561. * Try to guess the type of a value and
  562. * set it accordingly
  563. *
  564. * @access private
  565. * @param string character data
  566. * @return mixed value with the best matching type
  567. */
  568. function _guessAndSetType($value)
  569. {
  570. if ($value === 'true') {
  571. return true;
  572. }
  573. if ($value === 'false') {
  574. return false;
  575. }
  576. if ($value === 'NULL') {
  577. return null;
  578. }
  579. if (preg_match('/^[-+]?[0-9]{1,}$/', $value)) {
  580. return intval($value);
  581. }
  582. if (preg_match('/^[-+]?[0-9]{1,}\.[0-9]{1,}$/', $value)) {
  583. return doubleval($value);
  584. }
  585. return (string)$value;
  586. }
  587. /**
  588. * End element handler for XML parser
  589. *
  590. * @access private
  591. * @param object XML parser object
  592. * @param string
  593. * @return void
  594. */
  595. function endHandler($parser, $element)
  596. {
  597. $value = array_pop($this->_valStack);
  598. switch ($this->options[XML_UNSERIALIZER_OPTION_WHITESPACE]) {
  599. case XML_UNSERIALIZER_WHITESPACE_KEEP:
  600. $data = $this->_dataStack[$this->_depth];
  601. break;
  602. case XML_UNSERIALIZER_WHITESPACE_NORMALIZE:
  603. $data = trim(preg_replace('/\s\s+/m', ' ', $this->_dataStack[$this->_depth]));
  604. break;
  605. case XML_UNSERIALIZER_WHITESPACE_TRIM:
  606. default:
  607. $data = trim($this->_dataStack[$this->_depth]);
  608. break;
  609. }
  610. // adjust type of the value
  611. switch(strtolower($value['type'])) {
  612. // unserialize an object
  613. case 'object':
  614. if (isset($value['class'])) {
  615. $classname = $value['class'];
  616. } else {
  617. $classname = '';
  618. }
  619. // instantiate the class
  620. if ($this->options[XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME] === true && class_exists($classname)) {
  621. $value['value'] = new $classname;
  622. } else {
  623. $value['value'] = new $this->options[XML_UNSERIALIZER_OPTION_DEFAULT_CLASS];
  624. }
  625. if (trim($data) !== '') {
  626. if ($value['guessType'] === true) {
  627. $data = $this->_guessAndSetType($data);
  628. }
  629. $value['children'][$this->options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
  630. }
  631. // set properties
  632. foreach ($value['children'] as $prop => $propVal) {
  633. // check whether there is a special method to set this property
  634. $setMethod = 'set'.$prop;
  635. if (method_exists($value['value'], $setMethod)) {
  636. call_user_func(array(&$value['value'], $setMethod), $propVal);
  637. } else {
  638. $value['value']->$prop = $propVal;
  639. }
  640. }
  641. // check for magic function
  642. if (method_exists($value['value'], '__wakeup')) {
  643. $value['value']->__wakeup();
  644. }
  645. break;
  646. // unserialize an array
  647. case 'array':
  648. if (trim($data) !== '') {
  649. if ($value['guessType'] === true) {
  650. $data = $this->_guessAndSetType($data);
  651. }
  652. $value['children'][$this->options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
  653. }
  654. if (isset($value['children'])) {
  655. $value['value'] = $value['children'];
  656. } else {
  657. $value['value'] = array();
  658. }
  659. break;
  660. // unserialize a null value
  661. case 'null':
  662. $data = null;
  663. break;
  664. // unserialize a resource => this is not possible :-(
  665. case 'resource':
  666. $value['value'] = $data;
  667. break;
  668. // unserialize any scalar value
  669. default:
  670. if ($value['guessType'] === true) {
  671. $data = $this->_guessAndSetType($data);
  672. } else {
  673. settype($data, $value['type']);
  674. }
  675. $value['value'] = $data;
  676. break;
  677. }
  678. $parent = array_pop($this->_valStack);
  679. if ($parent === null) {
  680. $this->_unserializedData = &$value['value'];
  681. $this->_root = &$value['name'];
  682. return true;
  683. } else {
  684. // parent has to be an array
  685. if (!isset($parent['children']) || !is_array($parent['children'])) {
  686. $parent['children'] = array();
  687. if (!in_array($parent['type'], array('array', 'object'))) {
  688. $parent['type'] = $this->_getComplexType($parent['name']);
  689. if ($parent['type'] == 'object') {
  690. $parent['class'] = $parent['name'];
  691. }
  692. }
  693. }
  694. if (in_array($element, $this->options[XML_UNSERIALIZER_OPTION_IGNORE_KEYS])) {
  695. $ignoreKey = true;
  696. } else {
  697. $ignoreKey = false;
  698. }
  699. if (!empty($value['name']) && $ignoreKey === false) {
  700. // there already has been a tag with this name
  701. if (in_array($value['name'], $parent['childrenKeys']) || in_array($value['name'], $this->options[XML_UNSERIALIZER_OPTION_FORCE_ENUM])) {
  702. // no aggregate has been created for this tag
  703. if (!in_array($value['name'], $parent['aggregKeys'])) {
  704. if (isset($parent['children'][$value['name']])) {
  705. $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
  706. } else {
  707. $parent['children'][$value['name']] = array();
  708. }
  709. array_push($parent['aggregKeys'], $value['name']);
  710. }
  711. array_push($parent['children'][$value['name']], $value['value']);
  712. } else {
  713. $parent['children'][$value['name']] = &$value['value'];
  714. array_push($parent['childrenKeys'], $value['name']);
  715. }
  716. } else {
  717. array_push($parent['children'], $value['value']);
  718. }
  719. array_push($this->_valStack, $parent);
  720. }
  721. $this->_depth--;
  722. }
  723. /**
  724. * Handler for character data
  725. *
  726. * @access private
  727. * @param object XML parser object
  728. * @param string CDATA
  729. * @return void
  730. */
  731. function cdataHandler($parser, $cdata)
  732. {
  733. if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
  734. $cdata = call_user_func($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $cdata);
  735. }
  736. $this->_dataStack[$this->_depth] .= $cdata;
  737. }
  738. /**
  739. * get the complex type, that should be used for a specified tag
  740. *
  741. * @access private
  742. * @param string name of the tag
  743. * @return string complex type ('array' or 'object')
  744. */
  745. function _getComplexType($tagname)
  746. {
  747. if (is_string($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE])) {
  748. return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE];
  749. }
  750. if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname])) {
  751. return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname];
  752. }
  753. if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'])) {
  754. return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'];
  755. }
  756. return 'array';
  757. }
  758. /**
  759. * create the XML_Parser instance
  760. *
  761. * @access private
  762. * @return boolean
  763. */
  764. function _createParser()
  765. {
  766. if (is_object($this->_parser)) {
  767. $this->_parser->free();
  768. unset($this->_parser);
  769. }
  770. $this->_parser = new XML_Parser($this->options[XML_UNSERIALIZER_OPTION_ENCODING_SOURCE], 'event', $this->options[XML_UNSERIALIZER_OPTION_ENCODING_TARGET]);
  771. $this->_parser->folding = false;
  772. $this->_parser->setHandlerObj($this);
  773. return true;
  774. }
  775. }
  776. ?>