PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.53.2
Advanced Ads – Ad Manager & AdSense v1.53.2
2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / modules / import-export / classes / XmlEncoder.php
advanced-ads / modules / import-export / classes Last commit date
XmlEncoder.php 2 years ago export.php 2 years ago import.php 2 years ago
XmlEncoder.php
348 lines
1 <?php // phpcs:ignoreFile
2 /**
3 * Encodes XML data.
4 *
5 * Based on code from the Symfony package
6 *
7 * Copyright (c) 2004-2016 Fabien Potencier <fabien@symfony.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is furnished
14 * to do so, subject to the following conditions:
15
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
18
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 *
27 * @author Jordi Boggiano <j.boggiano@seld.be>
28 * @author John Wards <jwards@whiteoctober.co.uk>
29 * @author Fabian Vogler <fabian@equivalence.ch>
30 * @author Kévin Dunglas <dunglas@gmail.com>
31 */
32 class Advanced_Ads_XmlEncoder
33 {
34 /**
35 * @var DOMDocument
36 */
37 private $dom;
38
39 /**
40 * @var Advanced_Ads_XmlEncoder
41 */
42 private static $instance;
43
44 private function __construct() {}
45
46 /**
47 * @return Advanced_Ads_XmlEncoder
48 */
49 public static function get_instance()
50 {
51 if ( ! isset(self::$instance) ) {
52 self::$instance = new self;
53 }
54
55 return self::$instance;
56 }
57
58
59 public function encode( $data, $options = []) {
60 if ( ! extension_loaded( 'simplexml' ) ) {
61 throw new Exception( sprintf( __( 'The %s extension(s) is not loaded', 'advanced-ads' ), 'simplexml' ) );
62 }
63 if ( ! extension_loaded( 'dom' ) ) {
64 throw new Exception( sprintf( __( 'The %s extension(s) is not loaded', 'advanced-ads' ), 'dom' ) );
65 }
66
67 $this->dom = new DOMDocument();
68 $this->dom->preserveWhiteSpace = false;
69 $this->dom->formatOutput = true;
70 if (isset($options['encoding'])) {
71 $this->dom->encoding = $options['encoding'];
72 }
73
74 if ( ! is_array($data) ) {
75 throw new UnexpectedValueException( _x( 'The data must be an array', 'import_export', 'advanced-ads' ) );
76 }
77
78 if (isset($options['skip_root'])) {
79 $this->buildXml($this->dom, $data );
80 } else {
81 // create root <advads-export> tag
82 $root = $this->dom->createElement('advads-export');
83 $this->dom->appendChild($root);
84 $this->buildXml($root, $data );
85 }
86
87
88 return $this->dom->saveXML();
89 }
90
91 /**
92 * Parse the data and convert it to DOMElements.
93 */
94 private function buildXml(DOMNode $parentNode, $data ) {
95 $append = true;
96
97 foreach ($data as $key => $data) {
98 if (is_numeric($key) ) {
99 $append = $this->appendNode($parentNode, $data, 'item', $key);
100 } elseif ( $this->isElementNameValid($key) ) {
101 $append = $this->appendNode($parentNode, $data, $key);
102 }
103 }
104
105 return $append;
106 }
107
108
109 /**
110 * Selects the type of node to create and appends it to the parent.
111 *
112 * @param DOMNode $parentNode
113 * @param array|object $data
114 * @param string $nodeName
115 * @param string $key
116 *
117 * @return bool
118 */
119 private function appendNode(DOMNode $parentNode, $data, $nodeName, $key = null) {
120 $node = $this->dom->createElement($nodeName);
121
122 if (null !== $key) {
123 $node->setAttribute('key', $key);
124 }
125
126 $appendNode = false;
127 if (is_array($data)) {
128 $node->setAttribute('type', 'array' );
129 $appendNode = $this->buildXml($node, $data);
130 } elseif (is_numeric($data)) {
131 $node->setAttribute('type', is_string( $data) ? 'string' : 'numeric' );
132 $appendNode = $this->appendText($node, (string) $data);
133 } elseif (is_string($data)) {
134 $node->setAttribute('type', 'string');
135 $appendNode = $this->needsCdataWrapping($data) ? $this->appendCData($node, $data) : $this->appendText($node, $data);
136 } elseif (is_bool($data)) {
137 $node->setAttribute('type', 'boolean');
138 $appendNode = $this->appendText($node, (int) $data);
139 } elseif (is_null($data)) {
140 $node->setAttribute('type', 'null');
141 $appendNode = $this->appendText($node, '');
142 }
143
144 if ($appendNode) {
145 $parentNode->appendChild($node);
146 } else {
147 /* translators: %s node data */
148 throw new UnexpectedValueException( sprintf( _x( 'An unexpected value could not be serialized: %s', 'import_export', 'advanced-ads' ), var_export($data, true) ) );
149 }
150
151 return $appendNode;
152 }
153
154 final protected function appendText(DOMNode $node, $val) {
155 $nodeText = $this->dom->createTextNode($val);
156 $node->appendChild($nodeText);
157
158 return true;
159 }
160
161 final protected function appendCData(DOMNode $node, $val) {
162 $nodeText = $this->dom->createCDATASection($val);
163 $node->appendChild($nodeText);
164
165 return true;
166 }
167
168 /**
169 * Checks if a value contains any characters which would require CDATA wrapping.
170 *
171 * @param string $val
172 *
173 * @return bool
174 */
175 private function needsCdataWrapping($val) {
176 return preg_match('/[<>&]/', $val);
177 }
178
179 /**
180 * Checks the name is a valid xml element name.
181 *
182 * @param string $name
183 *
184 * @return bool
185 */
186 final protected function isElementNameValid($name) {
187 return $name && false === strpos($name, ' ') && preg_match('#^[\pL_][\pL0-9._:-]*$#ui', $name);
188 }
189
190 /**
191 * Decode XML data.
192 *
193 * @throws Exception If an extension is lt loaded.
194 * @throws UnexpectedValueException If XML data is invalid.
195 *
196 * @param string $data XML data.
197 * @return array Decoded XML data.
198 */
199 public function decode( $data ) {
200 if ( ! extension_loaded( 'simplexml' ) ) {
201 /* translators: %s: A name of not loaded extension. */
202 throw new Exception( sprintf( __( 'The %s extension(s) is not loaded', 'advanced-ads' ), 'simplexml' ) );
203 }
204 if ( ! extension_loaded( 'dom' ) ) {
205 /* translators: %s: A name of not loaded extension. */
206 throw new Exception( sprintf( __( 'The %s extension(s) is not loaded', 'advanced-ads' ), 'dom' ) );
207 }
208
209
210 if ('' === trim($data)) {
211 throw new UnexpectedValueException( _x( 'Invalid XML data, it can not be empty', 'import_export', 'advanced-ads' ) );
212 }
213
214 $internal_errors = libxml_use_internal_errors( true );
215
216 if ( LIBXML_VERSION < 20900 ) {
217 // The `libxml_disable_entity_loading` function has been deprecated in PHP 8.0 because in
218 // libxml >= 2.9.0 (that is required by PHP 8), external entity loading is disabled by default,
219 // so this function is no longer needed to protect against XXE attacks.
220 // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.libxml_disable_entity_loaderDeprecated
221 $disable_entities = libxml_disable_entity_loader( true );
222 }
223
224 libxml_clear_errors();
225
226 $dom = new DOMDocument();
227
228 if ( strpos( $data, '<advads-export>' ) === false ) {
229 $data = preg_replace('/^<\?xml.*?\?>/', '', $data );
230 $data = '<advads-export>' . $data . '</advads-export>';
231 }
232
233 $dom->loadXML($data, LIBXML_NONET | LIBXML_NOBLANKS);
234
235 libxml_use_internal_errors( $internal_errors );
236
237 if ( LIBXML_VERSION < 20900 ) {
238 // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.libxml_disable_entity_loaderDeprecated -- see L215ff. for an explanation
239 libxml_disable_entity_loader( $disable_entities );
240 }
241
242 if ($error = libxml_get_last_error()) {
243 libxml_clear_errors();
244
245 /* translators: %s error messages while trying to decode xml file */
246 throw new UnexpectedValueException( sprintf( _x( 'XML error: %s', 'import_export', 'advanced-ads' ), $error->message ) );
247
248 }
249
250 // <advads-export>
251 $rootNode = $dom->firstChild;
252
253 if ($rootNode->hasChildNodes()) {
254 return $this->parseXml($rootNode);
255 }
256 }
257
258 /**
259 * Parse the input DOMNode into an array or a string.
260 *
261 * @param DOMNode $node xml to parse
262 *
263 * @return array|string
264 */
265 private function parseXml(DOMNode $node) {
266 // Parse the input DOMNode value (content and children) into an array or a string
267 $data = [];
268 if ( $node->hasAttributes() ) {
269 foreach ($node->attributes as $attr) {
270 if (ctype_digit($attr->nodeValue)) {
271 $data['@'.$attr->nodeName] = (int) $attr->nodeValue;
272 } else {
273 $data['@'.$attr->nodeName] = $attr->nodeValue;
274 }
275 }
276 }
277
278 $text_type = isset($data['@type']) ? $data['@type'] : null;
279 unset( $data['@type'] );
280
281 // Parse the input DOMNode value (content and children) into an array or a string.
282 if (!$node->hasChildNodes()) {
283 $value = $node->nodeValue;
284 } elseif (1 === $node->childNodes->length && in_array($node->firstChild->nodeType, [XML_TEXT_NODE, XML_CDATA_SECTION_NODE])) {
285 $value = $node->firstChild->nodeValue;
286 } else {
287
288
289 $value = [];
290
291 foreach ($node->childNodes as $subnode) {
292 $val = $this->parseXml($subnode);
293
294 if ('item' === $subnode->nodeName && is_array($val) && isset($val['@key'])) {
295 $a = $val['@key'];
296 if (isset($val['#'])) {
297 $value[$a] = $val['#'] !== 'null' ? $val['#'] : null;
298 } else {
299 $value[$a] = $val !== 'null' ? $val : null;
300 }
301
302 } else {
303 $value[$subnode->nodeName][] = $val === 'null' ? null : $val;
304 }
305 }
306 foreach ($value as $key => $val) {
307 if (is_array($val) && 1 === count($val)) {
308 $value[$key] = current($val);
309 } else if ( is_array( $value[$key] ) && isset( $value[$key]['@key'] ) ) {
310 unset( $value[$key]['@key'] );
311 }
312 }
313 }
314
315 if (!count($data)) {
316 $value = $this->changeType( $value, $text_type );
317 return $value;
318 }
319
320 if (!is_array($value)) {
321 $value = $this->changeType( $value, $text_type );
322 $data['#'] = $value;
323 return $data;
324 }
325
326 if (1 === count($value) && key($value)) {
327 $data[key($value)] = current($value);
328
329 return $data;
330 }
331
332 foreach ($value as $key => $val) {
333 $data[$key] = $val;
334 }
335
336 return $data;
337 }
338
339 private function changeType( $text, $type ) {
340 if ( $type === 'string' ) return (string) $text;
341 if ( $type === 'numeric' ) return 0 + $text;
342 if ( $type === 'boolean' ) return (boolean) $text;
343 if ( $type === 'array' && $text=== '' ) return [];
344 if ( $type === 'null' ) return 'null';
345 return $text;
346 }
347 }
348