Issues (994)

src/shim/JSLikeHTMLElement.php (2 issues)

1
<?php
2
3
/**
4
 * JavaScript-like HTML DOM Element.
5
 *
6
 * This class extends PHP's DOMElement to allow
7
 * users to get and set the innerHTML property of
8
 * HTML elements in the same way it's done in
9
 * JavaScript.
10
 *
11
 * Example usage:
12
 *
13
 * ```php
14
 * require_once 'JSLikeHTMLElement.php';
15
 * header('Content-Type: text/plain');
16
 * $doc = new DOMDocument();
17
 * $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
18
 * $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
19
 * $elem = $doc->getElementsByTagName('div')->item(0);
20
 *
21
 * // print innerHTML
22
 * echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>'
23
 * echo "\n\n";
24
 *
25
 * // set innerHTML
26
 * $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>';
27
 * echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>'
28
 * echo "\n\n";
29
 *
30
 * // print document (with our changes)
31
 * echo $doc->saveXML();
32
 * ```
33
 *
34
 * @author Keyvan Minoukadeh - http://www.keyvan.net - [email protected]
35
 *
36
 * @see http://fivefilters.org (the project this was written for)
37
 */
38
class JSLikeHTMLElement extends DOMElement
39
{
40
	/**
41
	 * Used for setting innerHTML like it's done in JavaScript:.
42
	 *
43
	 * @code
44
	 * $div->innerHTML = '<h2>Chapter 2</h2><p>The story begins...</p>';
45
	 * @endcode
46
	 */
47
	public function __set($name, $value)
48
	{
49
		if ('innerHTML' == $name) {
50
			// first, empty the element
51
			for ($x = $this->childNodes->length - 1; $x >= 0; --$x) {
52
				$this->removeChild($this->childNodes->item($x));
53
			}
54
			// $value holds our new inner HTML
55
			if ('' != $value) {
56
				$f = $this->ownerDocument->createDocumentFragment();
0 ignored issues
show
The method createDocumentFragment() does not exist on null. ( Ignorable by Annotation )

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

56
				/** @scrutinizer ignore-call */ 
57
    $f = $this->ownerDocument->createDocumentFragment();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
57
				// appendXML() expects well-formed markup (XHTML)
58
				$result = @$f->appendXML($value); // @ to suppress PHP warnings
59
				if ($result) {
60
					if ($f->hasChildNodes()) {
61
						$this->appendChild($f);
62
					}
63
				} else {
64
					// $value is probably ill-formed
65
					$f = new DOMDocument();
66
					$value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
67
					// Using <htmlfragment> will generate a warning, but so will bad HTML
68
					// (and by this point, bad HTML is what we've got).
69
					// We use it (and suppress the warning) because an HTML fragment will
70
					// be wrapped around <html><body> tags which we don't really want to keep.
71
					// Note: despite the warning, if loadHTML succeeds it will return true.
72
					$result = @$f->loadHTML('<htmlfragment>' . $value . '</htmlfragment>');
0 ignored issues
show
Are you sure $value of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

72
					$result = @$f->loadHTML('<htmlfragment>' . /** @scrutinizer ignore-type */ $value . '</htmlfragment>');
Loading history...
73
					if ($result) {
74
						$import = $f->getElementsByTagName('htmlfragment')->item(0);
75
						foreach ($import->childNodes as $child) {
76
							$importedNode = $this->ownerDocument->importNode($child, true);
77
							$this->appendChild($importedNode);
78
						}
79
					} else {
80
						// oh well, we tried, we really did. :(
81
						// this element is now empty
82
					}
83
				}
84
			}
85
		} else {
86
			$trace = debug_backtrace();
87
			trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE);
88
		}
89
	}
90
91
	/**
92
	 * Used for getting innerHTML like it's done in JavaScript:.
93
	 *
94
	 * @code
95
	 * $string = $div->innerHTML;
96
	 * @endcode
97
	 */
98
	public function __get($name)
99
	{
100
		if ('innerHTML' == $name) {
101
			$inner = '';
102
			foreach ($this->childNodes as $child) {
103
				$inner .= $this->ownerDocument->saveXML($child);
104
			}
105
106
			return $inner;
107
		}
108
109
		$trace = debug_backtrace();
110
		trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE);
111
112
		return null;
113
	}
114
115
	public function __toString()
116
	{
117
		return '[' . $this->tagName . ']';
118
	}
119
}
120