155 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace crmeb\services\upload;
 | 
						|
 | 
						|
class XML
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * XML to array.
 | 
						|
     *
 | 
						|
     * @param string $xml XML string
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public static function parse($xml)
 | 
						|
    {
 | 
						|
        $backup = PHP_MAJOR_VERSION < 8 ? libxml_disable_entity_loader(true) : null;
 | 
						|
 | 
						|
        $result = self::normalize(simplexml_load_string(self::sanitize($xml), 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_NOCDATA | LIBXML_NOBLANKS));
 | 
						|
 | 
						|
        PHP_MAJOR_VERSION < 8 && libxml_disable_entity_loader($backup);
 | 
						|
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * XML encode.
 | 
						|
     *
 | 
						|
     * @param mixed $data
 | 
						|
     * @param string $root
 | 
						|
     * @param string $item
 | 
						|
     * @param string $attr
 | 
						|
     * @param string $id
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public static function build(
 | 
						|
        $data,
 | 
						|
        $root = 'xml',
 | 
						|
        $item = 'item',
 | 
						|
        $attr = '',
 | 
						|
        $id = 'id'
 | 
						|
    )
 | 
						|
    {
 | 
						|
        if (is_array($attr)) {
 | 
						|
            $_attr = [];
 | 
						|
 | 
						|
            foreach ($attr as $key => $value) {
 | 
						|
                $_attr[] = "{$key}=\"{$value}\"";
 | 
						|
            }
 | 
						|
 | 
						|
            $attr = implode(' ', $_attr);
 | 
						|
        }
 | 
						|
 | 
						|
        $attr = trim($attr);
 | 
						|
        $attr = empty($attr) ? '' : " {$attr}";
 | 
						|
        $xml = "<{$root}{$attr}>";
 | 
						|
        $xml .= self::data2Xml($data, $item, $id);
 | 
						|
        $xml .= "</{$root}>";
 | 
						|
 | 
						|
        return $xml;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Build CDATA.
 | 
						|
     *
 | 
						|
     * @param string $string
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public static function cdata($string)
 | 
						|
    {
 | 
						|
        return sprintf('<![CDATA[%s]]>', $string);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Object to array.
 | 
						|
     *
 | 
						|
     *
 | 
						|
     * @param SimpleXMLElement $obj
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected static function normalize($obj)
 | 
						|
    {
 | 
						|
        $result = null;
 | 
						|
 | 
						|
        if (is_object($obj)) {
 | 
						|
            $obj = (array)$obj;
 | 
						|
        }
 | 
						|
 | 
						|
        if (is_array($obj)) {
 | 
						|
            foreach ($obj as $key => $value) {
 | 
						|
                $res = self::normalize($value);
 | 
						|
                if (('@attributes' === $key) && ($key)) {
 | 
						|
                    $result = $res; // @codeCoverageIgnore
 | 
						|
                } else {
 | 
						|
                    $result[$key] = $res;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $result = $obj;
 | 
						|
        }
 | 
						|
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Array to XML.
 | 
						|
     *
 | 
						|
     * @param array $data
 | 
						|
     * @param string $item
 | 
						|
     * @param string $id
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected static function data2Xml($data, $item = 'item', $id = 'id')
 | 
						|
    {
 | 
						|
        $xml = $attr = '';
 | 
						|
 | 
						|
        foreach ($data as $key => $val) {
 | 
						|
            if (is_numeric($key)) {
 | 
						|
                $id && $attr = " {$id}=\"{$key}\"";
 | 
						|
                $key = $item;
 | 
						|
            }
 | 
						|
 | 
						|
            $xml .= "<{$key}{$attr}>";
 | 
						|
 | 
						|
            if ((is_array($val) || is_object($val))) {
 | 
						|
                $xml .= self::data2Xml((array)$val, $item, $id);
 | 
						|
            } else {
 | 
						|
                $xml .= is_numeric($val) ? $val : self::cdata($val);
 | 
						|
            }
 | 
						|
 | 
						|
            $xml .= "</{$key}>";
 | 
						|
        }
 | 
						|
 | 
						|
        return $xml;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Delete invalid characters in XML.
 | 
						|
     *
 | 
						|
     * @see https://www.w3.org/TR/2008/REC-xml-20081126/#charsets - XML charset range
 | 
						|
     * @see http://php.net/manual/en/regexp.reference.escape.php - escape in UTF-8 mode
 | 
						|
     *
 | 
						|
     * @param string $xml
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public static function sanitize($xml)
 | 
						|
    {
 | 
						|
        return preg_replace('/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', '', $xml);
 | 
						|
    }
 | 
						|
}
 |