Seditio Source
Root |
./othercms/ips_4.3.4/system/Xml/SimpleXML.php
<?php
/**
 * @brief        Class for managing small XML files
 * @author        <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
 * @copyright    (c) Invision Power Services, Inc.
 * @license        https://www.invisioncommunity.com/legal/standards/
 * @package        Invision Community
 * @since        18 Feb 2013
 */

namespace IPS\Xml;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
   
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * Class for managing small XML files
 */
class _SimpleXML extends \SimpleXMLElement
{
   
/**
     * Create New XML Document
     *
     * @param    string        $rootElement    Name of Root Element
     * @param    string|NULL    $xmlns            Namespace
     * @return    \IPS\Xml\SimpleXML
     * @note    We are disabling the entity loader after opening the content to prevent XXE
     */
   
public static function create( $rootElement, $xmlns=NULL )
    {
       
$entityLoaderValue = libxml_disable_entity_loader( false );

       
$string = $xmlns ? "<?xml version='1.0' encoding='UTF-8'?><{$rootElement} xmlns='{$xmlns}'></{$rootElement}>" : "<?xml version='1.0' encoding='UTF-8'?><{$rootElement}></{$rootElement}>";
       
$class = @simplexml_load_string( $string, get_called_class() );
       
libxml_disable_entity_loader( $entityLoaderValue );
        return
$class->subtype();
    }
   
   
/**
     * Load File
     *
     * @param    string    $filename    Filename of XML file
     * @return    \IPS\Xml\SimpleXML
     * @throws    \InvalidArgumentException
     * @note    We are disabling the entity loader after opening the content to prevent XXE
     */
   
public static function loadFile( $filename )
    {
       
$entityLoaderValue = libxml_disable_entity_loader( false );

       
$class = @simplexml_load_file( $filename, get_called_class() );
        if (
$class === FALSE )
        {
            throw new \
InvalidArgumentException;
        }
       
libxml_disable_entity_loader( $entityLoaderValue );
        return
$class->subtype();
    }
   
   
/**
     * Load String
     *
     * @param    string    $xml    XML
     * @return    \IPS\Xml\SimpleXML
     * @throws    \InvalidArgumentException
     * @note    We are disabling the entity loader after opening the content to prevent XXE
     */
   
public static function loadString( $xml )
    {
       
$entityLoaderValue = libxml_disable_entity_loader( false );
       
       
$class = @simplexml_load_string( $xml, get_called_class() );
        if (
$class === FALSE )
        {
            throw new \
InvalidArgumentException;
        }
       
libxml_disable_entity_loader( $entityLoaderValue );
        return
$class->subtype();
    }
   
   
/**
     * Get appropriate subtype
     *
     * @return    \IPS\Xml\SimpleXML
     */
   
protected function subtype()
    {
        if (
get_called_class() === 'IPS\Xml\SimpleXML' )
        {
            if (
$this->getName() === 'rss' )
            {
                return \
IPS\Xml\Rss::loadString( $this->asXml() );
            }
            if (
$this->getName() === 'feed' )
            {
                return \
IPS\Xml\Atom::loadString( $this->asXml() );
            }
            if (
mb_strtolower( $this->getName() ) === 'rdf' )
            {
               
/* Verify this is an RSS 1.0 document */
               
if( in_array( 'http://purl.org/rss/1.0/', $this->getNamespaces( true ) ) )
                {
                    return \
IPS\Xml\Rss1::loadString( $this->asXml() );
                }
            }
        }

        return
$this;
    }

   
/**
     * Get articles
     *
     * @param    mixed    $guidKey    In previous versions, we encoded a key with the GUID. For legacy purposes, this can be passed here.
     * @return    array
     * @note    Subtypes (ATOM and RSS) define this method
     * @throws    \BadMethodCallException
     */
   
public function articles( $guidKey=NULL )
    {
        throw new \
BadMethodCallException;
    }
   
   
/**
     * Add Child
     * Modified to support passing other data types (including multi-dimensional arrays and other \IPS\XML\SimpleXML objects) as values
     *
     * @see        <a href='http://www.php.net/manual/en/simplexmlelement.addchild.php'>SimpleXMLElement::addChild</a>
     * @param    string        $name    Element Name
     * @param    mixed        $value    Value
     * @param    string|null    $ns        Namespace
     * @return    void
     */
   
public function addChild( $name, $value=NULL, $ns=NULL )
    {        
       
/* Arrays are possibly numerically indexed, which XML won't have */
       
if( gettype( $name ) === 'integer' )
        {
           
$name = $this->getName();
           
           
/* If the name ends in s (e.g. <elements>) - we'll name it's children without the s (e.g. <element>) */
           
if( mb_substr( $name, -2 ) === 'es' )
            {
               
$name = mb_substr( $name, 0, mb_strlen( $name ) - 2 );
            }
            else if(
mb_substr( $name, -1 ) === 's' )
            {
               
$name = mb_substr( $name, 0, mb_strlen( $name ) - 1 );
            }                
        }
       
       
/* If it's not an array, we can just let the default SimpleXML method handle this */
       
if( !is_array( $value ) and !( $value instanceof \IPS\Xml\SimpleXML ) )
        {            
           
/* Unless it's a boolean value, then we should cast that to an integer */
           
if( gettype( $value ) === 'boolean' )
            {
               
$value = intval( $value );
            }
           
           
/* Needs CDATA? */
           
if ( preg_match( '/<|>|&/', $value ) )
            {
               
$element = parent::addChild( $name, '', $ns );

               
$node = dom_import_simplexml( $element );
               
$no = $node->ownerDocument;
               
$node->appendChild( $no->createCDATASection( $value ) );
               
                return
$element;
            }
            else
            {
                return
parent::addChild( $name, $value, $ns );
            }
           
           
/* Return */
       
}
       
/* If it is an array, we need to be a little clever */
       
else
        {            
           
/* Create an element with a blank value */
           
$element = parent::addChild( $name, '', $ns );
           
           
/* And loop through each value and rerun this method for each */
           
foreach ( $value as $k => $v )
            {
               
/* If the value is an XML text element, just get the value */
               
if ( $v instanceof \IPS\Xml\SimpleXML and count( $v->children() ) === 0 )
                {
                   
$v = (string) $v;
                }
               
               
/* And add it */
               
$element->addChild( $k, $v, $ns );
            }
        }
    }
   
   
/**
     * Remove Node
     *
     * @return    void
     */
   
public function removeNode()
    {
       
    }
   
   
/**
     * Format XML in a readable way (normally only used for debugging purposes)
     *
     * @return    string
     */
   
public function format()
    {
       
$dom = new \DOMDocument( '1.0', 'UTF-8' );
       
$dom->preserveWhiteSpace = false;
       
$dom->formatOutput = true;
        @
$dom->loadXML( $this->asXML() );
        return
$dom->saveXML();
    }
}