Issues (1751)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/ar/xml.php (11 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
	ar_pinp::allow( 'ar_xml' );
4
	ar_pinp::allow( 'ar_xmlElement' );
5
	ar_pinp::allow( 'ar_xmlNode' );
6
	ar_pinp::allow( 'ar_xmlNodes' );
7
	ar_pinp::allow( 'ar_xmlDataBinding' );
8
9
	class ar_xml extends arBase {
10
11
		public static $indenting = true;
12
		private static $comments = true;
13
		public static $indent = "\t";
14
		public static $strict = false;
15
		public static $preserveWhiteSpace = false;
16
		public static $autoparse = true;
17
18
		public static function configure( $option, $value ) {
19
			switch ( $option ) {
20
				case 'autoparse':
21
					self::$autoparse = (bool) $value;
22
				break;
23
				case 'indent':
24
					if ( is_bool( $value ) ) {
25
						self::$indenting = (bool) $value;
26
					} else if ( is_string( $value ) ) {
27
						self::$indenting = true;
28
						self::$indent = $value;
29
					} else if (!$value) {
30
						self::$indenting = false;
31
					}
32
				break;
33
				case 'comments':
34
					self::$comments = (bool)$value;
35
				break;
36
				case 'strict':
37
					self::$strict = (bool)$value;
38
				break;
39
				case 'preserveWhiteSpace':
40
					self::$preserveWhiteSpace = (bool) $value;
41
				break;
42
			}
43
		}
44
45
		public function __set( $name, $value ) {
46
			ar_xml::configure( $name, $value );
47
		}
48
49
		public function __get( $name ) {
50
			if ( isset( ar_xml::${$name} ) ) {
51
				return ar_xml::${$name};
52
			}
53
		}
54
55
		public static function preamble( $version = '1.0', $encoding = 'UTF-8', $standalone = null ) {
56
			if ( isset($standalone) ) {
57
				if ( $standalone === 'false' ) {
58
					$standalone = 'no';
59
				} else if ( $standalone === 'true' ) {
60
					$standalone = 'yes';
61
				}
62
				$standalone = self::attribute( 'standalone', $standalone );
63
			} else {
64
				$standalone = '';
65
			}
66
			return new ar_xmlNode('<?xml version="' . self::value($version)
67
				. '" encoding="' . self::value($encoding) . '"' . $standalone . ' ?'.'>');
68
		}
69
70
		public static function comment( $comment ) {
71
			return ( self::$comments ? new ar_xmlNode('<!-- '.self::value( $comment ).' -->') : '' );
72
		}
73
74
		public static function name( $name ) {
75
			ar::untaint($name, FILTER_UNSAFE_RAW);
76
			if (self::$strict) {
77
				$newname = preg_replace( '/[^-.0-9:a-z_]/isU', '', $name);
78
				$newname = preg_replace( '/^[^:a-z_]*/isU', '', $newname);
79
				//FIXME: throw an error here or something if newname !== name
80
				$name = $newname;
81
			}
82
			return $name;
83
		}
84
85
		public static function value( $value, $current = 0 ) {
86
			ar::untaint( $value, FILTER_UNSAFE_RAW );
87
			if ( is_array( $value ) ) {
88
				$content = '';
89
				foreach( $value as $subvalue ) {
90
					$content = rtrim($content) . ' ' . ltrim( self::value( $subvalue, $current ) );
91
				}
92
				$content = trim( $content );
93
			} else if ( is_bool( $value ) ) {
94
				$content = $value ? 'true' : 'false';
95
			} else if ( $value instanceof ar_listExpression ) {
96
				$content = self::value( $value->item( $current ) );
97
			} else {
98
				if ( preg_match( '/^\s*<!\[CDATA\[/', $value ) ) {
99
					$content = $value;
100
				} else {
101
					$content = htmlspecialchars( $value, ENT_QUOTES, 'UTF-8' );
102
				}
103
			}
104
			return $content;
105
		}
106
107
		public static function attribute( $name, $value, $current = 0 ) {
108
			if ( is_numeric( $name ) ) {
109
				return ' ' . self::name( $value );
110
			} else {
111
				return ' ' . self::name( $name ) . '="' . self::value( $value, $current ) . '"';
112
			}
113
		}
114
115
		public static function attributes( $attributes ) {
116
			$content = '';
117
			if ( is_array( $attributes ) ) {
118
				foreach( $attributes as $key => $value ) {
119
					$content .= self::attribute( $key, $value );
120
				}
121
			}
122
			return $content;
123
		}
124
125
		public static function cdata( $value ) {
126
			ar::untaint( $value, FILTER_UNSAFE_RAW );
127
			return new ar_xmlNode($value, null, true);
128
		}
129
130
		public static function tag() {
131
			$args = func_get_args();
132
			return call_user_func_array( array( 'ar_xml', 'el' ), $args );
133
		}
134
135
		public static function element() {
136
			$args = func_get_args();
137
			return call_user_func_array( array( 'ar_xml', 'el' ), $args );
138
		}
139
140 View Code Duplication
		public static function el() {
141
			$args       = func_get_args();
142
			$name       = array_shift($args);
143
			$attributes = array();
144
			$content    = array();
145
			foreach ($args as $arg) {
146
				if ( is_array( $arg ) ) {
147
					$attributes = array_merge($attributes, $arg);
148
				} else if ($arg instanceof ar_xmlNodes) {
149
					$content    = array_merge( $content, (array) $arg);
150
				} else {
151
					$content[]  = $arg;
152
				}
153
			}
154
			if ( !count( $content ) ) {
155
				$content = null;
156
			} else {
157
				$content = new ar_xmlNodes( $content );
158
			}
159
			return new ar_xmlElement($name, $attributes, $content);
160
		}
161
162
		public static function indent( $content, $indent=null ) {
163
			if ( ( isset($indent) || self::$indenting ) && preg_match( '/^(\s*)</', $content) ) {
164
				if ( !isset($indent) ) {
165
					$indent = self::$indent;
166
				}
167
				return "\n" . preg_replace( '/^(\s*)</m', $indent . '$1<', $content );
168
			} else {
169
				return $content;
170
			}
171
		}
172
173
		public static function nodes() {
174
			$args  = func_get_args();
175
			$nodes = call_user_func_array( array( 'ar_xmlNodes', 'mergeArguments' ), $args );
176
			return new ar_xmlNodes( $nodes );
177
		}
178
179
		protected static function parseAttributes( $DOMElement ) {
180
			// get all attributes including namespaced ones and namespaces themselves...
181
			// this is the best I could do given the many bugs and oversights in php's
182
			// DOM implementation.
183
184
			$declaredns = array();
185
			$allns = array();
186
187
			// this part retrieves all available namespaces on the parent
188
			// xpath is the only reliable way
189
			$x = new DOMXPath( $DOMElement->ownerDocument );
190
			$p = $DOMElement->parentNode;
191
			if ($p && $p instanceof DOMNode ) {
192
				$pns = $x->query('namespace::*', $p );
193
				foreach( $pns as $node ) {
194
					$allns[$node->localName] = $p->lookupNamespaceURI( $node->localName );
195
				}
196
			}
197
			// this retrieves all namespaces on the current node
198
			// all 'new' namespace must have been declared on this node
199
			$ns = $x->query('namespace::*', $DOMElement);
200
			foreach( $ns as $node) {
201
				$uri = $DOMElement->lookupNamespaceURI( $node->localName );
202
				if ($allns[$node->localName]!=$uri && $node->localName!='xmlns') {
203
					$declaredns['xmlns:'.$node->localName] = $uri;
204
				}
205
			}
206
207
			// finally check if the default namespace has been altered
208
			$dns = $DOMElement->getAttribute('xmlns');
209
			if ($dns) {
210
				$declaredns['xmlns'] = $dns;
211
			}
212
213
			$result = $declaredns;
214
215
			$length = $DOMElement->attributes->length;
216
			for ($i=0; $i<$length; $i++) {
217
				$a = $DOMElement->attributes->item($i);
218
				$prefix = '';
219
				if ($a->prefix) {
220
					$prefix = $a->prefix.':';
221
				}
222
				$result[$prefix.$a->name] = $a->value;
223
			}
224
225
			return $result;
226
		}
227
228
		protected static function parseChildren( $DOMElement ) {
229
			$result = array();
230
			foreach ( $DOMElement->childNodes as $child ) {
231
				if ( $child instanceof DOMComment ) {
232
					if ( self::$preserveWhiteSpace || trim( $child->data )!=='' ) {
233
						$result[] = new ar_xmlNode('<!--'.$child->data.'-->');
234
					}
235 View Code Duplication
				} else if ( $child instanceof DOMCharacterData ) {
236
					if ( self::$preserveWhiteSpace || trim( $child->data )!=='' ) {
237
						$result[] = new ar_xmlNode($child->data);
238
					}
239
				} else if ( $child instanceof DOMCdataSection ) {
240
					if ( self::$preserveWhiteSpace || trim( $child->data )!=='' ) {
241
						$result[] = self::cdata( $child->data );
242
					}
243
				} else if ( $child instanceof DOMElement ) {
244
					$result[] = self::el( $child->tagName, self::parseAttributes( $child ), self::parseChildren( $child ) );
245
				}
246
			}
247
			return self::nodes( $result );
248
		}
249
250
		protected static function parseHead( DOMDocument $dom ) {
251
			$result = self::nodes();
252
			if ($dom->xmlVersion && $dom->xmlEncoding) {
253
				$result[] = self::preamble( $dom->xmlVersion, $dom->xmlEncoding, $dom->xmlStandalone );
254
			}
255
			if ($dom->doctype) {
256
				$doctype = '<!DOCTYPE '.$dom->doctype->name;
257
				if ($dom->doctype->publicId) {
258
					$doctype .= ' PUBLIC "'.$dom->doctype->publicId.'"';
259
				}
260
				if ($dom->doctype->systemId) {
261
					$doctype .= ' "'.$dom->doctype->systemId.'"';
262
				}
263
				$doctype .= '>';
264
				$result[] = new ar_xmlNode($doctype);
265
			}
266
			return $result;
267
		}
268
269
		public static function parse( $xml, $encoding = null ) {
270
			// important: parse must never return results with simple string values, but must always
271
			// wrap them in an ar_xmlNode, or tryToParse may get called, which will call parse, which
272
			// will... etc.
273
			$dom = new DOMDocument();
274
			if ( $encoding ) {
275
				$xml = '<?xml encoding="' . $encoding . '">' . $xml;
276
			}
277
			$prevErrorSetting = libxml_use_internal_errors(true);
278
			if ( $dom->loadXML( $xml ) ) {
279 View Code Duplication
				if ( $encoding ) {
280
					foreach( $dom->childNodes as $item ) {
281
						if ( $item->nodeType == XML_PI_NODE ) {
282
							$dom->removeChild( $item );
283
							break;
284
						}
285
					}
286
					$dom->encoding = $encoding;
287
				}
288
				$domroot = $dom->documentElement;
289
				if ( $domroot ) {
290
					$result = self::parseHead( $dom );
291
					$root = self::el( $domroot->tagName, self::parseAttributes( $domroot ), self::parseChildren( $domroot ) );
292
					$s = simplexml_import_dom( $dom );
293
					$n = $s->getDocNamespaces();
294
					foreach( $n as $prefix => $ns ) {
295
						if ($prefix) {
296
							$prefix = ':'.$prefix;
297
						}
298
						$root->setAttribute('xmlns'.$prefix, $ns);
299
					}
300
					$result[] = $root;
301
					return $result;
302
				}
303
			}
304
			$errors = libxml_get_errors();
305
			libxml_clear_errors();
306
			libxml_use_internal_errors( $prevErrorSetting );
307
			return ar_error::raiseError( 'Incorrect xml passed', ar_exceptions::ILLEGAL_ARGUMENT, $errors );
308
		}
309
310
		public static function tryToParse( $xml ) {
311
			$result = $xml;
312
			if ( ! ($xml instanceof ar_xmlNodeInterface ) ) {
313
				if ($xml && strpos( $xml, '<' ) !== false ) {
314
					try {
315
						$result = self::parse( '<root>'.$xml.'</root>' );
316
						if ( ar_error::isError($result) ) {
317
							$result = new ar_xmlNode( (string) $xml );
318
						} else {
319
							$result = $result->firstChild->childNodes;
320
						}
321
					} catch( Exception $e ) {
322
						$result = new ar_xmlNode( (string) $xml );
323
					}
324
				} else {
325
					$result = new ar_xmlNode( (string) $xml );
326
				}
327
			}
328
			return $result;
329
		}
330
331
	}
332
333
	/*
334
		This class is used for generic nodelists as well as childNodes
335
		The difference is in whether or not parentNode is set. As a
336
		generic nodelist the child nodes can have any parentNode, so the
337
		list is an in memory reference to a set of nodes. As a childNodes
338
		list the child nodes must have the same parentNode as the list.
339
		If you set the parentNode of the nodes list, it will also set the
340
		parentNode of all the childNodes and remove them from any other parent
341
	*/
342
	interface ar_xmlNodeInterface {	}
343
344
	class ar_xmlNodes extends ArrayObject implements ar_xmlNodeInterface {
345
346
		private $parentNode = null;
347
		public $attributes  = array();
348
		public $isDocumentFragment = true;
349
		private $nodeValue = ''; // needed for __get to function
0 ignored issues
show
The property $nodeValue is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
350
351
		public static function mergeArguments(){
352
			$args  = func_get_args();
353
			$nodes = array();
354
			foreach ( $args as $input ) {
355
				if ( is_array( $input ) || $input instanceof ar_xmlNodes ) { //FIXME: accept other array like objects as well?
356
					$nodes = array_merge( $nodes, (array) $input );
357
				} else if ($input) { // skip empty and NULL arguments
358
					$nodes[] = $input;
359
				}
360
			}
361
			return $nodes;
362
		}
363
364
		protected function _tryToParse( $node ) {
365
			$node = ar_xml::tryToParse( $node );
366
			return $node;
367
		}
368
369
		public function _normalizeNodes( $nodes ) {
370
			$result = array();
371
			if ( is_array($nodes) || $nodes instanceof Traversable ) {
372
				foreach ( $nodes as $node ) {
373 View Code Duplication
					if ( !$node instanceof ar_xmlNodeInterface ) {
374
						if ( ar_xml::$autoparse ) {
375
							$node = $this->_tryToParse( $node );
376
						} else {
377
							$node = new ar_xmlNode( $node );
378
						}
379
					}
380
					if ( is_array($node) || $node instanceof Traversable ) {
381
						$subnodes = $this->_normalizeNodes( $node );
382
						foreach ( $subnodes as $subnode ) {
383
							$result[] = $subnode;
384
						}
385
					} else {
386
						$result[] = $node;
387
					}
388
				}
389
			} else {
390 View Code Duplication
				if ( !$nodes instanceof ar_xmlNode ) {
391
					if ( ar_xml::$autoparse ) {
392
						$nodes = $this->_tryToParse( $nodes );
393
					} else {
394
						$nodes = new ar_xmlNode( $nodes );
395
					}
396
				}
397
				$result[] = $nodes;
398
			}
399
			return $result;
400
		}
401
402
		public function __construct() {
403
			$args  = func_get_args();
404
			$nodes = call_user_func_array( array( 'ar_xmlNodes', 'mergeArguments' ), $args );
405
			$nodes = $this->_normalizeNodes( $nodes );
406
			parent::__construct($nodes);
407
		}
408
409
		public function offsetSet($offset, $value) {
410
			if (!$value instanceof ar_xmlNodeInterface) {
411
				$value = new ar_xmlNode( $value );
412
			}
413
			parent::offsetSet($offset, $value);
414
		}
415
416
		public function __toString() {
417
			return $this->toString();
418
		}
419
420
		public function toString( $indentWith = null ) {
421
			foreach ( $this->attributes as $name => $value ) {
422
				$position = 0;
423 View Code Duplication
				foreach ( $this as $node ) {
424
					if ($node instanceof ar_xmlElement) {
425
						$appliedValue = $this->_applyValues($value, $position);
426
						$node->setAttribute( $name, $appliedValue );
427
						$position++;
428
					}
429
				}
430
			}
431
			$result = '';
432
433
			$position = 0;
434
			foreach ( $this as $node) {
435
				if ( $node instanceof ar_xmlElement) {
436
					$result .= $node->toString($indentWith, $position);
437
					$position++;
438
				} else if ( $node instanceof ar_xmlNode) {
439
					$stringValue = (string) $node;
440
					if ( trim($stringValue) !== "" ) {
441
						$result .= $stringValue;
442
					}
443
				} else if ( $node instanceof ar_xmlNodes) {
444
					$result .= $node->toString( $indentWith );
445
				} else if ( is_string($node) ) {
446
					$node = trim($node);
447
					if( $node !== "" ) {
448
						$result .= ar_xml::indent( (string) $node, $indentWith);
449
					}
450
				}
451
			}
452
			return $result;
453
		}
454
455
456
		public function setAttributes( array $attributes, $dynamic = true ) {
457
			foreach ($attributes as $name => $value) {
458
				$this->setAttribute( $name, $value, $dynamic );
459
			}
460
			return $this;
461
		}
462
463
		private function _runPatterns( $value ) {
464
			if ($value instanceof ar_listExpression_Pattern) {
465
				$count = 0;
466
				foreach ( $this as $key => $node ) {
467
					if ($node instanceof ar_xmlElement) {
468
						$count++;
469
					}
470
				}
471
				$value = ar::listExpression( $count )->pattern( $value->patterns );
472
			} else if ( is_array( $value ) ) {
473
				$newvalue = array();
474
				foreach ($value as $key => $subvalue ) {
475
					$newvalue[$key] = $this->_runPatterns( $subvalue );
476
				}
477
				$value = $newvalue;
478
			}
479
			return $value;
480
		}
481
482
		private function _applyValues( $value, $position = 0 ) {
483
			if ($value instanceof ar_listExpression) {
484
				$result = $value->item( $position );
485
			} else if ( is_array($value) ) {
486
				$result = array();
487
				foreach( $value as $key => $subvalue ) {
488
					$result[$key] = $this->_applyValues( $subvalue, $position );
489
				}
490
			} else {
491
				$result = $value;
492
			}
493
			return $result;
494
		}
495
496
		public function getAttribute( $name ) {
497
			return $this->attributes[$name];
498
		}
499
500
		public function setAttribute( $name, $value, $dynamic = true ) {
501
			$value = $this->_runPatterns($value);
502 View Code Duplication
			if ($dynamic) {
503
				if ( isset($this->attributes[$name]) && is_array($value) && !isset($value[0]) ) {
504
					if (!is_array($this->attributes[$name])) {
505
						$this->attributes[$name] = array( $this->attributes[$name] );
506
					}
507
					$this->attributes[$name] = array_merge( (array) $this->attributes[$name], $value );
508
				} else {
509
					$this->attributes[$name] = $value;
510
				}
511
			}
512
			$position = 0;
513 View Code Duplication
			foreach ( $this as $node ) {
514
				if ($node instanceof ar_xmlElement) {
515
					$appliedValue = $this->_applyValues($value, $position);
516
					$node->setAttribute( $name, $appliedValue );
517
					$position++;
518
				}
519
			}
520
			return $this;
521
		}
522
523
		public function removeAttribute( $name ) {
524
			if ( isset( $this->attributes[$name] ) ) {
525
				unset( $this->attributes[$name] );
526
			}
527
			foreach ( $this as $node ) {
528
				if ( $node instanceof ar_xmlElement ) {
529
					$node->removeAttribute( $name );
530
				}
531
			}
532
		}
533
534
		public function __get( $name ) {
535
			switch ( $name ) {
536
				case 'parentNode':
537
					return $this->parentNode;
538
				break;
539
				case 'firstChild':
540
					return $this[0];
541
				break;
542
				case 'lastChild':
543
					return $this[count($this)-1];
544
				break;
545
				case 'childNodes':
546
					return $this;
547
				break;
548
				case 'nodeValue':
549
					if ( count($this)==1 ) {
550
						return $this[0]->nodeValue;
551
					} else {
552
						$result = array();
553
						foreach($this as $node) {
554
							$result[] = $node->nodeValue;
555
						}
556
						return $result;
557
					}
558
				break;
559
				case 'attributes':
560
					if ( count($this)==1 ) {
561
						return $this[0]->attributes;
562
					} else {
563
						$result = array();
564
						foreach($this as $node) {
565
							if ($node instanceof ar_xmlElement || $node instanceof ar_xmlNodes ) {
566
								$result[] = $node->attributes;
567
							}
568
						}
569
						return $result;
570
					}
571
				break;
572
				default:
573
					if (!isset($this->parentNode) && !$this->isDocumentFragment ) {
574
						$result = array();
575
						foreach ($this as $node) {
576
							if ($node instanceof ar_xmlElement || $node instanceof ar_xmlNodes ) {
577
								$temp = $node->getElementsByTagName( $name, false );
578
								$result = array_merge( $result, (array) $temp);
579
							}
580
						}
581
						$result = $this->getNodeList( $result );
582
						$result->isDocumentFragment = false;
583
						return $result;
584
					} else {
585
						return $this->getElementsByTagName( $name, false );
586
					}
587
				break;
588
			}
589
		}
590
591
		public function __call( $name, $params ) {
592
			if (($name[0]==='_')) {
593
				$realName = substr($name, 1);
594
				if (ar_pinp::isAllowed($this, $realName)) {
595
					return call_user_func_array(array($this, $realName), $params);
596
				} else {
597
					trigger_error("Method $realName not found in class ".get_class($this), E_USER_ERROR);
598
				}
599
			} else if (isset($this[0]) && is_object($this[0]) ) {
600
				$el = $this[0];
601
				return call_user_func_array( array( $el, $name ), $params );
602
			} else {
603
				return null;
604
			}
605
		}
606
607
		public function __unset( $name ) {
608
			// e.g. unset( $xml->root->child )
609
			// __unset is called on $xml->root with 'child' as $name
610
			// so find all tags with name 'child' and remove them
611
			// or unset( $xml->root->child[2] )
612
			//
613
			if (is_numeric($name)) {
614
				$node = $this->childNodes[$name];
0 ignored issues
show
The property childNodes does not exist on object<ar_xmlNodes>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
615
				$this->removeChild($node);
616
			} else {
617
				$nodes = $this->getElementsByTagname( $name, false );
618
				$this->removeChild($nodes);
619
			}
620
		}
621
622
		public function __set( $name, $value ) {
623
			switch( $name ) {
624
				case 'parentNode':
625
					$this->setParentNode($value);
626
				break;
627
				default:
628
					if (is_numeric($name)) {
629
						$node = $this->childNodes[$name];
0 ignored issues
show
The property childNodes does not exist on object<ar_xmlNodes>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
630
						$this->replaceChild($node, $value);
631
					} else {
632
						switch ( $name ) {
633
							case 'nodeValue':
634
								foreach( $this->childNodes as $node ) {
0 ignored issues
show
The property childNodes does not exist on object<ar_xmlNodes>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
635
									$node->nodeValue = $value;
636
								}
637
							break;
638
							default:
639
								$nodes = $this->getElementsByTagname( $name, false );
640
								$this->replaceChild($value, $nodes);
641
							break;
642
						}
643
					}
644
				break;
645
			}
646
		}
647
648
		public function cloneNode( $recurse = false ) {
649
			if (!$recurse) {
650
				$result = $this->getNodeList();
651
			} else {
652
				$result = clone $this;
653
				$result->parentNode = null;
654
				foreach ( $result as $pos => $el ) {
655
					$result[$pos] = $el->cloneNode($recurse);
656
				}
657
			}
658
			return $result;
659
		}
660
661
		protected function getNodeList() {
662
			$params = func_get_args();
663
			return call_user_func_array( array( 'ar_xml', 'nodes'), $params );
664
		}
665
666
		function getElementsByTagName( $name, $recurse = true ) {
667
			$nodeList = array();
668
			foreach ($this as $node) {
669
				if ( $node instanceof ar_xmlElement ) {
670
					if ( $name == '*' || $node->tagName == $name) {
671
						$nodeList[] = $node;
672
					}
673
					if ($recurse) {
674
						$nodeList = array_merge( $nodeList, (array) $node->getElementsByTagName( $name ) );
675
					}
676
				}
677
			}
678
			$result = $this->getNodeList( $nodeList );
679
			$result->isDocumentFragment = false;
680
			return $result;
681
		}
682
683
		function getElementById( $id ) {
684
			if (isset($this->parentNode)) {
685
				return $this->parentNode->getElementById($id);
686
			} else {
687
				foreach ($this as $node ) {
688
					if ( $node instanceof ar_xmlElement ) {
689
						$el = $node->getElementById($id);
690
						if ( isset($el) ) {
691
							return $el;
692
						}
693
					}
694
				}
695
				return null;
696
			}
697
		}
698
699
		function __clearAllNodes() {
700
			self::__construct();
701
		}
702
703
		function setParentNode( ar_xmlElement $el ) {
704
			if ( $el === $this ) {
705
				return false;
706
			}
707
			$this->parentNode = $el;
708
			foreach ($this as $node) {
709
				if ($node instanceof ar_xmlElement) {
710
					if ( isset($node->parentNode) ) {
711
						if ( $node->parentNode !== $el ) {
712
							$node->parentNode->removeChild($node);
713
						}
714
					} else {
715
						$node->parentNode = $el;
0 ignored issues
show
The property $parentNode is declared private in ar_xmlElement. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
716
					}
717
				}
718
			}
719
			$this->isDocumentFragment = false;
720
		}
721
722
		function getPreviousSibling( ar_xmlNode $el ) {
723
			$pos = $this->_getPosition( $el );
724
			if ( $pos > 0 ) {
725
				return $this[ $pos - 1 ];
726
			} else {
727
				return null;
728
			}
729
		}
730
731
		function getNextSibling( ar_xmlNode $el ) {
732
			$pos = $this->_getLastPosition( $el );
733
			if ( $pos <= count( $this ) ) {
734
				return $this[ $pos ];
735
			} else {
736
				return null;
737
			}
738
		}
739
740 View Code Duplication
		function _getPosition( $el ) {
741
			if ( is_array($el) || $el instanceof Traversable ) {
742
				return $this->_getPosition( reset($el) );
743
			} else {
744
				foreach ( $this as $pos => $node ) {
745
					if ( $node === $el ) {
746
						return $pos;
747
					}
748
				}
749
			}
750
		}
751
752 View Code Duplication
		function _getLastPosition( $el ) {
753
			if ( is_array($el) || $el instanceof Traversable ) {
754
				return $this->_getLastPosition( end($el) );
755
			} else {
756
				foreach ( $this as $pos => $node ) {
757
					if ( $node === $el ) {
758
						return $pos+1;
759
					}
760
				}
761
			}
762
		}
763
764
		private function _removeChildNodes( $el ) {
765
			if ( isset( $this->parentNode ) ) {
766
				if ( is_array( $el ) || $el instanceof Traversable ) {
767
					foreach ( $el as $subEl ) {
768
						if ( isset($subEl->parentNode) ) {
769
							$subEl->parentNode->removeChild( $subEl );
770
						}
771
					}
772
				} else {
773
					if ( isset($el->parentNode) ) {
774
						$el->parentNode->removeChild( $el );
775
					}
776
				}
777
			}
778
		}
779
780
		private function _setParentNodes( $el ) {
781
			if ( isset( $this->parentNode ) ) {
782
				if ( is_array( $el ) || $el instanceof Traversable ) {
783
					foreach ( $el as $subEl ) {
784
						$this->_setParentNodes( $subEl );
785
					}
786
				} else if ( $el instanceof ar_xmlNode) {
787
					$el->__clearParentIdCache();
788
					$el->parentNode = $this->parentNode;
0 ignored issues
show
The property $parentNode is declared private in ar_xmlNode. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
789
					$el->__restoreParentIdCache();
790
				}
791
			}
792
		}
793
794
		function appendChild( $el ) {
795
			$this->_removeChildNodes( $el );
796
			$result = $this->_appendChild( $el );
797
			return $result;
798
		}
799
800
		private function _appendChild( $el ) {
801
			$this->_setParentNodes( $el );
802
			if ( !is_array( $el ) && !( $el instanceof ArrayObject ) ) {
803
				$list = array( $el );
804
			} else {
805
				$list = (array) $el;
806
			}
807
			self::__construct( array_merge( (array) $this, $list ) );
808
			return $el;
809
		}
810
811
		function insertBefore( $el, ar_xmlNodeInterface $referenceEl = null ) {
812
			$this->_removeChildNodes( $el );
813
			if ( !isset($referenceEl) ) {
814
				return $this->_appendChild( $el );
815
			} else {
816
				$pos = $this->_getPosition( $referenceEl );
817 View Code Duplication
				if ( !isset($pos) ) {
818
					$this->_appendChild( $el );
819
				} else {
820
					$this->_setParentNodes( $el );
821
					if ( !is_array( $el ) ) {
822
						$list = array( $el );
823
					} else {
824
						$list = (array) $el;
825
					}
826
					$arr = (array) $this;
827
					array_splice( $arr, $pos, 0, $list );
828
					self::__construct( $arr );
829
				}
830
			}
831
			return $el;
832
		}
833
834
		function replaceChild( $el, ar_xmlNodeInterface $referenceEl ) {
835
			$this->_removeChildNodes( $el );
836
			$pos = $this->_getPosition( $referenceEl );
837 View Code Duplication
			if ( !isset($pos) ) {
838
				return null;
839
			} else {
840
				$this->_setParentNodes( $el );
841
				if ( !is_array( $el ) ) {
842
					$list = array( $el );
843
				} else {
844
					$list = (array) $el;
845
				}
846
				$arr = (array) $this;
847
				array_splice( $arr, $pos, 0, $list );
848
				self::__construct( $arr );
849
				return $this->removeChild( $referenceEl );
850
			}
851
		}
852
853
		public function removeChild( $el ) {
854
			// Warning: must never ever call _removeChildNodes, can be circular.
855
			if ( is_array( $el ) || $el instanceof Traversable) {
856
				foreach( $el as $subEl ) {
857
					$this->removeChild( $subEl );
858
				}
859
			} else {
860
				$pos = $this->_getPosition( $el );
861
				if ( isset($pos) ) {
862
					$oldEl = $this[$pos];
863
					$arr = (array) $this;
864
					array_splice( $arr, $pos, 1);
865
					self::__construct( $arr );
866
					if ( isset($this->parentNode) ) {
867
						$oldEl->__clearParentIdCache();
868
						$oldEl->parentNode = null;
869
					}
870
				} else {
871
					return null;
872
				}
873
			}
874
			return $el;
875
		}
876
877
		public function bind( $nodes, $name, $type = 'string' ) {
878
			$b = new ar_xmlDataBinding( );
879
			return $b->bind( $nodes, $name, $type );
880
		}
881
882
		public function bindAsArray( $nodes, $type = 'string' ) {
883
			$b = new ar_xmlDataBinding( );
884
			return $b->bindAsArray( $nodes, 'list', $type)->list;
0 ignored issues
show
The property list does not seem to exist in ar_xmlDataBinding.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
885
		}
886
887
	}
888
889
	class ar_xmlNode extends arBase implements ar_xmlNodeInterface {
890
		private $parentNode = null;
891
		private $nodeValue = '';
892
		public $cdata = false;
893
894
		function __construct($value, $parentNode = null, $cdata = false) {
895
			$this->nodeValue  = $value;
896
			$this->parentNode = $parentNode;
897
			$this->cdata      = $cdata;
898
		}
899
900
		function __toString() {
901
			return $this->toString();
902
		}
903
904
		function toString() {
905
			if ($this->cdata) {
906
				return "<![CDATA[" . str_replace("]]>", "]]&gt;", $this->nodeValue) . "]]>";
907
			} else {
908
				return (string) $this->nodeValue;
909
			}
910
		}
911
912
		function __get( $name ) {
913
			switch( $name ) {
914
				case 'parentNode':
915
					return $this->parentNode;
916
				break;
917
				case 'previousSibling':
918
					if (isset($this->parentNode)) {
919
						return $this->parentNode->childNodes->getPreviousSibling($this);
920
					}
921
				break;
922
				case 'nextSibling':
923
					if (isset($this->parentNode)) {
924
						return $this->parentNode->childNodes->getNextSibling($this);
925
					}
926
				break;
927
				case 'nodeValue':
928
					return $this->nodeValue;
929
				break;
930
			}
931
		}
932
933
		function __set( $name, $value ) {
934
			switch ($name) {
935
				case 'nodeValue':
936
					$this->nodeValue = $value;
937
				break;
938 View Code Duplication
				case 'parentNode':
939
					if ( $value === $this || !( $value instanceof ar_xmlElement ) ) {
940
						$this->parentNode = null;
941
					} else {
942
						$this->parentNode = $value;
943
					}
944
				break;
945
			}
946
		}
947
948
		function __isset( $name ) {
949
			$value = $this->__get($name);
950
			return isset($value);
951
		}
952
953
		function __clone() {
954
			$this->parentNode = null;
955
		}
956
957
		function cloneNode( $recurse = false ) {
958
			return clone($this);
959
		}
960
961
		public function __clearParentIdCache() {
962
		}
963
964
		public function __restoreParentIdCache() {
965
		}
966
967
	}
968
969
	class ar_xmlElement extends ar_xmlNode implements ar_xmlNodeInterface {
970
		public $tagName     = null;
971
		public $attributes  = array();
972
		private $childNodes = null;
973
		private $parentNode  = null;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
974
		private $idCache    = array();
975
		private $nodeValue  = '';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
976
977
		function __construct($name, $attributes = null, $childNodes = null, $parentNode = null) {
978
			$this->tagName    = $name;
979
			$this->parentNode = $parentNode;
980
			$this->childNodes = $this->getNodeList();
981
			$this->childNodes->setParentNode( $this );
982
			if ($childNodes) {
983
				$this->appendChild( $childNodes );
984
			}
985
			if ($attributes) {
986
				$this->setAttributes( $attributes );
987
			}
988
		}
989
990 View Code Duplication
		public function __clearParentIdCache() {
991
			if ( isset($this->parentNode) && count( $this->idCache ) ) {
992
				foreach( $this->idCache as $id => $value ) {
993
					$this->parentNode->__updateIdCache($id, null, $value);
994
				}
995
			}
996
		}
997
998 View Code Duplication
		public function __restoreParentIdCache() {
999
			if ( isset($this->parentNode) && count( $this->idCache ) ) {
1000
				foreach( $this->idCache as $id => $value ) {
1001
					$this->parentNode->__updateIdCache($id, $value);
1002
				}
1003
			}
1004
		}
1005
1006
		public function __updateIdCache($id, $el, $oldEl = null) {
1007
			if ( !isset($el) ) {
1008
				// remove id cache entry
1009
				if ( isset($this->idCache[$id]) && ($this->idCache[$id]===$oldEl) ) {
1010
					// only remove id cache pointers to the correct element
1011
					unset($this->idCache[$id]);
1012
				}
1013
			} else {
1014
				$this->idCache[$id] = $el;
1015
			}
1016
			if (isset($this->parentNode) && $this->parentNode !== $this) { // Prevent loops if the parentNode is this object.
1017
				$this->parentNode->__updateIdCache($id, $el, $oldEl);
1018
			}
1019
		}
1020
1021
		function setAttributes( $attributes ) {
1022
			foreach ( $attributes as $name => $value ) {
1023
				$this->setAttribute( $name, $value );
1024
			}
1025
			return $this;
1026
		}
1027
1028
		function getAttribute( $name ) {
1029
			return $this->attributes[$name];
1030
		}
1031
1032
		function setAttribute( $name, $value ) {
1033
			if ( $name == 'id' ) {
1034
				$oldId = null;
1035
				if (isset($this->attributes['id'])) {
1036
					$oldId = $this->attributes['id'];
1037
				}
1038
			}
1039 View Code Duplication
			if ( is_array($value) && !isset($value[0]) ) {
1040
				// this bit of magic allows ar_xmlNodes->setAttribute to override only
1041
				// specific attribute values, leaving others alone, by specifying a
1042
				// non-number key.
1043
				if ( !is_array($this->attributes[$name]) ) {
1044
					$this->attributes[$name] = array( $this->attributes[$name] );
1045
				}
1046
				$this->attributes[$name] = array_merge( $this->attributes[$name], $value );
1047
			} else {
1048
				$this->attributes[$name] = $value;
1049
			}
1050
			if ('id'==(string)$name) { // string cast is necessary, otherwise if $name is 0, 'id' will be cast to int, which is also 0...
1051
				if ( isset($oldId) ) {
1052
					$this->__updateIdCache( $oldId, null, $this );
1053
				}
1054
				$this->__updateIdCache($value, $this);
1055
			}
1056
			return $this;
1057
		}
1058
1059
		function removeAttribute( $name ) {
1060
			if ( isset( $this->attributes[$name] ) ) {
1061
				unset( $this->attributes[$name] );
1062
			}
1063
		}
1064
1065
		function __toString() {
1066
			return $this->toString();
1067
		}
1068
1069
		function toString( $indent = '', $current = 0 ) {
1070
			$indent = ar_xml::$indenting ? $indent : '';
1071
			$result = "\n" . $indent . '<' . ar_xml::name( $this->tagName );
1072 View Code Duplication
			if ( is_array($this->attributes) ) {
1073
				foreach ( $this->attributes as $name => $value ) {
1074
					$result .= ar_xml::attribute($name, $value, $current);
1075
				}
1076
			} else if ( is_string($this->attributes) ) {
1077
				$result .= ltrim(' '.$this->attributes);
1078
			}
1079
			if ( $this->childNodes instanceof ar_xmlNodes && count($this->childNodes) ) {
1080
				$result .= '>';
1081
				$result .= $this->childNodes->toString( ar_xml::$indent . $indent );
1082
				if ( substr($result, -1) == ">") {
1083
					$result .= "\n" . $indent;
1084
				}
1085
				$result .= '</' . ar_xml::name( $this->tagName ) . '>';
1086
			} else {
1087
				$result .= ' />';
1088
			}
1089
			return $result;
1090
		}
1091
1092
		public function getNodeList() {
1093
			$params = func_get_args();
1094
			return call_user_func_array( array( 'ar_xml', 'nodes'), $params );
1095
		}
1096
1097
		function __get( $name ) {
1098
			switch( $name ) {
1099
				case 'parentNode':
1100
					return $this->parentNode;
1101
				break;
1102
				case 'firstChild':
1103
					if (isset($this->childNodes) && count($this->childNodes)) {
1104
						return $this->childNodes[0];
1105
					}
1106
				break;
1107
				case 'lastChild':
1108
					if (isset($this->childNodes) && count($this->childNodes)) {
1109
						return $this->childNodes[count($this->childNodes)-1];
1110
					}
1111
				break;
1112
				case 'childNodes':
1113
					return $this->childNodes;
1114
				break;
1115
				case 'nodeValue':
1116
					//echo get_class($this->childNodes[0]).'('.$this->childNodes[0].')';
1117
					if (isset($this->childNodes) && count($this->childNodes) ) {
1118
						return $this->childNodes->nodeValue;
1119
					}
1120
				break;
1121
			}
1122
			$result = parent::__get( $name );
1123
			if ( isset($result) ) {
1124
				return $result;
1125
			}
1126
			return $this->getElementsByTagName( $name, false );
1127
		}
1128
1129
		function __set( $name, $value ) {
1130
			switch ( $name ) {
1131
				case 'previousSibling':
1132
				case 'nextSibling':
1133
				break;
1134 View Code Duplication
				case 'parentNode':
1135
					if ( $value === $this || !($value instanceof ar_xmlElement) ) {
1136
						$this->parentNode = null;
1137
					} else {
1138
						$this->parentNode = $value;
1139
					}
1140
				break;
1141
				case 'nodeValue':
1142
					if ( isset($this->childNodes) && count($this->childNodes) ) {
1143
						$this->removeChild( $this->childNodes );
1144
					}
1145
					$this->appendChild( $value );
1146
				break;
1147
				case 'childNodes':
1148
					if ( !isset($value) ) {
1149
						$value = $this->getNodeList();
1150
					} else if ( !($value instanceof ar_xmlNodes) ) {
1151
						$value = $this->getNodeList($value);
1152
					}
1153
					$this->childNodes->setParentNode( null );
1154
					$this->childNodes = $value;
1155
					$this->childNodes->setParentNode( $this );
1156
				break;
1157
				default:
1158
					$nodeList = $this->__get( $name );
1159
					$this->replaceChild( $value, $nodeList );
1160
				break;
1161
			}
1162
		}
1163
1164
		function __clone() {
1165
			parent::__clone();
1166
			$this->childNodes = $this->getNodeList();
1167
		}
1168
1169
		function cloneNode( $recurse = false ) {
1170
			$childNodes = $this->childNodes->cloneNode( $recurse );
1171
			$result = parent::cloneNode( $recurse );
1172
			$result->childNodes = $childNodes;
1173
			return $result;
1174
		}
1175
1176
		function getElementsByTagName( $name , $recurse = true ) {
1177
			if ( isset( $this->childNodes ) ) {
1178
				return $this->childNodes->getElementsByTagName( $name, $recurse );
1179
			}
1180
		}
1181
1182
		function getElementById( $id ) {
1183
			if (isset($this->idCache[ (string) $id ])) {
1184
				return $this->idCache[ (string) $id ];
1185
			}
1186
		}
1187
1188
		function appendChild( $el ) {
1189
			return $this->childNodes->appendChild( $el );
1190
		}
1191
1192
		function insertBefore( $el, $referenceEl = null ) {
1193
			return $this->childNodes->insertBefore( $el, $referenceEl );
1194
		}
1195
1196
		function replaceChild( $el, $referenceEl ) {
1197
			return $this->childNodes->replaceChild( $el, $referenceEl );
1198
		}
1199
1200
		function removeChild( $el ) {
1201
			return $this->childNodes->removeChild( $el );
1202
		}
1203
1204
		public function bind( $nodes, $name, $type = 'string' ) {
1205
			$b = new ar_xmlDataBinding( );
1206
			return $b->bind( $nodes, $name, $type );
1207
		}
1208
1209
		public function bindAsArray( $nodes, $type = 'string' ) {
1210
			$b = new ar_xmlDataBinding( );
1211
			return $b->bindAsArray( $nodes, 'list', $type)->list;
0 ignored issues
show
The property list does not seem to exist in ar_xmlDataBinding.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1212
		}
1213
1214
	}
1215
1216
	class ar_xmlDataBinding extends arBase {
1217
1218
		public function bindAsArray( $nodes, $name, $type='string') {
1219
			$this->{$name} = array();
1220
1221
			foreach ( $nodes as $key => $node ) {
1222
				$this->{$name}[$key] = $this->bindValue( $node, $type);
1223
			}
1224
			return $this;
1225
		}
1226
1227
		public function bind( $node, $name, $type='string' ) {
1228
			if ( ( is_array($node) || ( $node instanceof Countable ) ) && count($node)>1 ) {
1229
				return $this->bindAsArray( $node, $name, $type );
1230
			}
1231
			$this->{$name} = $this->bindValue( $node, $type );
1232
			return $this;
1233
		}
1234
1235
		public function __toString() {
1236
			return $this->source->toString();
0 ignored issues
show
The property source does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
1237
		}
1238
1239
		protected function bindValue( $source, $type ) {
1240
			if ( $source instanceof ar_xmlNode || $source instanceof ar_xmlNodes ) {
1241
				$nodeValue = $source->nodeValue;
1242
				if (is_array($nodeValue) && !count($nodeValue)) {
1243
					$nodeValue = null;
1244
				}
1245
			} else {
1246
				$nodeValue = $source;
1247
			}
1248
			if ( is_callable($type) ) {
1249
				$nodeValue = call_user_func( $type, $source );
1250
			} else {
1251
				switch ($type) {
1252
					case 'int':
1253
						$nodeValue = (int) $nodeValue;
1254
					break;
1255
					case 'float':
1256
						$nodeValue = (float) $nodeValue;
1257
					break;
1258
					case 'string':
1259
						$nodeValue = (string) $nodeValue;
1260
					break;
1261
					case 'bool':
1262
						$nodeValue = (bool) $nodeValue;
1263
					break;
1264
					case 'url':
1265
						$nodeValue = ar::url( $nodeValue );
1266
					break;
1267
					case 'xml':
1268
					case 'html':
1269
						if ($source instanceof ar_xmlNode || $source instanceof ar_xmlNodes) {
1270
							$nodeValue = (string) $source;
1271
						}
1272
					break;
1273
					default:
1274
						if ( is_string($type) && class_exists($type) && ar_pinp::isAllowed($type, '__construct') ) {
1275
							$nodeValue = new $type($nodeValue);
1276
						}
1277
					break;
1278
				}
1279
			}
1280
			return $nodeValue;
1281
		}
1282
1283
	}
1284