This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Copyright 2014 Fabian Grutschus. All rights reserved. |
||
5 | * |
||
6 | * Redistribution and use in source and binary forms, with or without modification, |
||
7 | * are permitted provided that the following conditions are met: |
||
8 | * |
||
9 | * 1. Redistributions of source code must retain the above copyright notice, this |
||
10 | * list of conditions and the following disclaimer. |
||
11 | * |
||
12 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
13 | * this list of conditions and the following disclaimer in the documentation |
||
14 | * and/or other materials provided with the distribution. |
||
15 | * |
||
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
||
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
26 | * |
||
27 | * The views and conclusions contained in the software and documentation are those |
||
28 | * of the authors and should not be interpreted as representing official policies, |
||
29 | * either expressed or implied, of the copyright holders. |
||
30 | * |
||
31 | * @author Fabian Grutschus <[email protected]> |
||
32 | * @copyright 2014 Fabian Grutschus. All rights reserved. |
||
33 | * @license BSD |
||
34 | * @link http://github.com/fabiang/xmpp |
||
35 | */ |
||
36 | |||
37 | namespace Fabiang\Xmpp\Stream; |
||
38 | |||
39 | use Fabiang\Xmpp\Event\EventManagerAwareInterface; |
||
40 | use Fabiang\Xmpp\Event\EventManagerInterface; |
||
41 | use Fabiang\Xmpp\Event\EventManager; |
||
42 | use Fabiang\Xmpp\Event\XMLEvent; |
||
43 | use Fabiang\Xmpp\Event\XMLEventInterface; |
||
44 | use Fabiang\Xmpp\Exception\XMLParserException; |
||
45 | |||
46 | /** |
||
47 | * Xml stream class. |
||
48 | * |
||
49 | * @package Xmpp\Stream |
||
50 | */ |
||
51 | class XMLStream implements EventManagerAwareInterface |
||
52 | { |
||
53 | |||
54 | const NAMESPACE_SEPARATOR = ':'; |
||
55 | |||
56 | /** |
||
57 | * Eventmanager. |
||
58 | * |
||
59 | * @var EventManagerInterface |
||
60 | */ |
||
61 | protected $events; |
||
62 | |||
63 | /** |
||
64 | * Document encoding. |
||
65 | * |
||
66 | * @var string |
||
67 | */ |
||
68 | protected $encoding; |
||
69 | |||
70 | /** |
||
71 | * Current parsing depth. |
||
72 | * |
||
73 | * @var integer |
||
74 | */ |
||
75 | protected $depth = 0; |
||
76 | |||
77 | /** |
||
78 | * |
||
79 | * @var \DOMDocument |
||
80 | */ |
||
81 | protected $document; |
||
82 | |||
83 | /** |
||
84 | * Collected namespaces. |
||
85 | * |
||
86 | * @var array |
||
87 | */ |
||
88 | protected $namespaces = []; |
||
89 | |||
90 | /** |
||
91 | * Cache of namespace prefixes. |
||
92 | * |
||
93 | * @var array |
||
94 | */ |
||
95 | protected $namespacePrefixes = []; |
||
96 | |||
97 | /** |
||
98 | * Element cache. |
||
99 | * |
||
100 | * @var array |
||
101 | */ |
||
102 | protected $elements = []; |
||
103 | |||
104 | /** |
||
105 | * XML parser. |
||
106 | * |
||
107 | * @var resource |
||
108 | */ |
||
109 | protected $parser; |
||
110 | |||
111 | /** |
||
112 | * Event object. |
||
113 | * |
||
114 | * @var XMLEventInterface |
||
115 | */ |
||
116 | protected $eventObject; |
||
117 | |||
118 | /** |
||
119 | * Collected events while parsing. |
||
120 | * |
||
121 | * @var array |
||
122 | */ |
||
123 | protected $eventCache = []; |
||
124 | |||
125 | /** |
||
126 | * Constructor. |
||
127 | */ |
||
128 | 3 | public function __construct($encoding = 'UTF-8', XMLEventInterface $eventObject = null) |
|
129 | { |
||
130 | 3 | $this->encoding = $encoding; |
|
131 | 3 | $this->reset(); |
|
132 | |||
133 | 3 | if (null === $eventObject) { |
|
134 | 3 | $eventObject = new XMLEvent(); |
|
135 | 3 | } |
|
136 | |||
137 | 3 | $this->eventObject = $eventObject; |
|
138 | 3 | } |
|
139 | |||
140 | /** |
||
141 | * Free XML parser on desturct. |
||
142 | */ |
||
143 | public function __destruct() |
||
144 | { |
||
145 | xml_parser_free($this->parser); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Parse XML data and trigger events. |
||
150 | * |
||
151 | * @param string $source XML source |
||
152 | * @return \DOMDocument |
||
153 | */ |
||
154 | 21 | public function parse($source) |
|
155 | { |
||
156 | 21 | $this->clearDocument($source); |
|
157 | |||
158 | 21 | $this->eventCache = []; |
|
159 | 21 | if (0 === xml_parse($this->parser, $source, false)) { |
|
160 | 3 | throw XMLParserException::create($this->parser); |
|
161 | } |
||
162 | // trigger collected events. |
||
163 | 18 | $this->trigger(); |
|
164 | 18 | $this->eventCache = []; |
|
165 | |||
166 | // </stream> was not there, so lets close the document |
||
167 | 18 | if ($this->depth > 0) { |
|
168 | 12 | $this->document->appendChild($this->elements[0]); |
|
169 | 12 | } |
|
170 | |||
171 | 18 | return $this->document; |
|
172 | } |
||
173 | |||
174 | /** |
||
175 | * Clear document. |
||
176 | * |
||
177 | * Method resets the parser instance if <?xml is found. Overwise it clears the DOM document. |
||
178 | * |
||
179 | * @return void |
||
180 | */ |
||
181 | 6 | protected function clearDocument($source) |
|
182 | { |
||
183 | 6 | $documentElement = $this->document->documentElement; |
|
184 | |||
185 | // collect xml declaration |
||
186 | 6 | if ('<?xml' === substr($source, 0, 5)) { |
|
187 | 6 | $this->reset(); |
|
188 | |||
189 | 6 | $matches = []; |
|
190 | 6 | if (preg_match('/^<\?xml.*encoding=(\'|")([\w-]+)\1.*?>/i', $source, $matches)) { |
|
191 | 6 | $this->encoding = $matches[2]; |
|
192 | 6 | xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->encoding); |
|
193 | 6 | } |
|
194 | 6 | } elseif (null !== $documentElement) { |
|
195 | // clean the document |
||
196 | /* @var $childNode \DOMNode */ |
||
197 | 3 | while ($documentElement->hasChildNodes()) { |
|
198 | 3 | $documentElement->removeChild($documentElement->firstChild); |
|
199 | 3 | } |
|
200 | 3 | } |
|
201 | 6 | } |
|
202 | |||
203 | /** |
||
204 | * Starting tag found. |
||
205 | * |
||
206 | * @param resource $parser XML parser |
||
0 ignored issues
–
show
|
|||
207 | * @param string $name Element name |
||
0 ignored issues
–
show
There is no parameter named
$name . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
208 | * @param attribs $attribs Element attributes |
||
0 ignored issues
–
show
There is no parameter named
$attribs . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
209 | * @return void |
||
210 | */ |
||
211 | 3 | protected function startXml() |
|
212 | { |
||
213 | 3 | list (, $name, $attribs) = func_get_args(); |
|
214 | |||
215 | 3 | $elementData = explode(static::NAMESPACE_SEPARATOR, $name, 2); |
|
216 | 3 | $elementName = $elementData[0]; |
|
217 | 3 | $prefix = null; |
|
218 | 3 | if (isset($elementData[1])) { |
|
219 | 3 | $elementName = $elementData[1]; |
|
220 | 3 | $prefix = $elementData[0]; |
|
221 | 3 | } |
|
222 | |||
223 | 3 | $attributesNodes = $this->createAttributeNodes($attribs); |
|
224 | 3 | $namespaceAttrib = false; |
|
225 | |||
226 | // current namespace |
||
227 | 3 | if (array_key_exists('xmlns', $attribs)) { |
|
228 | 3 | $namespaceURI = $attribs['xmlns']; |
|
229 | 3 | } else { |
|
230 | 3 | $namespaceURI = $this->namespaces[$this->depth - 1]; |
|
231 | } |
||
232 | |||
233 | // namespace of the element |
||
234 | 3 | if (null !== $prefix) { |
|
235 | 3 | $namespaceElement = $this->namespacePrefixes[$prefix]; |
|
236 | 3 | } else { |
|
237 | 3 | $namespaceAttrib = true; |
|
238 | 3 | $namespaceElement = $namespaceURI; |
|
239 | } |
||
240 | |||
241 | 3 | $this->namespaces[$this->depth] = $namespaceURI; |
|
242 | |||
243 | // workaround for multiple xmlns defined, since we did have parent element inserted into the dom tree yet |
||
244 | 3 | if (true === $namespaceAttrib) { |
|
245 | 3 | $element = $this->document->createElement($elementName); |
|
246 | 3 | } else { |
|
247 | 3 | $elementNameFull = $elementName; |
|
248 | 3 | if (null !== $prefix) { |
|
249 | 3 | $elementNameFull = $prefix . static::NAMESPACE_SEPARATOR . $elementName; |
|
250 | 3 | } |
|
251 | |||
252 | 3 | $element = $this->document->createElementNS($namespaceElement, $elementNameFull); |
|
253 | } |
||
254 | |||
255 | 3 | foreach ($attributesNodes as $attributeNode) { |
|
256 | 3 | $element->setAttributeNode($attributeNode); |
|
257 | 3 | } |
|
258 | |||
259 | 3 | $this->elements[$this->depth] = $element; |
|
260 | 3 | $this->depth++; |
|
261 | |||
262 | 3 | $event = '{' . $namespaceElement . '}' . $elementName; |
|
263 | 3 | $this->cacheEvent($event, true, [$element]); |
|
264 | 3 | } |
|
265 | |||
266 | /** |
||
267 | * Turn attribes into attribute nodes. |
||
268 | * |
||
269 | * @param array $attribs Attributes |
||
270 | * @return array |
||
271 | */ |
||
272 | 3 | protected function createAttributeNodes(array $attribs) |
|
273 | { |
||
274 | 3 | $attributesNodes = []; |
|
275 | 3 | foreach ($attribs as $name => $value) { |
|
276 | // collect namespace prefixes |
||
277 | 3 | if ('xmlns:' === substr($name, 0, 6)) { |
|
278 | 3 | $prefix = substr($name, 6); |
|
279 | |||
280 | 3 | $this->namespacePrefixes[$prefix] = $value; |
|
281 | 3 | } else { |
|
282 | 3 | $attribute = $this->document->createAttribute($name); |
|
283 | 3 | $attribute->value = $value; |
|
284 | 3 | $attributesNodes[] = $attribute; |
|
285 | } |
||
286 | 3 | } |
|
287 | 3 | return $attributesNodes; |
|
288 | } |
||
289 | |||
290 | /** |
||
291 | * End tag found. |
||
292 | * |
||
293 | * @return void |
||
294 | */ |
||
295 | 6 | protected function endXml() |
|
296 | { |
||
297 | 6 | $this->depth--; |
|
298 | |||
299 | 6 | $element = $this->elements[$this->depth]; |
|
300 | |||
301 | 6 | if ($this->depth > 0) { |
|
302 | 6 | $parent = $this->elements[$this->depth - 1]; |
|
303 | 6 | } else { |
|
304 | 3 | $parent = $this->document; |
|
305 | } |
||
306 | 6 | $parent->appendChild($element); |
|
307 | |||
308 | 6 | $localName = $element->localName; |
|
309 | |||
310 | // Frist: try to get the namespace from element. |
||
311 | 6 | $namespaceURI = $element->namespaceURI; |
|
312 | |||
313 | // Second: loop over namespaces till namespace is not null |
||
314 | 6 | if (null === $namespaceURI) { |
|
315 | 3 | $namespaceURI = $this->namespaces[$this->depth]; |
|
316 | 3 | } |
|
317 | |||
318 | 6 | $event = '{' . $namespaceURI . '}' . $localName; |
|
319 | 6 | $this->cacheEvent($event, false, [$element]); |
|
320 | 6 | } |
|
321 | |||
322 | /** |
||
323 | * Data found. |
||
324 | * |
||
325 | * @param resource $parser XML parser |
||
0 ignored issues
–
show
There is no parameter named
$parser . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
326 | * @param string $data Element data |
||
0 ignored issues
–
show
There is no parameter named
$data . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
327 | * @return void |
||
328 | */ |
||
329 | 3 | protected function dataXml() |
|
330 | { |
||
331 | 3 | $data = func_get_arg(1); |
|
332 | 3 | if (isset($this->elements[$this->depth - 1])) { |
|
333 | 3 | $element = $this->elements[$this->depth - 1]; |
|
334 | 3 | $element->appendChild($this->document->createTextNode($data)); |
|
335 | 3 | } |
|
336 | 3 | } |
|
337 | |||
338 | /** |
||
339 | * Add event to cache. |
||
340 | * |
||
341 | * @param string $event |
||
342 | * @param boolean $startTag |
||
343 | * @param array $params |
||
344 | * @return void |
||
345 | */ |
||
346 | 3 | protected function cacheEvent($event, $startTag, $params) |
|
347 | { |
||
348 | 3 | $this->eventCache[] = [$event, $startTag, $params]; |
|
349 | 3 | } |
|
350 | |||
351 | /** |
||
352 | * Trigger cached events |
||
353 | * |
||
354 | * @return void |
||
355 | */ |
||
356 | 3 | protected function trigger() |
|
357 | { |
||
358 | 3 | foreach ($this->eventCache as $event) { |
|
359 | 3 | list($event, $startTag, $param) = $event; |
|
360 | 3 | $this->eventObject->setStartTag($startTag); |
|
361 | 3 | $this->getEventManager()->setEventObject($this->eventObject); |
|
362 | 3 | $this->getEventManager()->trigger($event, $this, $param); |
|
363 | 3 | } |
|
364 | 3 | } |
|
365 | |||
366 | /** |
||
367 | * Reset class properties. |
||
368 | * |
||
369 | * @return void |
||
370 | */ |
||
371 | 3 | public function reset() |
|
372 | { |
||
373 | 3 | $parser = xml_parser_create($this->encoding); |
|
374 | 3 | xml_set_object($parser, $this); |
|
375 | |||
376 | 3 | xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); |
|
377 | 3 | xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); |
|
378 | |||
379 | 3 | xml_set_element_handler($parser, 'startXml', 'endXml'); |
|
380 | 3 | xml_set_character_data_handler($parser, 'dataXml'); |
|
381 | |||
382 | 3 | $this->parser = $parser; |
|
383 | 3 | $this->depth = 0; |
|
384 | 3 | $this->document = new \DOMDocument('1.0', $this->encoding); |
|
385 | 3 | $this->namespaces = []; |
|
386 | 3 | $this->namespacePrefixes = []; |
|
387 | 3 | $this->elements = []; |
|
388 | 3 | } |
|
389 | |||
390 | /** |
||
391 | * Get XML parser resource. |
||
392 | * |
||
393 | * @return resource |
||
394 | */ |
||
395 | public function getParser() |
||
396 | { |
||
397 | return $this->parser; |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * {@inheritDoc} |
||
402 | */ |
||
403 | 6 | public function getEventManager() |
|
404 | { |
||
405 | 6 | if (null === $this->events) { |
|
406 | 6 | $this->setEventManager(new EventManager()); |
|
407 | 6 | } |
|
408 | |||
409 | 6 | return $this->events; |
|
410 | } |
||
411 | |||
412 | /** |
||
413 | * {@inheritDoc} |
||
414 | */ |
||
415 | 6 | public function setEventManager(EventManagerInterface $events) |
|
416 | { |
||
417 | 6 | $this->events = $events; |
|
418 | 6 | $events->setEventObject($this->getEventObject()); |
|
419 | 6 | return $this; |
|
420 | } |
||
421 | |||
422 | /** |
||
423 | * Get event object. |
||
424 | * |
||
425 | * @return XMLEventInterface |
||
426 | */ |
||
427 | 3 | public function getEventObject() |
|
428 | { |
||
429 | 3 | return $this->eventObject; |
|
430 | } |
||
431 | |||
432 | /** |
||
433 | * Set event object. |
||
434 | * |
||
435 | * @param XMLEventInterface $eventObject |
||
436 | * @return $this |
||
437 | */ |
||
438 | public function setEventObject(XMLEventInterface $eventObject) |
||
439 | { |
||
440 | $this->eventObject = $eventObject; |
||
441 | return $this; |
||
442 | } |
||
443 | } |
||
444 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.