Completed
Push — master ( 6374e7...82cfc2 )
by Carlos
03:41
created

XML::sanitize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
/*
4
 * This file is part of the overtrue/http.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Overtrue\Http\Support;
13
14
use SimpleXMLElement;
15
16
/**
17
 * Class XML.
18
 */
19
class XML
20
{
21
    /**
22
     * XML to array.
23
     *
24
     * @param string $xml XML string
25
     *
26
     * @return array
27
     */
28
    public static function parse($xml)
29
    {
30
        $backup = libxml_disable_entity_loader(true);
31
32
        $result = self::normalize(simplexml_load_string(self::sanitize($xml), 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_NOCDATA | LIBXML_NOBLANKS));
0 ignored issues
show
Bug introduced by
It seems like simplexml_load_string(se...upport\LIBXML_NOBLANKS) can also be of type false; however, parameter $obj of Overtrue\Http\Support\XML::normalize() does only seem to accept SimpleXMLElement, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

32
        $result = self::normalize(/** @scrutinizer ignore-type */ simplexml_load_string(self::sanitize($xml), 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_NOCDATA | LIBXML_NOBLANKS));
Loading history...
33
34
        libxml_disable_entity_loader($backup);
35
36
        return $result;
37
    }
38
39
    /**
40
     * XML encode.
41
     *
42
     * @param mixed  $data
43
     * @param string $root
44
     * @param string $item
45
     * @param string $attr
46
     * @param string $id
47
     *
48
     * @return string
49
     */
50
    public static function build(
51
        $data,
52
        $root = 'xml',
53
        $item = 'item',
54
        $attr = '',
55
        $id = 'id'
56
    ) {
57
        if (is_array($attr)) {
0 ignored issues
show
introduced by
The condition is_array($attr) is always false.
Loading history...
58
            $_attr = [];
59
60
            foreach ($attr as $key => $value) {
61
                $_attr[] = "{$key}=\"{$value}\"";
62
            }
63
64
            $attr = implode(' ', $_attr);
65
        }
66
67
        $attr = trim($attr);
68
        $attr = empty($attr) ? '' : " {$attr}";
69
        $xml = "<{$root}{$attr}>";
70
        $xml .= self::data2Xml($data, $item, $id);
71
        $xml .= "</{$root}>";
72
73
        return $xml;
74
    }
75
76
    /**
77
     * Build CDATA.
78
     *
79
     * @param string $string
80
     *
81
     * @return string
82
     */
83
    public static function cdata($string)
84
    {
85
        return sprintf('<![CDATA[%s]]>', $string);
86
    }
87
88
    /**
89
     * Object to array.
90
     *
91
     *
92
     * @param SimpleXMLElement $obj
93
     *
94
     * @return array
95
     */
96
    protected static function normalize($obj)
97
    {
98
        $result = null;
99
100
        if (is_object($obj)) {
101
            $obj = (array) $obj;
102
        }
103
104
        if (is_array($obj)) {
105
            foreach ($obj as $key => $value) {
106
                $res = self::normalize($value);
107
                if (('@attributes' === $key) && ($key)) {
108
                    $result = $res; // @codeCoverageIgnore
109
                } else {
110
                    $result[$key] = $res;
111
                }
112
            }
113
        } else {
114
            $result = $obj;
115
        }
116
117
        return $result;
118
    }
119
120
    /**
121
     * Array to XML.
122
     *
123
     * @param array  $data
124
     * @param string $item
125
     * @param string $id
126
     *
127
     * @return string
128
     */
129
    protected static function data2Xml($data, $item = 'item', $id = 'id')
130
    {
131
        $xml = $attr = '';
132
133
        foreach ($data as $key => $val) {
134
            if (is_numeric($key)) {
135
                $id && $attr = " {$id}=\"{$key}\"";
136
                $key = $item;
137
            }
138
139
            $xml .= "<{$key}{$attr}>";
140
141
            if ((is_array($val) || is_object($val))) {
142
                $xml .= self::data2Xml((array) $val, $item, $id);
143
            } else {
144
                $xml .= is_numeric($val) ? $val : self::cdata($val);
145
            }
146
147
            $xml .= "</{$key}>";
148
        }
149
150
        return $xml;
151
    }
152
153
    /**
154
     * Delete invalid characters in XML.
155
     *
156
     * @see https://www.w3.org/TR/2008/REC-xml-20081126/#charsets - XML charset range
157
     * @see http://php.net/manual/en/regexp.reference.escape.php - escape in UTF-8 mode
158
     *
159
     * @param string $xml
160
     *
161
     * @return string
162
     */
163
    public static function sanitize($xml)
164
    {
165
        return preg_replace('/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', '', $xml);
166
    }
167
}
168