Вход Регистрация
Файл: ips_kernel/classXmlRpc.php
Строк: 596
<?php

/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.3.3
 * XML-RPC Server: Send, receive and process XML-RPC requests
 * Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
 * </pre>
 *
 * @author         $Author: bfarber $
 * @copyright    (c) 2001 - 2009 Invision Power Services, Inc.
 * @license        http://www.invisionpower.com/company/standards.php#license
 * @package        IP.Board
 * @subpackage    Kernel
 * @link        http://www.invisionpower.com
 * @since        6th January 2006
 * @version        $Revision: 10721 $
 *
 *
 * Example Usage:
 * <code>
 * SENDING XML-RPC Request
 * (Optional)
 * $xmlrpc->map_type_to_key['key']  = 'string';
 * $xmlrpc->map_type_to_key['key2'] = 'base64';
 * $return = $xmlrpc->sendXmlRpc( 'http://domain.com/xml-rpc_server.php', 'methodNameHere', array( 'key' => 'value', 'key2' => 'value2' ) );
 * if ( $xmlrpc->errors )
 * {
 *     print_r( $xmlrpc->errors );
 * }
 * 
 * Decoding XML-RPC
 * $xmlrpc->decode( $raw_xmlrpc_text );
 * 
 * print_r( $xmlrpc->xmlrpc_params );
 * RETURN
 * $xmlrpc->returnTrue();
 * </code>
 *
 */
 
class classXmlRpc
{
    
/**
     * XML header - this is prepended to every request
     *
     * @var         string
     */
    
public $header            = "";
    
    
/**
     * Character-set encoding to use
     *
     * @var         string
     */
    
public $doc_type        = 'UTF-8';
    
    
/**
     * Array of error messages
     *
     * @var         array
     */
    
public $errors            = array();
    
    
/**
     * Variable types (do not change - the specification only accounts for certain variable types)
     *
     * @var         array
     */
    
public $var_types        = array('string', 'int', 'i4', 'double', 'dateTime.iso8601', 'base64', 'boolean');
    
    
/**
     * Method to call
     *
     * @var        string
     */
    
public $xmlrpc_method_call    = '';

    
/**
     * Extracted xmlrpc params
     *
     * @var        array
     */
    
public $xmlrpc_params    = array();
    
    
/**
     * Optionally map types to key
     *
     * @var         array
     */
    
public $map_type_to_key    = array();
    
    
/**#@+
     * HTTP-authentication username and password
     *
     * @var         string
     */
    
public $auth_user         = '';
    public 
$auth_pass         = '';
    
/**#@-*/
    
    /**
     * Decode an XML RPC document
     *
     * @param    string        XML-RPC data
     * @return    @e string
     */
    
public function decodeXmlRpc( $_xml )
    {
        
$xml_parser    = new xmlRpcParser();
        
$data        = $xml_parser->parse( $_xml );
    
        if ( isset( 
$data['methodResponse']['fault'] ) )
        {
            
$tmp            = $this->adjustValue( $data['methodResponse']['fault']['value'] );
            
$this->errors[] = $tmp['faultString'];
        }
        
        
$this->xmlrpc_params      = $this->getParams( $data );
        
$this->xmlrpc_method_call = $this->getMethodName( $data );
        
        
//-----------------------------------------
        // Debug?
        //-----------------------------------------
        
        
if ( IPS_XML_RPC_DEBUG_ON )
        {
            
$this->addDebug( "DECODING XML data: " . $_xml );
            
$this->addDebug( "DECODE RESULT XML data: " . var_export( $data, TRUE ) );
        }

        return 
$data;
    }
    
    
/**
     * Adjust value of parameter and return it properly cast
     *
     * @param    string        Curernt node
     * @return    @e mixed
     */
    
public function & adjustValue( &$current_node )
    {
        if ( 
is_array( $current_node ) )
        {
            if ( isset(
$current_node['array']) )
            {
                if ( ! 
is_array($current_node['array']['data']) )
                {
                    
$temp = array();
                }
                else
                {
                    
$temp = &$current_node['array']['data']['value'];
    
                    if ( 
is_array($temp) and array_key_exists(0, $temp) )
                    {
                        
$count = count($temp);
    
                        for( 
$n = 0 ; $n < $count ; $n++ )
                        {
                            
$temp2[$n] = & $this->adjustValue($temp[$n]);
                        }
    
                        
$temp = &$temp2;
    
                    }
                    else
                    {
                        
$temp2 = & $this->adjustValue($temp);
                        
$temp = array(&$temp2);
                    }
                }
            }
            elseif ( isset(
$current_node['struct']) )
            {
                if ( ! 
is_array($current_node['struct']) )
                {
                    return array();
                }
                else
                {
                    
$temp = &$current_node['struct']['member'];
    
                    if ( 
is_array($temp) and array_key_exists(0, $temp) )
                    {
                        
$count = count($temp);
    
                        for( 
$n = 0 ; $n < $count ; $n++ )
                        {
                            
$temp2[$temp[$n]['name']] = & $this->adjustValue($temp[$n]['value']);
                        }
                    }
                    else
                    {
                        
$temp2[$temp['name']] = & $this->adjustValue($temp['value']);
                    }
                    
$temp = &$temp2;
                }
            }
            else
            {
                
$got_it = false;
    
                foreach( 
$this->var_types as $type )
                {
                    if ( 
array_key_exists($type, $current_node) )
                    {
                        
$temp   = &$current_node[$type];
                        
$got_it = true;
                        break;
                    }
                }
    
                if ( ! 
$got_it )
                {
                    
$type = 'string';
                }
    
                switch (
$type)
                {
                    case 
'int':
                     case 
'i4':
                    case 
'integer':
                    case 
'integar':
                        
$temp = (int)    $temp;
                        break;
                    case 
'string':
                        
$temp = (string) $temp;
                        break;
                    case 
'double':
                        
$temp = (double) $temp; 
                        break;
                    case 
'boolean':
                        
$temp = (bool)   $temp;
                        break;
                    case 
'base64':
                        
$temp = base64_decode(trim($temp));
                        break;
                }
            }
        }
        else
        {
            
$temp = (string) $current_node;
        }
    
        return 
$temp;
    }
    
    
/**
     * Get the params from the XML RPC return
     *
     * @param    array        Request data
     * @return    @e array
     */
    
public function getParams( $request )
    {
        if ( isset( 
$request['methodCall']['params'] ) AND is_array( $request['methodCall']['params'] ) )
        {
            
$temp = & $request['methodCall']['params']['param'];
        }
        else if ( isset( 
$request['methodResponse']['params'] ) AND is_array( $request['methodResponse']['params'] ) )
        {
            
$temp = & $request['methodResponse']['params']['param'];
        }
        else
        {
            return array();
        }
       
        if ( 
is_array( $temp ) and array_key_exists( 0, $temp ) )
        {
            
$count = count($temp);

            for( 
$n = 0 ; $n < $count ; $n++)
            {
                
$temp2[$n] = & $this->adjustValue($temp[$n]['value']);
            }
        }
        else
        {
            
$temp2[0] = & $this->adjustValue($temp['value']);
        }

        
$temp = &$temp2;

        return 
$temp;
    }
    
    
/**
     * Get RPC method name
     *
     * @param    array        Request params
     * @return    @e string
     */
    
public function getMethodName( $request )
    {
        return isset( 
$request['methodCall']['methodName'] ) ? $request['methodCall']['methodName'] : '';
    }
    
    
/**
     * Create and send an XML document, returning boolean if there is a problem, or the decoded response
     *
     * @param    string        URL to send XML-RPC data to
     * @param    string        Method name to request
     * @param    array       Array of fields to send (must be in key => value pairings)
     * @return    @e mixed
     */
    
public function sendXmlRpc( $url, $method_name='', $data_array=array() )
    {
        
//-----------------------------------------
        // Build RPC request
        //-----------------------------------------
        
        
$xmldata = $this->buildDocument( $data_array, $method_name );
        
        if ( 
$xmldata )
        {
            
//-----------------------------------------
            // Debug?
            //-----------------------------------------
            
            
if ( IPS_XML_RPC_DEBUG_ON )
            {
                
$this->addDebug( "SENDING XML data: " . $xmldata );
            }
            
            
//-----------------------------------------
            // Continue
            //-----------------------------------------
            
            
return $this->post( $url, $xmldata );
        }
        else
        {
            return 
false;
        }
    }
    
    
/**
     * Prints a document with a single value and exits
     *
     * @param    string        Value
     * @return    @e void
     */
    
public function returnValue( $value )
    {
        
$this->generateHeader();
        
        
$to_print = $this->header."<methodResponse>
            <params>
                <param>
                    <value>
{$value}</value>
                </param>
            </params>
           </methodResponse>"
;

        @
header( "Connection: close" );
        @
header( "Content-length: " . strlen($to_print) );
        @
header( "Content-type: text/xml" );
        @
header( "Date: " . date("r") );
        print 
$to_print;
        
        
$this->addDebug( "ReturnValue: {$to_print}" );

        exit();
    }

    
/**
     * Creates an XML-RPC complex document
     *
     * @param    array       Array of fields to send (must be in key => value pairings)
     * @param    string        Method name (optional)
     * @return    @e string
     */
    
public function buildDocument( $data_array, $method_name='' )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$xmldata  = "";
        
$root_tag = 'methodCall';
        
        
//-----------------------------------------
        // Test
        //-----------------------------------------
        
        
if ( ! is_array( $data_array ) or ! count( $data_array ) )
        {
            return 
false;
        }
        
        if ( ! 
$method_name )
        {
            
$root_tag = 'methodResponse';
        }
        
        
$this->generateHeader();
        
        
$xmldata  = $this->header . "n";
        
$xmldata .= "<".$root_tag.">n";
        
        if ( 
$method_name )
        {
            
$xmldata .= "t<methodName>".$method_name."</methodName>n";
        }
        
        
$xmldata .= "t<params>n";
        
$xmldata .= "tt<param>n";
        
$xmldata .= "ttt<value>n";

        if ( isset( 
$data_array[0] ) AND is_array( $data_array[0] ) )
        {
             
$xmldata .= "ttt<array>n";
            
$xmldata .= "tttt<data>n";

            foreach( 
$data_array as $k => $v )
            {
                
$xmldata .= "ttttt<value>n";
                
$xmldata .= "tttttt<struct>n";
                
                foreach( 
$v as $k2 => $v2 )
                {
                    
$_type = $this->map_type_to_key[ $k2 ] ? $this->map_type_to_key[ $k2 ] : $this->getStringType( $v2 );

                    
$xmldata .= "ttttttt<member>n";
                    
$xmldata .= "tttttttt<name>".$k2."</name>n";
                    
                    if ( 
strpos( $v2, '>' ) !== false OR strpos( $v2, '<' ) !== false OR strpos( $v2, '&' ) !== false )
                    {
                        
$xmldata .= "tttttttt<value><base64>" . base64_encode($v2) . "</base64></value>n";
                    }
                    else
                    {
                        
$xmldata .= "tttttttt<value><".$_type.">" . htmlspecialchars($v2) . "</".$_type."></value>n";
                    }

                    
$xmldata .= "ttttttt</member>n";
                }
                
                
$xmldata .= "tttttt</struct>n";
                
$xmldata .= "ttttt</value>n";
            }

            
$xmldata .= "tttt</data>n";
            
$xmldata .= "ttt</array>n";
        }
        else
        {
            
$xmldata .= "ttt<struct>n";

            foreach( 
$data_array as $k => $v )
            {
                if ( 
is_array( $v ) )
                {
                    
$xmldata .= $this->_buildDocumentRecurse( "", $k, $v, 4 );
                }
                else
                {
                    
$_type = isset( $this->map_type_to_key[ $k ] ) ? $this->map_type_to_key[ $k ] : $this->getStringType( $v );

                    
$xmldata .= "tttt<member>n";
                    
$xmldata .= "ttttt<name>".$k."</name>n";
                    
                    if ( 
strpos( $v, '>' ) !== false OR strpos( $v, '<' ) !== false OR strpos( $v, '&' ) !== false )
                    {
                        
$xmldata .= "tttttttt<value><base64>" . base64_encode($v) . "</base64></value>n";
                    }
                    else
                    {
                        
$xmldata .= "ttttt<value><".$_type.">" . htmlspecialchars($v) . "</".$_type."></value>n";
                    }
                    
                    
$xmldata .= "tttt</member>n";
                }
            }

            
$xmldata .= "ttt</struct>n";
        }

        
$xmldata .= "ttt</value>n";
        
$xmldata .= "tt</param>n";
        
$xmldata .= "t</params>n";
        
$xmldata .= "</".$root_tag.">";
        
        return 
$xmldata;
    }
    
    
/**
     * Recursive method to build document
     *
     * @param    string        XML Data
     * @param    string        Key
     * @param    string        Value
     * @param    integer        Depth
     * @return    @e string
     */
    
protected function _buildDocumentRecurse( $xmldata, $k, $v, $depth=4 )
    {
        
$xmldata .= "t<member>n";
        
$xmldata .= "tt<name>".$k."</name>n";
        
$xmldata .= "tt<value>n";
        
$xmldata .= "ttt<array>n";
        
$xmldata .= "tttt<data>n";
        
$xmldata .= "ttttt<value>n";
        
$xmldata .= "tttttt<struct>n";
        
        foreach( 
$v as $_k => $_v )
        {
            if ( 
is_array( $_v ) )
            {
                
$depth++;
                
$xmldata .= $this->_buildDocumentRecurse( $xmldata, $k, $v, $depth );
            }
            else
            {
                
$_type = isset( $this->map_type_to_key[ $_k ] ) ? $this->map_type_to_key[ $_k ] : $this->getStringType( $_v );
                
                
$xmldata .= "ttttttt<member>n";
                
$xmldata .= "tttttttt<name>".$_k."</name>n";
                
                if ( 
strpos( $_v, '>' ) !== false OR strpos( $_v, '<' ) !== false OR strpos( $_v, '&' ) !== false )
                {
                    
$xmldata .= "tttttttt<value><base64>" . base64_encode($_v) . "</base64></value>n";
                }
                else
                {
                    
$xmldata .= "ttttt<value><".$_type.">" . htmlspecialchars($_v) . "</".$_type."></value>n";
                }

                
$xmldata .= "ttttttt</member>n";
            }
        }
        
        
$xmldata .= "tttttt</struct>n";
        
$xmldata .= "ttttt</value>n";
        
$xmldata .= "tttt</data>n";
        
$xmldata .= "ttt</array>n";
        
$xmldata .= "tt</value>n";
        
$xmldata .= "t</member>n";
        
        return 
$xmldata;
    }
    
    
/**
     * Prints a true document and exits
     *
     * @return    @e void
     */
    
public function returnTrue()
    {
        
$this->generateHeader();
        
        
$to_print = $this->header."
        <methodResponse>
            <params>
                <param>
                    <value><boolean>1</boolean></value>
                </param>
            </params>
           </methodResponse>"
;
        
        @
header( "Connection: close" );
        @
header( "Content-length: ".strlen($to_print) );
        @
header( "Content-type: text/xml" );
        @
header( "Date: " . date("r") ); 
        print 
$to_print;
        
        
$this->addDebug( "ReturnTrue: {$to_print}" );
        
        exit();
    }
    
    
/**
     * Prints a document and exits
     *
     * @param    array          Array of params to return in key => value pairs
     * @return    @e void
     */
    
public function returnParams( $data_array )
    {
        
$to_print = $this->buildDocument( $data_array );
        @
header( "Connection: close" );
        @
header( "Content-length: ".strlen($to_print) );
        @
header( "Content-type: text/xml" );
        @
header( "Date: " . date("r") );
        @
header( "Pragma: no-cache" );
        @
header( "Cache-Control: no-cache" );
        print 
$to_print;
        
        
$this->addDebug( "ReturnParams: {$to_print}" );
        
        exit();
    }
    
    
/**
     * Prints an error document and exits
     *
     * @param    int            Error code
     * @param    string        Error Message
     * @return    @e void
     */
    
public function returnError( $error_code, $error_msg )
    {
        
$this->generateHeader();
        
        
$to_print = $this->header . "
        <methodResponse>
           <fault>
              <value>
                 <struct>
                    <member>
                       <name>faultCode</name>
                       <value>
                          <int>"
.intval($error_code)."</int>
                          </value>
                       </member>
                    <member>
                       <name>faultString</name>
                       <value>
                          <string>"
.$error_msg."</string>
                          </value>
                       </member>
                    </struct>
                 </value>
                    </fault>
           </methodResponse>"
;
        
        @
header( "Connection: close" );
        @
header( "Content-length: ".strlen($to_print) );
        @
header( "Content-type: text/xml" );
        @
header( "Date: " . date("r") ); 
        print 
$to_print;
        
        exit();
    }

    
/**
     * Create and send an XML document.  Returns false on error, or the decoded XML-RPC response as a string.
     *
     * @param    string        URL to send XML-RPC data to
     * @param    array       XML-RPC data
     * @return    @e mixed
     */
    
public function post( $file_location, $xmldata='' )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------

        
$data            = null;
        
$fsocket_timeout = 10;
        
$header          = "";
        
        
//-----------------------------------------
        // Send it..
        //-----------------------------------------

        
$url_parts = parse_url($file_location);
        
        if ( ! 
$url_parts['host'] )
        {
            
$this->errors[] = "No host found in the URL '{$file_location}'!";
            return 
false;
        }
        
        
//-------------------------------
        // Finalize
        //-------------------------------
        
        
$host = $url_parts['host'];
        
$_host = $url_parts['scheme'] == 'https' ? 'ssl://' . $host : $host;
          
        
$port = ( isset($url_parts['port']) ) ? $url_parts['port'] : ( $url_parts['scheme'] == 'https' ? 443 : 80 );
          
        
//-----------------------------------------
        // User and pass?
        //-----------------------------------------
        
        
if ( ! $this->auth_user AND !empty($url_parts['user']) )
        {
            
$this->auth_user = $url_parts['user'];
            
$this->auth_pass = $url_parts['pass'];
        }
        
          
//-------------------------------
          // Tidy up path
          //-------------------------------
          
          
if ( ! empty( $url_parts["path"] ) )
        {
            
$path = $url_parts["path"];
        }
        else
        {
            
$path = "/";
        }
 
        if ( ! empty( 
$url_parts["query"] ) )
        {
            
$path .= "?" . $url_parts["query"];
        }
        
        if ( ! 
$fp = @fsockopen( $_host, $port, $errno, $errstr, $fsocket_timeout ) )
        {
            
$this->errors[] = "CONNECTION REFUSED FROM {$host}";
            return 
FALSE;
        
        }
        else
        {
            
$header  = "POST $path HTTP/1.0rn";
            
$header .= "User-Agent: IPS XML-RPC Client Library ($Revision: 10721 $)rn";
            
$header .= "Host: $hostrn";
            
            if ( 
$this->auth_user && $this->auth_pass )
            {
                
$this->addDebug( "Authorization: Basic Performed" );

                
$header .= "Authorization: Basic ".base64_encode("{$this->auth_user}:{$this->auth_pass}")."rn";
            }
            
            
$header .= "Connection: closern";
            
$header .= "Content-Type: text/xmlrn";
            
$header .= "Content-Length: " . strlen($xmldata) . "rnrn";
            
            if ( ! 
fputs( $fp, $header . $xmldata ) )
            {
                
$this->errors[] = "Unable to send request to $host!";
                return 
FALSE;
            }
         }

         @
stream_set_timeout($fp, $fsocket_timeout);
        
         
$status = @socket_get_status($fp);
        
         while( ! 
feof($fp) && ! $status['timed_out'] )         
         {
            
$data  .= fgets ( $fp, 8192 );
            
$status = socket_get_status($fp);
         }
        
        
fclose ($fp);
       
        
//-------------------------------
        // Strip headers
        //-------------------------------
        
        
$tmp  = explode("rnrn", $data, 2);
        
$data = trim($tmp[1]);

        
//-----------------------------------------
        // Debug?
        //-----------------------------------------
        
        
if ( IPS_XML_RPC_DEBUG_ON )
        {
            if( 
$this->auth_pass )
            {
                
$_pass = str_repeat( 'x', strlen( $this->auth_pass ) - 1 ) . substr( $this->auth_pass, -1 );
            }
            else
            {
                
$_pass = '';
            }

            
$this->addDebug( "POST RESPONSE to {$this->auth_user}:{$_pass}@$host{$path}: " . $data );
        }
        
        
//-----------------------------------------
        // Continue
        //-----------------------------------------
        
        
return $this->decodeXmlRpc( $data );
    }
    
    
/**
     * Get the XML-RPC string type
     *
     * @param    string        String
     * @return    @e string
     */
    
public function getStringType( $string )
    {
        
$type = gettype( $string );
        
        switch( 
$type )
        {
            default:
            case 
'string':
                
$type = 'string';
                break;
            case 
'integer':
                
$type = 'int';
                break;
            case 
'double':
                
$type = 'double';
                break;
            case 
'null':
            case 
'boolean':
                
$type = 'boolean';
                break;
        }
        
        return 
$type;
    }
    
    
/**
     * Add debug message
     *
     * @param    string        Log message
     * @return    @e boolean
     */
    
public function addDebug( $msg )
    {
        if ( 
IPS_XML_RPC_DEBUG_FILE AND IPS_XML_RPC_DEBUG_ON )
        {
            
$full_msg = "==================================================================n"
                       
. "SCRIPT NAME: " . $_SERVER["SCRIPT_NAME"] . "n"
                       
. gmdate( 'r' ) . ' - ' . $_SERVER['REMOTE_ADDR'] . ' - ' . $msg . "n"
                       
. "==================================================================n";
            
            if ( 
$FH = @fopen( IPS_XML_RPC_DEBUG_FILE, 'a+' ) )
            {
                
fwrite( $FH, $full_msg, strlen( $full_msg ) );
                
fclose( $FH );
            }
        }
        
        return 
true;
    }
    
    
/**
     * Create the XML header
     *
     * @access    protected
     * @return    @e void
     */
    
protected function generateHeader()
    {
        
$this->header    = '<?xml version="1.0" encoding="' . $this->doc_type . '" ?>';
    }
}

class 
xmlRpcParser
{
    
/**
     * Parser object
     *
     * @var        object
     */
    
public $parser;
    
    
/**
     * Current document
     *
     * @var        string
     */
    
public $document;
    
    
/**
     * Current tag
     *
     * @var        string
     */
    
public $current;
    
    
/**
     * Parent tag
     *
     * @var        string
     */
    
public $parent;
    
    
/**
     * Parents
     *
     * @var        array
     */
    
public $parents;
    
    
/**
     * Last opened tag
     *
     * @var        string
     */
    
public $last_opened_tag;
    
    
/**
     * Constructor
     *
     * @param    string        Data
     * @return    @e void
     */
    
public function __construct( $data=null )
    {
        
$this->parser = xml_parser_create();

        
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
        
xml_set_object(               $this->parser, $this);
        
xml_set_element_handler(      $this->parser, "_rpcOpen", "_rpcClose");
        
xml_set_character_data_handler($this->parser, "_rpcData");
    }
    
    
/**
     * Destructor
     *
     * @return    @e void
     */
    
public function __destruct()
    {
        
xml_parser_free( $this->parser );
    }
    
    
/**
     * Parse the XML data
     *
     * @param    string        Data
     * @return    @e string
     */
    
public function parse( $data )
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$this->document        = array();
        
$this->parent          = &$this->document;
        
$this->parents         = array();
        
$this->last_opened_tag = NULL;

        
//-----------------------------------------
        // Parse
        //-----------------------------------------
        
        
xml_parse($this->parser, $data);
        
        
//-----------------------------------------
        // Return...
        //-----------------------------------------
        
$tmp = $this->document;
        return 
$tmp;
    }
    
    
/**
     * Open handler for XML object
     *
     * @param    object        Parser reference
     * @param    string        Tag
     * @param    array         Attributes
     * @return    @e void
     */
    
protected function _rpcOpen($parser, $tag, $attributes)
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------
        
        
$this->data            = "";
        
$this->last_opened_tag = $tag;

        if ( 
array_key_exists( $tag, $this->parent ) )
        {
            if ( 
is_array( $this->parent[$tag] ) and array_key_exists( 0, $this->parent[$tag] ) )
            {
                
$key = is_array( $this->parent[$tag] ) ? count( array_filter( array_keys($this->parent[$tag]), 'is_numeric' ) ) : 0;
            }
            else
            {
                
$temp = &$this->parent[$tag];
                unset(
$this->parent[$tag]);

                
$this->parent[$tag][0] = &$temp;

                if ( 
array_key_exists( $tag ." attr", $this->parent ) )
                {
                    
$temp = &$this->parent[ $tag ." attr" ];
                    unset(
$this->parent[ $tag ." attr" ]);
                    
$this->parent[$tag]["0 attr"] = &$temp;
                }

                
$key = 1;
            }

            
$this->parent = &$this->parent[$tag];
        }
        else
        {
            
$key = $tag;
        }

        if ( 
$attributes )
        {
            
$this->parent[ $key ." attr" ] = $attributes;
        }

        
$this->parent[$key] = array();
        
$this->parent       = &$this->parent[$key];

        
//array_unshift($this->parents, &$this->parent);
        
$this->_arrayUnshiftReference($this->parents, $this->parent);
    }
    
    
/**
     * Array unshift wrapper
     *
     * @param    array        Array
     * @param    string        Value
     * @return    @e array
     */
    
protected function _arrayUnshiftReference(&$array, &$value)
    {
       
$return = array_unshift($array,'');
       
$array[0] =& $value;
       return 
$return;
    }    

    
/**
     * XML data handler
     *
     * @param    object        Parser reference
     * @param    string        Data
     * @return    @e void
     */
    
protected function _rpcData($parser, $data)
    {
        if ( 
$this->last_opened_tag != NULL )
        {
            
$this->data .= $data;
        }
    }
    
    
/**
     * XML close handler
     *
     * @param    object        Parser reference
     * @param    string        Tag
     * @return    @e void
     */
    
protected function _rpcClose($parser, $tag)
    {
        if ( 
$this->last_opened_tag == $tag )
        {
            
$this->parent = $this->data;
            
$this->last_opened_tag = NULL;
        }

        
array_shift($this->parents);

        
$this->parent = &$this->parents[0];
    }
}
Онлайн: 4
Реклама