XML_Serializer
[ class tree: XML_Serializer ] [ index: XML_Serializer ] [ all elements ]

Source for file Unserializer.php

Documentation is available at Unserializer.php

  1. <?PHP
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stephan Schmidt <schst@php-tools.net>                       |
  17. // +----------------------------------------------------------------------+
  18. //
  19. //    $Id: Unserializer.php,v 1.30 2005/02/12 15:14:06 schst Exp $
  20.  
  21. /**
  22.  * uses PEAR error managemt
  23.  */
  24. require_once 'PEAR.php';
  25.  
  26. /**
  27.  * uses XML_Parser to unserialize document
  28.  */
  29. require_once 'XML/Parser.php';
  30.  
  31. /**
  32.  * error code for no serialization done
  33.  */
  34. define('XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION'151);
  35.  
  36. /**
  37.  * XML_Unserializer
  38.  *
  39.  * class to unserialize XML documents that have been created with
  40.  * XML_Serializer. To unserialize an XML document you have to add
  41.  * type hints to the XML_Serializer options.
  42.  *
  43.  * If no type hints are available, XML_Unserializer will guess how
  44.  * the tags should be treated, that means complex structures will be
  45.  * arrays and tags with only CData in them will be strings.
  46.  *
  47.  * <code>
  48.  * require_once 'XML/Unserializer.php';
  49.  *
  50.  * //  be careful to always use the ampersand in front of the new operator
  51.  * $unserializer = &new XML_Unserializer();
  52.  *
  53.  * $unserializer->unserialize($xml);
  54.  *
  55.  * $data = $unserializer->getUnserializedData();
  56.  * <code>
  57.  *
  58.  * Possible options for the Unserializer are:
  59.  *
  60.  * 1. complexTypes => array|object
  61.  * This is needed, when unserializing XML files w/o type hints. If set to
  62.  * 'array' (default), all nested tags will be arrays, if set to 'object'
  63.  * all nested tags will be objects, that means you have read access like:
  64.  *
  65.  * <code>
  66.  * require_once 'XML/Unserializer.php';
  67.  * $options = array('complexType' => 'object');
  68.  * $unserializer = &new XML_Unserializer($options);
  69.  *
  70.  * $unserializer->unserialize('http://pear.php.net/rss.php');
  71.  *
  72.  * $rss = $unserializer->getUnserializedData();
  73.  * echo $rss->channel->item[3]->title;
  74.  * </code>
  75.  *
  76.  * 2. keyAttribute
  77.  * This lets you specify an attribute inside your tags, that are used as key
  78.  * for associative arrays or object properties.
  79.  * You will need this if you have XML that looks like this:
  80.  *
  81.  * <users>
  82.  *   <user handle="schst">Stephan Schmidt</user>
  83.  *   <user handle="ssb">Stig S. Bakken</user>
  84.  * </users>
  85.  *
  86.  * Then you can use:
  87.  * <code>
  88.  * require_once 'XML/Unserializer.php';
  89.  * $options = array('keyAttribute' => 'handle');
  90.  * $unserializer = &new XML_Unserializer($options);
  91.  *
  92.  * $unserializer->unserialize($xml, false);
  93.  *
  94.  * $users = $unserializer->getUnserializedData();
  95.  * </code>
  96.  *
  97.  * @category XML
  98.  * @package  XML_Serializer
  99.  * @version  0.14.1
  100.  * @author   Stephan Schmidt <schst@php-tools.net>
  101.  * @uses     XML_Parser
  102.  */
  103. class XML_Unserializer extends PEAR
  104. {
  105.  
  106.    /**
  107.     * default options for the serialization
  108.     * @access private
  109.     * @var array $_defaultOptions 
  110.     */
  111.     var $_defaultOptions = array(
  112.                          'complexType'       => 'array',                // complex types will be converted to arrays, if no type hint is given
  113.                          'keyAttribute'      => '_originalKey',         // get array key/property name from this attribute
  114.                          'typeAttribute'     => '_type',                // get type from this attribute
  115.                          'classAttribute'    => '_class',               // get class from this attribute (if not given, use tag name)
  116.                          'tagAsClass'        => true,                   // use the tagname as the classname
  117.                          'defaultClass'      => 'stdClass',             // name of the class that is used to create objects
  118.                          'parseAttributes'   => false,                  // parse the attributes of the tag into an array
  119.                          'attributesArray'   => false,                  // parse them into sperate array (specify name of array here)
  120.                          'prependAttributes' => '',                     // prepend attribute names with this string
  121.                          'contentName'       => '_content',             // put cdata found in a tag that has been converted to a complex type in this key
  122.                          'tagMap'            => array(),                // use this to map tagnames
  123.                          'forceEnum'         => array(),                // these tags will always be an indexed array
  124.                          'encoding'          => null,                   // specify the encoding character of the document to parse
  125.                          'targetEncoding'    => null,                   // specify the target encoding
  126.                          'decodeFunction'    => null,                   // function used to decode data
  127.                          'returnResult'      => false                   // unserialize() returns the result of the unserialization instead of true
  128.                         );
  129.  
  130.    /**
  131.     * actual options for the serialization
  132.     * @access private
  133.     * @var array $options 
  134.     */
  135.     var $options = array();
  136.  
  137.    /**
  138.     * unserialized data
  139.     * @var string $_unserializedData 
  140.     */
  141.     var $_unserializedData = null;
  142.  
  143.    /**
  144.     * name of the root tag
  145.     * @var string $_root 
  146.     */
  147.     var $_root = null;
  148.  
  149.    /**
  150.     * stack for all data that is found
  151.     * @var array    $_dataStack 
  152.     */
  153.     var $_dataStack  =   array();
  154.  
  155.    /**
  156.     * stack for all values that are generated
  157.     * @var array    $_valStack 
  158.     */
  159.     var $_valStack  =   array();
  160.  
  161.    /**
  162.     * current tag depth
  163.     * @var int    $_depth 
  164.     */
  165.     var $_depth = 0;
  166.  
  167.    /**
  168.     * XML_Parser instance
  169.     *
  170.     * @access   private
  171.     * @var      object XML_Parser 
  172.     */
  173.     var $_parser = null;
  174.     
  175.    /**
  176.     * constructor
  177.     *
  178.     * @access   public
  179.     * @param    mixed   $options    array containing options for the serialization
  180.     */
  181.     function XML_Unserializer($options = null)
  182.     {
  183.         if (is_array($options)) {
  184.             $this->options array_merge($this->_defaultOptions$options);
  185.         else {
  186.             $this->options $this->_defaultOptions;
  187.         }
  188.     }
  189.  
  190.    /**
  191.     * return API version
  192.     *
  193.     * @access   public
  194.     * @static
  195.     * @return   string  $version API version
  196.     */
  197.     function apiVersion()
  198.     {
  199.         return '0.14';
  200.     }
  201.  
  202.    /**
  203.     * reset all options to default options
  204.     *
  205.     * @access   public
  206.     * @see      setOption(), XML_Unserializer(), setOptions()
  207.     */
  208.     function resetOptions()
  209.     {
  210.         $this->options $this->_defaultOptions;
  211.     }
  212.  
  213.    /**
  214.     * set an option
  215.     *
  216.     * You can use this method if you do not want to set all options in the constructor
  217.     *
  218.     * @access   public
  219.     * @see      resetOption(), XML_Unserializer(), setOptions()
  220.     */
  221.     function setOption($name$value)
  222.     {
  223.         $this->options[$name$value;
  224.     }
  225.  
  226.    /**
  227.     * sets several options at once
  228.     *
  229.     * You can use this method if you do not want to set all options in the constructor
  230.     *
  231.     * @access   public
  232.     * @see      resetOption(), XML_Unserializer(), setOption()
  233.     */
  234.     function setOptions($options)
  235.     {
  236.         $this->options array_merge($this->options$options);
  237.     }
  238.  
  239.    /**
  240.     * unserialize data
  241.     *
  242.     * @access   public
  243.     * @param    mixed    $data   data to unserialize (string, filename or resource)
  244.     * @param    boolean  $isFile string should be treated as a file
  245.     * @param    array    $options 
  246.     * @return   boolean  $success
  247.     */
  248.     function unserialize($data$isFile = false$options = null)
  249.     {
  250.         $this->_unserializedData = null;
  251.         $this->_root = null;
  252.  
  253.         // if options have been specified, use them instead
  254.         // of the previously defined ones
  255.         if (is_array($options)) {
  256.             $optionsBak $this->options;
  257.             if (isset($options['overrideOptions']&& $options['overrideOptions'== true{
  258.                 $this->options array_merge($this->_defaultOptions$options);
  259.             else {
  260.                 $this->options array_merge($this->options$options);
  261.             }
  262.         }
  263.         else {
  264.             $optionsBak = null;
  265.         }
  266.  
  267.         $this->_valStack = array();
  268.         $this->_dataStack = array();
  269.         $this->_depth = 0;
  270.  
  271.         $this->_createParser();
  272.         
  273.         if (is_string($data)) {
  274.             if ($isFile{
  275.                 $result $this->_parser->setInputFile($data);
  276.                 if (PEAR::isError($result)) {
  277.                     return $result;
  278.                 }
  279.                 $result $this->_parser->parse();
  280.             else {
  281.                 $result $this->_parser->parseString($data,true);
  282.             }
  283.         else {
  284.            $this->_parser->setInput($data);
  285.            $result $this->_parser->parse();
  286.         }
  287.  
  288.         if ($this->options['returnResult'=== true{
  289.             $return $this->_unserializedData;
  290.         else {
  291.             $return = true;
  292.         }
  293.  
  294.         if ($optionsBak !== null{
  295.             $this->options $optionsBak;
  296.         }
  297.  
  298.         if (PEAR::isError($result)) {
  299.             return $result;
  300.         }
  301.  
  302.         return $return;
  303.     }
  304.  
  305.    /**
  306.     * get the result of the serialization
  307.     *
  308.     * @access public
  309.     * @return string  $serializedData
  310.     */
  311.     function getUnserializedData()
  312.     {
  313.         if ($this->_root === null {
  314.             return  $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.'XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
  315.         }
  316.         return $this->_unserializedData;
  317.     }
  318.  
  319.    /**
  320.     * get the name of the root tag
  321.     *
  322.     * @access public
  323.     * @return string  $rootName
  324.     */
  325.     function getRootName()
  326.     {
  327.         if ($this->_root === null {
  328.             return  $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.'XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
  329.         }
  330.         return $this->_root;
  331.     }
  332.  
  333.    /**
  334.     * Start element handler for XML parser
  335.     *
  336.     * @access private
  337.     * @param  object $parser  XML parser object
  338.     * @param  string $element XML element
  339.     * @param  array  $attribs attributes of XML tag
  340.     * @return void 
  341.     */
  342.     function startHandler($parser$element$attribs)
  343.     {
  344.         if (isset($attribs[$this->options['typeAttribute']])) {
  345.             $type $attribs[$this->options['typeAttribute']];
  346.         else {
  347.             $type 'string';
  348.         }
  349.  
  350.         if ($this->options['decodeFunction'!== null{
  351.             $element call_user_func($this->options['decodeFunction']$element);
  352.             $attribs array_map($this->options['decodeFunction']$attribs);
  353.         }
  354.         
  355.         $this->_depth++;
  356.         $this->_dataStack[$this->_depth= null;
  357.  
  358.         $val = array(
  359.                      'name'         => $element,
  360.                      'value'        => null,
  361.                      'type'         => $type,
  362.                      'childrenKeys' => array(),
  363.                      'aggregKeys'   => array()
  364.                     );
  365.  
  366.         if ($this->options['parseAttributes'== true && (count($attribs> 0)) {
  367.             $val['children'= array();
  368.             $val['type']  $this->options['complexType'];
  369.             $val['class'$element;
  370.  
  371.             if ($this->options['attributesArray'!= false{
  372.                 $val['children'][$this->options['attributesArray']] $attribs;
  373.             else {
  374.                 foreach ($attribs as $attrib => $value{
  375.                     $val['children'][$this->options['prependAttributes'].$attrib$value;
  376.                 }
  377.             }
  378.         }
  379.  
  380.         $keyAttr = false;
  381.         
  382.         if (is_string($this->options['keyAttribute'])) {
  383.             $keyAttr $this->options['keyAttribute'];
  384.         elseif (is_array($this->options['keyAttribute'])) {
  385.             if (isset($this->options['keyAttribute'][$element])) {
  386.                 $keyAttr $this->options['keyAttribute'][$element];
  387.             elseif (isset($this->options['keyAttribute']['__default'])) {
  388.                 $keyAttr $this->options['keyAttribute']['__default'];
  389.             }
  390.         }
  391.         
  392.         if ($keyAttr !== false && isset($attribs[$keyAttr])) {
  393.             $val['name'$attribs[$keyAttr];
  394.         }
  395.  
  396.         if (isset($attribs[$this->options['classAttribute']])) {
  397.             $val['class'$attribs[$this->options['classAttribute']];
  398.         }
  399.  
  400.         array_push($this->_valStack$val);
  401.     }
  402.  
  403.    /**
  404.     * End element handler for XML parser
  405.     *
  406.     * @access private
  407.     * @param  object XML parser object
  408.     * @param  string 
  409.     * @return void 
  410.     */
  411.     function endHandler($parser$element)
  412.     {
  413.         $value array_pop($this->_valStack);
  414.         $data  trim($this->_dataStack[$this->_depth]);
  415.  
  416.         // adjust type of the value
  417.         switch(strtolower($value['type'])) {
  418.             /*
  419.              * unserialize an object
  420.              */
  421.             case 'object':
  422.                 if(isset($value['class'])) {
  423.                     $classname  $value['class'];
  424.                 else {
  425.                     $classname '';
  426.                 }
  427.                 if (is_array($this->options['tagMap']&& isset($this->options['tagMap'][$classname])) {
  428.                     $classname $this->options['tagMap'][$classname];
  429.                 }
  430.  
  431.                 // instantiate the class
  432.                 if ($this->options['tagAsClass'=== true && class_exists($classname)) {
  433.                     $value['value'&new $classname;
  434.                 else {
  435.                     $value['value'&new $this->options['defaultClass'];
  436.                 }
  437.                 if ($data !== ''{
  438.                     $value['children'][$this->options['contentName']] $data;
  439.                 }
  440.  
  441.                 // set properties
  442.                 foreach($value['children'as $prop => $propVal{
  443.                     // check whether there is a special method to set this property
  444.                     $setMethod 'set'.$prop;
  445.                     if (method_exists($value['value']$setMethod)) {
  446.                         call_user_func(array(&$value['value']$setMethod)$propVal);
  447.                     else {
  448.                         $value['value']->$prop $propVal;
  449.                     }
  450.                 }
  451.                 //  check for magic function
  452.                 if (method_exists($value['value']'__wakeup')) {
  453.                     $value['value']->__wakeup();
  454.                 }
  455.                 break;
  456.  
  457.             /*
  458.              * unserialize an array
  459.              */
  460.             case 'array':
  461.                 if ($data !== ''{
  462.                     $value['children'][$this->options['contentName']] $data;
  463.                 }
  464.                 if (isset($value['children'])) {
  465.                     $value['value'$value['children'];
  466.                 else {
  467.                     $value['value'= array();
  468.                 }
  469.                 break;
  470.  
  471.             /*
  472.              * unserialize a null value
  473.              */
  474.             case 'null':
  475.                 $data = null;
  476.                 break;
  477.  
  478.             /*
  479.              * unserialize a resource => this is not possible :-(
  480.              */
  481.             case 'resource':
  482.                 $value['value'$data;
  483.                 break;
  484.  
  485.             /*
  486.              * unserialize any scalar value
  487.              */
  488.             default:
  489.                 settype($data$value['type']);
  490.                 $value['value'$data;
  491.                 break;
  492.         }
  493.         $parent array_pop($this->_valStack);
  494.         if ($parent === null{
  495.             $this->_unserializedData &$value['value'];
  496.             $this->_root &$value['name'];
  497.             return true;
  498.         else {
  499.             // parent has to be an array
  500.             if (!isset($parent['children']|| !is_array($parent['children'])) {
  501.                 $parent['children'= array();
  502.                 if (!in_array($parent['type']array('array''object'))) {
  503.                     $parent['type'$this->options['complexType'];
  504.                     if ($this->options['complexType'== 'object'{
  505.                         $parent['class'$parent['name'];
  506.                     }
  507.                 }
  508.             }
  509.  
  510.             if (!empty($value['name'])) {
  511.                 // there already has been a tag with this name
  512.                 if (in_array($value['name']$parent['childrenKeys']|| in_array($value['name']$this->options['forceEnum'])) {
  513.                     // no aggregate has been created for this tag
  514.                     if (!in_array($value['name']$parent['aggregKeys'])) {
  515.                         if (isset($parent['children'][$value['name']])) {
  516.                             $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
  517.                         else {
  518.                             $parent['children'][$value['name']] = array();
  519.                         }
  520.                         array_push($parent['aggregKeys']$value['name']);
  521.                     }
  522.                     array_push($parent['children'][$value['name']]$value['value']);
  523.                 else {
  524.                     $parent['children'][$value['name']] &$value['value'];
  525.                     array_push($parent['childrenKeys']$value['name']);
  526.                 }
  527.             else {
  528.                 array_push($parent['children'],$value['value']);
  529.             }
  530.             array_push($this->_valStack$parent);
  531.         }
  532.  
  533.         $this->_depth--;
  534.     }
  535.  
  536.    /**
  537.     * Handler for character data
  538.     *
  539.     * @access private
  540.     * @param  object XML parser object
  541.     * @param  string CDATA
  542.     * @return void 
  543.     */
  544.     function cdataHandler($parser$cdata)
  545.     {
  546.         $this->_dataStack[$this->_depth.= $cdata;
  547.     }
  548.  
  549.    /**
  550.     * create the XML_Parser instance
  551.     *
  552.     * @access    private
  553.     */
  554.     function _createParser()
  555.     {
  556.         if (is_object($this->_parser)) {
  557.             $this->_parser->free();
  558.             unset($this->_parser);
  559.         }
  560.         $this->_parser &new XML_Parser($this->options['encoding']'event'$this->options['targetEncoding']);
  561.         $this->_parser->folding = false;
  562.         $this->_parser->setHandlerObj($this);
  563.         return true;
  564.     }
  565. }
  566. ?>

Documentation generated on Mon, 11 Mar 2019 14:23:49 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.