Subversion Repositories oidplus

Rev

Rev 514 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
480 daniel-mar 1
<?php
2
 
3
/*
4
 * PHP SimpleXML-Supplement
510 daniel-mar 5
 * Copyright 2020 - 2021 Daniel Marschall, ViaThinkSoft
480 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 * http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
20
 
21
// ======== ATTENTION, PLEASE READ ========
22
// This supplement script was created to support rare PHP installations that
23
// do not contain SimpleXML, for example at PHP you need to explicitly
24
// install the package "php-xml" if you want to have SimpleXML (In the PHP
25
// documentation, it is written that SimpleXML is available to all, which is
26
// not true).
27
//
28
// Beware that the supplement behaves differently than the real SimpleXML!
29
// (If you know how to improve this, please feel free to send me a patch)
30
//
31
// Just a few differences towards the original SimpleXML
32
// - print_r() looks different
33
// - The supplement requires that an XML string begins with "<!DOCTYPE" or "<?xml",
34
//   otherwise, the first element will not be stripped away
35
// - The supplement is slow because of regular expressions
36
// - Many functions like "asXML" are not implemented
510 daniel-mar 37
// - There might be other incompatibilities
480 daniel-mar 38
//
39
// So, if you want to use the SimpleXML supplement, then please carefully
40
// test it with your application if it works.
41
// ========================================
42
 
43
if (!function_exists('simplexml_load_string')) {
44
 
45
        function simplexml_load_file($file): SimpleXMLElement {
46
                return simplexml_load_string(file_get_contents($file));
47
        }
48
 
49
        function simplexml_load_string($testxml): SimpleXMLElement {
585 daniel-mar 50
                $out = new SimpleXMLElement(); /** @phpstan-ignore-line */
480 daniel-mar 51
 
52
                $testxml = preg_replace('@<!\\-\\-.+\\-\\->@','',$testxml); // remove comments
53
                $testxml = preg_replace('@<(\\S+)[^>]*/>@smU','<\\1></\\1>',$testxml); // <x/> => <x></x>
54
 
55
                if ((stripos($testxml, '<?xml') !== false) || (stripos($testxml, '<!doctype') !== false)) {
56
                        $testxml = preg_replace('@<\\?.+\\?>@','',$testxml);
57
                        $testxml = preg_replace('@<!doctype.+>@i','',$testxml);
58
                        $m = array();
59
                        preg_match('@<(\\S+?)[^>]*>(.*)</\\1>@smU',$testxml,$m); // find root element
60
                        $root_element = $m[1];
61
                } else {
62
                        $root_element = null;
63
                }
64
 
65
                $m = array();
510 daniel-mar 66
                preg_match_all('@<(\\S+?)([^>]*)>(.*)</\\1>@smU', $testxml, $m, PREG_SET_ORDER);
480 daniel-mar 67
                foreach ($m as $n) {
68
                        $name = $n[1];
510 daniel-mar 69
                        $other = $n[2];
70
                        $val  = $n[3];
480 daniel-mar 71
 
72
                        $val = str_replace('<![CDATA[', '', $val);
73
                        $val = str_replace(']]>', '', $val);
74
                        $val = trim($val);
75
 
510 daniel-mar 76
                        $new = $out->addChild($name, $val);
77
 
514 daniel-mar 78
                        $m2 = array();
510 daniel-mar 79
                        preg_match_all('@(\S+)=\\"([^\\"]+)\\"@smU', $other, $m2, PREG_SET_ORDER);
80
                        foreach ($m2 as $n2) {
81
                                $att_name = $n2[1];
82
                                $att_val = $n2[2];
83
                                $new->addAttribute($att_name, $att_val);
84
                        }
480 daniel-mar 85
                }
86
 
87
                if (!is_null($root_element)) {
88
                        $out = $out->$root_element;
89
                }
90
 
91
                return $out;
92
        }
93
 
510 daniel-mar 94
        class SimpleXMLElement implements ArrayAccess, Iterator {
480 daniel-mar 95
 
510 daniel-mar 96
                private $_attrs = array();
97
 
98
                public function addAttribute($name, $val) {
99
                        $this->_attrs[$name] = $val;
100
                }
101
 
102
                public function attributes() {
103
                        return $this->_attrs;
104
                }
105
 
480 daniel-mar 106
                public function isSupplement() {
107
                        return true;
108
                }
109
 
510 daniel-mar 110
                public function __construct($val=null) {
111
                        if (!is_null($val)) {
112
                                $this->{0} = $val;
113
                        }
114
                }
115
 
116
                public function isArray() {
117
                        $vars = get_object_vars($this);
118
                        $max = -1;
119
                        foreach ($vars as $x => $dummy) {
120
                                if (($x == '_attrs') || ($x == 'position')) continue;
121
                                if (!is_numeric($x)) {
122
                                        $max = -1;
123
                                        break;
124
                                } else {
125
                                        if ($x > $max) $max = $x;
126
                                }
127
                        }
128
                        return $max > 0;
129
                }
130
 
131
                public function addToArray($val) {
132
                        $vars = get_object_vars($this);
133
                        $max = -1;
134
                        foreach ($vars as $x => $dummy) {
135
                                if (($x == '_attrs') || ($x == 'position')) continue;
136
                                if (!is_numeric($x)) {
137
                                        $max = -1;
138
                                        break;
139
                                } else {
140
                                        if ($x > $max) $max = $x;
141
                                }
142
                        }
143
                        $max++;
144
                        $this->{(string)$max} = $val;
145
                }
146
 
480 daniel-mar 147
                public function __toString() {
148
                        $data = /*$this->data;*/get_object_vars($this);
149
                        if (is_array($data)) {
150
                                if (isset($data[0])) {
151
                                        return $data[0];
152
                                } else {
153
                                        return '';
154
                                }
155
                        } else {
156
                                return $data;
157
                        }
158
                }
159
 
160
                public function offsetExists($offset) {
161
                        return isset($this->$offset);
162
                }
163
 
164
                public function offsetGet($offset) {
165
                        return $this->$offset;
166
                }
167
 
168
                public function offsetSet($offset, $value) {
169
                        $this->$offset = $value;
170
                }
171
 
172
                public function offsetUnset($offset) {
173
                        unset($this->$offset);
174
                }
175
 
176
                public function __get($name) {
177
                        // Output nothing
585 daniel-mar 178
                        return new SimpleXMLElement(); /** @phpstan-ignore-line */
480 daniel-mar 179
                }
180
 
181
                public function addChild($name, $val=null) {
585 daniel-mar 182
                        if ($val == null) $val = new SimpleXMLElement(); /** @phpstan-ignore-line */
480 daniel-mar 183
 
184
                        if ((substr(trim($val),0,1) === '<') || (trim($val) == '')) {
185
                                $val = simplexml_load_string($val);
186
                        }
187
 
188
                        $data = /*$this->data;*/get_object_vars($this);
510 daniel-mar 189
 
480 daniel-mar 190
                        if (!isset($data[$name])) {
510 daniel-mar 191
                                if ($val instanceof SimpleXMLElement) {
192
                                        //echo "First add $name already exist\n";
193
                                        $this->$name = $val;
480 daniel-mar 194
                                } else {
510 daniel-mar 195
                                        $this->$name = new SimpleXMLElement($val);
196
                                        //echo "First add $name with val\n";
480 daniel-mar 197
                                }
510 daniel-mar 198
                        } else {
199
                                if (!($val instanceof SimpleXMLElement)) {
200
                                        $val = new SimpleXMLElement($val);
480 daniel-mar 201
                                }
510 daniel-mar 202
 
203
                                if ($data[$name]->isArray()) {
204
                                        $data[$name]->addToArray($val);
480 daniel-mar 205
                                } else {
585 daniel-mar 206
                                        $tmp = new SimpleXMLElement(); /** @phpstan-ignore-line */
510 daniel-mar 207
                                        $tmp->addToArray($data[$name]);
208
                                        $tmp->addToArray($val);
209
                                        $this->$name = $tmp;
210
                                        $this->_attrs = array();
480 daniel-mar 211
                                }
510 daniel-mar 212
                                return $val;
480 daniel-mar 213
                        }
214
 
510 daniel-mar 215
                        return $this->$name;
216
                }
217
 
218
                private $position = 0;
219
 
220
                public function rewind() {
221
                        $this->position = 0;
222
                }
223
 
224
                public function current() {
225
                        $vars = get_object_vars($this);
226
                        $cnt = 0;
227
                        foreach ($vars as $x => $dummy) {
228
                                if (($x == '_attrs') || ($x == 'position')) continue;
229
                                if (($dummy instanceof SimpleXMLElement) && !is_numeric($x) && $dummy->isArray()) {
230
                                        $vars2 = get_object_vars($dummy);
231
                                        foreach ($vars2 as $x2 => $dummy2) {
232
                                                if (($x2 == '_attrs') || ($x2 == 'position')) continue;
233
                                                if ($cnt == $this->position) {
234
                                                        if ($dummy2 instanceof SimpleXMLElement) {
235
                                                                return $dummy2;
236
                                                        } else {
237
                                                                return new SimpleXMLElement($dummy2);
238
                                                        }
239
                                                }
240
                                                $cnt++;
241
                                        }
242
                                } else {
243
                                        if ($cnt == $this->position) {
244
                                                if ($dummy instanceof SimpleXMLElement) {
245
                                                        return $dummy;
246
                                                } else {
247
                                                        return new SimpleXMLElement($dummy);
248
                                                }
249
                                        }
250
                                        $cnt++;
480 daniel-mar 251
                                }
252
                        }
253
 
510 daniel-mar 254
 
480 daniel-mar 255
                }
256
 
510 daniel-mar 257
                public function key() {
258
                        $vars = get_object_vars($this);
259
                        $cnt = 0;
260
                        foreach ($vars as $x => $dummy) {
261
                                if (($x == '_attrs') || ($x == 'position')) continue;
262
                                if (($dummy instanceof SimpleXMLElement) && !is_numeric($x) && $dummy->isArray()) {
263
                                        $vars2 = get_object_vars($dummy);
264
                                        foreach ($vars2 as $x2 => $dummy2) {
265
                                                if (($x2 == '_attrs') || ($x2 == 'position')) continue;
266
                                                if ($cnt == $this->position) return $x/*sic*/;
267
                                                $cnt++;
268
                                        }
269
                                } else {
270
                                        if ($cnt == $this->position) return $x;
271
                                        $cnt++;
272
                                }
273
                        }
274
                }
480 daniel-mar 275
 
510 daniel-mar 276
                public function next() {
277
                        ++$this->position;
278
                }
480 daniel-mar 279
 
510 daniel-mar 280
                public function valid() {
281
                        $vars = get_object_vars($this);
282
                        $cnt = 0;
283
                        foreach ($vars as $x => $dummy) {
284
                                if (($x == '_attrs') || ($x == 'position')) continue;
285
                                if (($dummy instanceof SimpleXMLElement) && !is_numeric($x) && $dummy->isArray()) {
286
                                        $vars2 = get_object_vars($dummy);
287
                                        foreach ($vars2 as $x2 => $dummy2) {
288
                                                if (($x2 == '_attrs') || ($x2 == 'position')) continue;
289
                                                $cnt++;
290
                                        }
291
                                } else {
292
                                        $cnt++;
293
                                }
294
                        }
480 daniel-mar 295
 
510 daniel-mar 296
                        return $this->position < $cnt;
297
                }
480 daniel-mar 298
 
510 daniel-mar 299
        }
480 daniel-mar 300
}