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 | use dokuwiki\HTTP\DokuHTTPClient; |
||
0 ignored issues
–
show
|
|||
4 | |||
5 | /** |
||
6 | * IXR - The Incutio XML-RPC Library |
||
7 | * |
||
8 | * Copyright (c) 2010, Incutio Ltd. |
||
9 | * All rights reserved. |
||
10 | * |
||
11 | * Redistribution and use in source and binary forms, with or without |
||
12 | * modification, are permitted provided that the following conditions are met: |
||
13 | * |
||
14 | * - Redistributions of source code must retain the above copyright notice, |
||
15 | * this list of conditions and the following disclaimer. |
||
16 | * - Redistributions in binary form must reproduce the above copyright |
||
17 | * notice, this list of conditions and the following disclaimer in the |
||
18 | * documentation and/or other materials provided with the distribution. |
||
19 | * - Neither the name of Incutio Ltd. nor the names of its contributors |
||
20 | * may be used to endorse or promote products derived from this software |
||
21 | * without specific prior written permission. |
||
22 | * |
||
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||
24 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||
25 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||
26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
||
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
28 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||
29 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||
30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
||
31 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
||
33 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
34 | * |
||
35 | * @package IXR |
||
36 | * @since 1.5 |
||
37 | * |
||
38 | * @copyright Incutio Ltd 2010 (http://www.incutio.com) |
||
39 | * @version 1.7.4 7th September 2010 |
||
40 | * @author Simon Willison |
||
41 | * @link http://scripts.incutio.com/xmlrpc/ Site/manual |
||
42 | * |
||
43 | * Modified for DokuWiki |
||
44 | * @author Andreas Gohr <[email protected]> |
||
45 | */ |
||
46 | class IXR_Value { |
||
47 | |||
48 | /** @var IXR_Value[]|IXR_Date|IXR_Base64|int|bool|double|string */ |
||
49 | var $data; |
||
50 | /** @var string */ |
||
51 | var $type; |
||
52 | |||
53 | /** |
||
54 | * @param mixed $data |
||
55 | * @param bool $type |
||
56 | */ |
||
57 | function __construct($data, $type = false) { |
||
0 ignored issues
–
show
|
|||
58 | $this->data = $data; |
||
59 | if(!$type) { |
||
60 | $type = $this->calculateType(); |
||
61 | } |
||
62 | $this->type = $type; |
||
0 ignored issues
–
show
It seems like
$type can also be of type boolean . However, the property $type is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
63 | if($type == 'struct') { |
||
64 | // Turn all the values in the array in to new IXR_Value objects |
||
65 | foreach($this->data as $key => $value) { |
||
66 | $this->data[$key] = new IXR_Value($value); |
||
67 | } |
||
68 | } |
||
69 | if($type == 'array') { |
||
70 | for($i = 0, $j = count($this->data); $i < $j; $i++) { |
||
71 | $this->data[$i] = new IXR_Value($this->data[$i]); |
||
72 | } |
||
73 | } |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * @return string |
||
78 | */ |
||
79 | function calculateType() { |
||
0 ignored issues
–
show
|
|||
80 | if($this->data === true || $this->data === false) { |
||
81 | return 'boolean'; |
||
82 | } |
||
83 | if(is_integer($this->data)) { |
||
84 | return 'int'; |
||
85 | } |
||
86 | if(is_double($this->data)) { |
||
87 | return 'double'; |
||
88 | } |
||
89 | |||
90 | // Deal with IXR object types base64 and date |
||
91 | if(is_object($this->data) && is_a($this->data, 'IXR_Date')) { |
||
92 | return 'date'; |
||
93 | } |
||
94 | if(is_object($this->data) && is_a($this->data, 'IXR_Base64')) { |
||
95 | return 'base64'; |
||
96 | } |
||
97 | |||
98 | // If it is a normal PHP object convert it in to a struct |
||
99 | if(is_object($this->data)) { |
||
100 | $this->data = get_object_vars($this->data); |
||
101 | return 'struct'; |
||
102 | } |
||
103 | if(!is_array($this->data)) { |
||
104 | return 'string'; |
||
105 | } |
||
106 | |||
107 | // We have an array - is it an array or a struct? |
||
108 | if($this->isStruct($this->data)) { |
||
109 | return 'struct'; |
||
110 | } else { |
||
111 | return 'array'; |
||
112 | } |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * @return bool|string |
||
117 | */ |
||
118 | function getXml() { |
||
0 ignored issues
–
show
|
|||
119 | // Return XML for this value |
||
120 | switch($this->type) { |
||
121 | case 'boolean': |
||
122 | return '<boolean>' . (($this->data) ? '1' : '0') . '</boolean>'; |
||
123 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
124 | case 'int': |
||
125 | return '<int>' . $this->data . '</int>'; |
||
126 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
127 | case 'double': |
||
128 | return '<double>' . $this->data . '</double>'; |
||
129 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
130 | case 'string': |
||
131 | return '<string>' . htmlspecialchars($this->data) . '</string>'; |
||
132 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
133 | case 'array': |
||
134 | $return = '<array><data>' . "\n"; |
||
135 | foreach($this->data as $item) { |
||
0 ignored issues
–
show
The expression
$this->data of type array<integer,object<IXR...r|boolean|double|string is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
136 | $return .= ' <value>' . $item->getXml() . "</value>\n"; |
||
137 | } |
||
138 | $return .= '</data></array>'; |
||
139 | return $return; |
||
140 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
141 | case 'struct': |
||
142 | $return = '<struct>' . "\n"; |
||
143 | foreach($this->data as $name => $value) { |
||
0 ignored issues
–
show
The expression
$this->data of type array<integer,object<IXR...r|boolean|double|string is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
144 | $return .= " <member><name>$name</name><value>"; |
||
145 | $return .= $value->getXml() . "</value></member>\n"; |
||
146 | } |
||
147 | $return .= '</struct>'; |
||
148 | return $return; |
||
149 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
150 | case 'date': |
||
151 | case 'base64': |
||
152 | return $this->data->getXml(); |
||
153 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
154 | } |
||
155 | return false; |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Checks whether or not the supplied array is a struct or not |
||
160 | * |
||
161 | * @param array $array |
||
162 | * @return boolean |
||
163 | */ |
||
164 | function isStruct($array) { |
||
0 ignored issues
–
show
|
|||
165 | $expected = 0; |
||
166 | foreach($array as $key => $value) { |
||
167 | if((string) $key != (string) $expected) { |
||
168 | return true; |
||
169 | } |
||
170 | $expected++; |
||
171 | } |
||
172 | return false; |
||
173 | } |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * IXR_MESSAGE |
||
178 | * |
||
179 | * @package IXR |
||
180 | * @since 1.5 |
||
181 | * |
||
182 | */ |
||
183 | class IXR_Message { |
||
184 | var $message; |
||
185 | var $messageType; // methodCall / methodResponse / fault |
||
186 | var $faultCode; |
||
187 | var $faultString; |
||
188 | var $methodName; |
||
189 | var $params; |
||
190 | |||
191 | // Current variable stacks |
||
192 | var $_arraystructs = array(); // The stack used to keep track of the current array/struct |
||
193 | var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array |
||
194 | var $_currentStructName = array(); // A stack as well |
||
195 | var $_param; |
||
196 | var $_value; |
||
197 | var $_currentTag; |
||
198 | var $_currentTagContents; |
||
199 | var $_lastseen; |
||
200 | // The XML parser |
||
201 | var $_parser; |
||
202 | |||
203 | /** |
||
204 | * @param string $message |
||
205 | */ |
||
206 | function __construct($message) { |
||
0 ignored issues
–
show
|
|||
207 | $this->message =& $message; |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * @return bool |
||
212 | */ |
||
213 | function parse() { |
||
0 ignored issues
–
show
|
|||
214 | // first remove the XML declaration |
||
215 | // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages |
||
216 | $header = preg_replace('/<\?xml.*?\?' . '>/', '', substr($this->message, 0, 100), 1); |
||
217 | $this->message = substr_replace($this->message, $header, 0, 100); |
||
218 | |||
219 | // workaround for a bug in PHP/libxml2, see http://bugs.php.net/bug.php?id=45996 |
||
220 | $this->message = str_replace('<', '<', $this->message); |
||
221 | $this->message = str_replace('>', '>', $this->message); |
||
222 | $this->message = str_replace('&', '&', $this->message); |
||
223 | $this->message = str_replace(''', ''', $this->message); |
||
224 | $this->message = str_replace('"', '"', $this->message); |
||
225 | $this->message = str_replace("\x0b", ' ', $this->message); //vertical tab |
||
226 | if(trim($this->message) == '') { |
||
227 | return false; |
||
228 | } |
||
229 | $this->_parser = xml_parser_create(); |
||
230 | // Set XML parser to take the case of tags in to account |
||
231 | xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); |
||
232 | // Set XML parser callback functions |
||
233 | xml_set_object($this->_parser, $this); |
||
234 | xml_set_element_handler($this->_parser, 'tag_open', 'tag_close'); |
||
235 | xml_set_character_data_handler($this->_parser, 'cdata'); |
||
236 | $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages |
||
237 | $final = false; |
||
238 | do { |
||
239 | if(strlen($this->message) <= $chunk_size) { |
||
240 | $final = true; |
||
241 | } |
||
242 | $part = substr($this->message, 0, $chunk_size); |
||
243 | $this->message = substr($this->message, $chunk_size); |
||
244 | if(!xml_parse($this->_parser, $part, $final)) { |
||
245 | return false; |
||
246 | } |
||
247 | if($final) { |
||
248 | break; |
||
249 | } |
||
250 | } while(true); |
||
251 | xml_parser_free($this->_parser); |
||
252 | |||
253 | // Grab the error messages, if any |
||
254 | if($this->messageType == 'fault') { |
||
255 | $this->faultCode = $this->params[0]['faultCode']; |
||
256 | $this->faultString = $this->params[0]['faultString']; |
||
257 | } |
||
258 | return true; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * @param $parser |
||
263 | * @param string $tag |
||
264 | * @param $attr |
||
265 | */ |
||
266 | function tag_open($parser, $tag, $attr) { |
||
0 ignored issues
–
show
|
|||
267 | $this->_currentTagContents = ''; |
||
268 | $this->_currentTag = $tag; |
||
269 | |||
270 | switch($tag) { |
||
271 | case 'methodCall': |
||
272 | case 'methodResponse': |
||
273 | case 'fault': |
||
274 | $this->messageType = $tag; |
||
275 | break; |
||
276 | /* Deal with stacks of arrays and structs */ |
||
277 | case 'data': // data is to all intents and purposes more interesting than array |
||
278 | $this->_arraystructstypes[] = 'array'; |
||
279 | $this->_arraystructs[] = array(); |
||
280 | break; |
||
281 | case 'struct': |
||
282 | $this->_arraystructstypes[] = 'struct'; |
||
283 | $this->_arraystructs[] = array(); |
||
284 | break; |
||
285 | } |
||
286 | $this->_lastseen = $tag; |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * @param $parser |
||
291 | * @param string $cdata |
||
292 | */ |
||
293 | function cdata($parser, $cdata) { |
||
0 ignored issues
–
show
|
|||
294 | $this->_currentTagContents .= $cdata; |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * @param $parser |
||
299 | * @param $tag |
||
300 | */ |
||
301 | function tag_close($parser, $tag) { |
||
0 ignored issues
–
show
|
|||
302 | $value = null; |
||
303 | $valueFlag = false; |
||
304 | switch($tag) { |
||
305 | case 'int': |
||
306 | case 'i4': |
||
307 | $value = (int) trim($this->_currentTagContents); |
||
308 | $valueFlag = true; |
||
309 | break; |
||
310 | case 'double': |
||
311 | $value = (double) trim($this->_currentTagContents); |
||
312 | $valueFlag = true; |
||
313 | break; |
||
314 | case 'string': |
||
315 | $value = (string) $this->_currentTagContents; |
||
316 | $valueFlag = true; |
||
317 | break; |
||
318 | case 'dateTime.iso8601': |
||
319 | $value = new IXR_Date(trim($this->_currentTagContents)); |
||
320 | $valueFlag = true; |
||
321 | break; |
||
322 | case 'value': |
||
323 | // "If no type is indicated, the type is string." |
||
324 | if($this->_lastseen == 'value') { |
||
325 | $value = (string) $this->_currentTagContents; |
||
326 | $valueFlag = true; |
||
327 | } |
||
328 | break; |
||
329 | case 'boolean': |
||
330 | $value = (boolean) trim($this->_currentTagContents); |
||
331 | $valueFlag = true; |
||
332 | break; |
||
333 | case 'base64': |
||
334 | $value = base64_decode($this->_currentTagContents); |
||
335 | $valueFlag = true; |
||
336 | break; |
||
337 | /* Deal with stacks of arrays and structs */ |
||
338 | case 'data': |
||
339 | case 'struct': |
||
340 | $value = array_pop($this->_arraystructs); |
||
341 | array_pop($this->_arraystructstypes); |
||
342 | $valueFlag = true; |
||
343 | break; |
||
344 | case 'member': |
||
345 | array_pop($this->_currentStructName); |
||
346 | break; |
||
347 | case 'name': |
||
348 | $this->_currentStructName[] = trim($this->_currentTagContents); |
||
349 | break; |
||
350 | case 'methodName': |
||
351 | $this->methodName = trim($this->_currentTagContents); |
||
352 | break; |
||
353 | } |
||
354 | |||
355 | if($valueFlag) { |
||
356 | if(count($this->_arraystructs) > 0) { |
||
357 | // Add value to struct or array |
||
358 | if($this->_arraystructstypes[count($this->_arraystructstypes) - 1] == 'struct') { |
||
359 | // Add to struct |
||
360 | $this->_arraystructs[count($this->_arraystructs) - 1][$this->_currentStructName[count($this->_currentStructName) - 1]] = $value; |
||
361 | } else { |
||
362 | // Add to array |
||
363 | $this->_arraystructs[count($this->_arraystructs) - 1][] = $value; |
||
364 | } |
||
365 | } else { |
||
366 | // Just add as a parameter |
||
367 | $this->params[] = $value; |
||
368 | } |
||
369 | } |
||
370 | $this->_currentTagContents = ''; |
||
371 | $this->_lastseen = $tag; |
||
372 | } |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * IXR_Server |
||
377 | * |
||
378 | * @package IXR |
||
379 | * @since 1.5 |
||
380 | */ |
||
381 | class IXR_Server { |
||
382 | var $data; |
||
383 | /** @var array */ |
||
384 | var $callbacks = array(); |
||
385 | var $message; |
||
386 | /** @var array */ |
||
387 | var $capabilities; |
||
388 | |||
389 | /** |
||
390 | * @param array|bool $callbacks |
||
391 | * @param bool $data |
||
392 | * @param bool $wait |
||
393 | */ |
||
394 | function __construct($callbacks = false, $data = false, $wait = false) { |
||
0 ignored issues
–
show
|
|||
395 | $this->setCapabilities(); |
||
396 | if($callbacks) { |
||
397 | $this->callbacks = $callbacks; |
||
0 ignored issues
–
show
It seems like
$callbacks can also be of type boolean . However, the property $callbacks is declared as type array . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
398 | } |
||
399 | $this->setCallbacks(); |
||
400 | |||
401 | if(!$wait) { |
||
402 | $this->serve($data); |
||
403 | } |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * @param bool|string $data |
||
408 | */ |
||
409 | function serve($data = false) { |
||
0 ignored issues
–
show
|
|||
410 | if(!$data) { |
||
411 | |||
412 | $postData = trim(http_get_raw_post_data()); |
||
413 | if(!$postData) { |
||
414 | header('Content-Type: text/plain'); // merged from WP #9093 |
||
415 | die('XML-RPC server accepts POST requests only.'); |
||
416 | } |
||
417 | $data = $postData; |
||
418 | } |
||
419 | $this->message = new IXR_Message($data); |
||
0 ignored issues
–
show
It seems like
$data defined by parameter $data on line 409 can also be of type boolean ; however, IXR_Message::__construct() does only seem to accept string , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
420 | if(!$this->message->parse()) { |
||
421 | $this->error(-32700, 'parse error. not well formed'); |
||
422 | } |
||
423 | if($this->message->messageType != 'methodCall') { |
||
424 | $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall'); |
||
425 | } |
||
426 | $result = $this->call($this->message->methodName, $this->message->params); |
||
427 | |||
428 | // Is the result an error? |
||
429 | if(is_a($result, 'IXR_Error')) { |
||
430 | $this->error($result); |
||
431 | } |
||
432 | |||
433 | // Encode the result |
||
434 | $r = new IXR_Value($result); |
||
435 | $resultxml = $r->getXml(); |
||
436 | |||
437 | // Create the XML |
||
438 | $xml = <<<EOD |
||
439 | <methodResponse> |
||
440 | <params> |
||
441 | <param> |
||
442 | <value> |
||
443 | $resultxml |
||
444 | </value> |
||
445 | </param> |
||
446 | </params> |
||
447 | </methodResponse> |
||
448 | |||
449 | EOD; |
||
450 | // Send it |
||
451 | $this->output($xml); |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * @param string $methodname |
||
456 | * @param array $args |
||
457 | * @return IXR_Error|mixed |
||
458 | */ |
||
459 | function call($methodname, $args) { |
||
0 ignored issues
–
show
|
|||
460 | if(!$this->hasMethod($methodname)) { |
||
461 | return new IXR_Error(-32601, 'server error. requested method ' . $methodname . ' does not exist.'); |
||
462 | } |
||
463 | $method = $this->callbacks[$methodname]; |
||
464 | |||
465 | // Perform the callback and send the response |
||
466 | |||
467 | # Removed for DokuWiki to have a more consistent interface |
||
468 | # if (count($args) == 1) { |
||
469 | # // If only one parameter just send that instead of the whole array |
||
470 | # $args = $args[0]; |
||
471 | # } |
||
472 | |||
473 | # Adjusted for DokuWiki to use call_user_func_array |
||
474 | |||
475 | // args need to be an array |
||
476 | $args = (array) $args; |
||
477 | |||
478 | // Are we dealing with a function or a method? |
||
479 | if(is_string($method) && substr($method, 0, 5) == 'this:') { |
||
480 | // It's a class method - check it exists |
||
481 | $method = substr($method, 5); |
||
482 | if(!method_exists($this, $method)) { |
||
483 | return new IXR_Error(-32601, 'server error. requested class method "' . $method . '" does not exist.'); |
||
484 | } |
||
485 | // Call the method |
||
486 | #$result = $this->$method($args); |
||
487 | $result = call_user_func_array(array(&$this, $method), $args); |
||
488 | } elseif(substr($method, 0, 7) == 'plugin:') { |
||
489 | list($pluginname, $callback) = explode(':', substr($method, 7), 2); |
||
490 | if(!plugin_isdisabled($pluginname)) { |
||
491 | $plugin = plugin_load('action', $pluginname); |
||
492 | return call_user_func_array(array($plugin, $callback), $args); |
||
493 | } else { |
||
494 | return new IXR_Error(-99999, 'server error'); |
||
495 | } |
||
496 | } else { |
||
497 | // It's a function - does it exist? |
||
498 | if(is_array($method)) { |
||
499 | if(!is_callable(array($method[0], $method[1]))) { |
||
500 | return new IXR_Error(-32601, 'server error. requested object method "' . $method[1] . '" does not exist.'); |
||
501 | } |
||
502 | } else if(!function_exists($method)) { |
||
503 | return new IXR_Error(-32601, 'server error. requested function "' . $method . '" does not exist.'); |
||
504 | } |
||
505 | |||
506 | // Call the function |
||
507 | $result = call_user_func($method, $args); |
||
508 | } |
||
509 | return $result; |
||
510 | } |
||
511 | |||
512 | /** |
||
513 | * @param int $error |
||
514 | * @param string|bool $message |
||
515 | */ |
||
516 | function error($error, $message = false) { |
||
0 ignored issues
–
show
|
|||
517 | // Accepts either an error object or an error code and message |
||
518 | if($message && !is_object($error)) { |
||
519 | $error = new IXR_Error($error, $message); |
||
0 ignored issues
–
show
It seems like
$message defined by parameter $message on line 516 can also be of type boolean ; however, IXR_Error::__construct() does only seem to accept string , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
520 | } |
||
521 | $this->output($error->getXml()); |
||
0 ignored issues
–
show
It seems like
$error is not always an object, but can also be of type integer . Maybe add an additional type check?
If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe: function someFunction(A $objectMaybe = null)
{
if ($objectMaybe instanceof A) {
$objectMaybe->doSomething();
}
}
![]() |
|||
522 | } |
||
523 | |||
524 | /** |
||
525 | * @param string $xml |
||
526 | */ |
||
527 | function output($xml) { |
||
0 ignored issues
–
show
|
|||
528 | header('Content-Type: text/xml; charset=utf-8'); |
||
529 | echo '<?xml version="1.0"?>', "\n", $xml; |
||
530 | exit; |
||
531 | } |
||
532 | |||
533 | /** |
||
534 | * @param string $method |
||
535 | * @return bool |
||
536 | */ |
||
537 | function hasMethod($method) { |
||
0 ignored issues
–
show
|
|||
538 | return in_array($method, array_keys($this->callbacks)); |
||
539 | } |
||
540 | |||
541 | function setCapabilities() { |
||
0 ignored issues
–
show
|
|||
542 | // Initialises capabilities array |
||
543 | $this->capabilities = array( |
||
544 | 'xmlrpc' => array( |
||
545 | 'specUrl' => 'http://www.xmlrpc.com/spec', |
||
546 | 'specVersion' => 1 |
||
547 | ), |
||
548 | 'faults_interop' => array( |
||
549 | 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', |
||
550 | 'specVersion' => 20010516 |
||
551 | ), |
||
552 | 'system.multicall' => array( |
||
553 | 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', |
||
554 | 'specVersion' => 1 |
||
555 | ), |
||
556 | ); |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * @return mixed |
||
561 | */ |
||
562 | function getCapabilities() { |
||
0 ignored issues
–
show
|
|||
563 | return $this->capabilities; |
||
564 | } |
||
565 | |||
566 | function setCallbacks() { |
||
0 ignored issues
–
show
|
|||
567 | $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; |
||
568 | $this->callbacks['system.listMethods'] = 'this:listMethods'; |
||
569 | $this->callbacks['system.multicall'] = 'this:multiCall'; |
||
570 | } |
||
571 | |||
572 | /** |
||
573 | * @return array |
||
574 | */ |
||
575 | function listMethods() { |
||
0 ignored issues
–
show
|
|||
576 | // Returns a list of methods - uses array_reverse to ensure user defined |
||
577 | // methods are listed before server defined methods |
||
578 | return array_reverse(array_keys($this->callbacks)); |
||
579 | } |
||
580 | |||
581 | /** |
||
582 | * @param array $methodcalls |
||
583 | * @return array |
||
584 | */ |
||
585 | function multiCall($methodcalls) { |
||
0 ignored issues
–
show
|
|||
586 | // See http://www.xmlrpc.com/discuss/msgReader$1208 |
||
587 | $return = array(); |
||
588 | foreach($methodcalls as $call) { |
||
589 | $method = $call['methodName']; |
||
590 | $params = $call['params']; |
||
591 | if($method == 'system.multicall') { |
||
592 | $result = new IXR_Error(-32800, 'Recursive calls to system.multicall are forbidden'); |
||
593 | } else { |
||
594 | $result = $this->call($method, $params); |
||
595 | } |
||
596 | if(is_a($result, 'IXR_Error')) { |
||
597 | $return[] = array( |
||
598 | 'faultCode' => $result->code, |
||
599 | 'faultString' => $result->message |
||
600 | ); |
||
601 | } else { |
||
602 | $return[] = array($result); |
||
603 | } |
||
604 | } |
||
605 | return $return; |
||
606 | } |
||
607 | } |
||
608 | |||
609 | /** |
||
610 | * IXR_Request |
||
611 | * |
||
612 | * @package IXR |
||
613 | * @since 1.5 |
||
614 | */ |
||
615 | class IXR_Request { |
||
616 | /** @var string */ |
||
617 | var $method; |
||
618 | /** @var array */ |
||
619 | var $args; |
||
620 | /** @var string */ |
||
621 | var $xml; |
||
622 | |||
623 | /** |
||
624 | * @param string $method |
||
625 | * @param array $args |
||
626 | */ |
||
627 | function __construct($method, $args) { |
||
0 ignored issues
–
show
|
|||
628 | $this->method = $method; |
||
629 | $this->args = $args; |
||
630 | $this->xml = <<<EOD |
||
631 | <?xml version="1.0"?> |
||
632 | <methodCall> |
||
633 | <methodName>{$this->method}</methodName> |
||
634 | <params> |
||
635 | |||
636 | EOD; |
||
637 | foreach($this->args as $arg) { |
||
638 | $this->xml .= '<param><value>'; |
||
639 | $v = new IXR_Value($arg); |
||
640 | $this->xml .= $v->getXml(); |
||
641 | $this->xml .= "</value></param>\n"; |
||
642 | } |
||
643 | $this->xml .= '</params></methodCall>'; |
||
644 | } |
||
645 | |||
646 | /** |
||
647 | * @return int |
||
648 | */ |
||
649 | function getLength() { |
||
0 ignored issues
–
show
|
|||
650 | return strlen($this->xml); |
||
651 | } |
||
652 | |||
653 | /** |
||
654 | * @return string |
||
655 | */ |
||
656 | function getXml() { |
||
0 ignored issues
–
show
|
|||
657 | return $this->xml; |
||
658 | } |
||
659 | } |
||
660 | |||
661 | /** |
||
662 | * IXR_Client |
||
663 | * |
||
664 | * @package IXR |
||
665 | * @since 1.5 |
||
666 | * |
||
667 | * Changed for DokuWiki to use DokuHTTPClient |
||
668 | * |
||
669 | * This should be compatible to the original class, but uses DokuWiki's |
||
670 | * HTTP client library which will respect proxy settings |
||
671 | * |
||
672 | * Because the XMLRPC client is not used in DokuWiki currently this is completely |
||
673 | * untested |
||
674 | */ |
||
675 | class IXR_Client extends DokuHTTPClient { |
||
676 | var $posturl = ''; |
||
677 | /** @var IXR_Message|bool */ |
||
678 | var $message = false; |
||
679 | |||
680 | // Storage place for an error message |
||
681 | /** @var IXR_Error|bool */ |
||
682 | var $xmlerror = false; |
||
683 | |||
684 | /** |
||
685 | * @param string $server |
||
686 | * @param string|bool $path |
||
687 | * @param int $port |
||
688 | * @param int $timeout |
||
689 | */ |
||
690 | function __construct($server, $path = false, $port = 80, $timeout = 15) { |
||
0 ignored issues
–
show
|
|||
691 | parent::__construct(); |
||
692 | if(!$path) { |
||
693 | // Assume we have been given a URL instead |
||
694 | $this->posturl = $server; |
||
695 | } else { |
||
696 | $this->posturl = 'http://' . $server . ':' . $port . $path; |
||
697 | } |
||
698 | $this->timeout = $timeout; |
||
699 | } |
||
700 | |||
701 | /** |
||
702 | * parameters: method and arguments |
||
703 | * @return bool success or error |
||
704 | */ |
||
705 | function query() { |
||
0 ignored issues
–
show
|
|||
706 | $args = func_get_args(); |
||
707 | $method = array_shift($args); |
||
708 | $request = new IXR_Request($method, $args); |
||
709 | $xml = $request->getXml(); |
||
710 | |||
711 | $this->headers['Content-Type'] = 'text/xml'; |
||
712 | if(!$this->sendRequest($this->posturl, $xml, 'POST')) { |
||
713 | $this->xmlerror = new IXR_Error(-32300, 'transport error - ' . $this->error); |
||
714 | return false; |
||
715 | } |
||
716 | |||
717 | // Check HTTP Response code |
||
718 | if($this->status < 200 || $this->status > 206) { |
||
719 | $this->xmlerror = new IXR_Error(-32300, 'transport error - HTTP status ' . $this->status); |
||
720 | return false; |
||
721 | } |
||
722 | |||
723 | // Now parse what we've got back |
||
724 | $this->message = new IXR_Message($this->resp_body); |
||
725 | if(!$this->message->parse()) { |
||
726 | // XML error |
||
727 | $this->xmlerror = new IXR_Error(-32700, 'parse error. not well formed'); |
||
728 | return false; |
||
729 | } |
||
730 | |||
731 | // Is the message a fault? |
||
732 | if($this->message->messageType == 'fault') { |
||
733 | $this->xmlerror = new IXR_Error($this->message->faultCode, $this->message->faultString); |
||
734 | return false; |
||
735 | } |
||
736 | |||
737 | // Message must be OK |
||
738 | return true; |
||
739 | } |
||
740 | |||
741 | /** |
||
742 | * @return mixed |
||
743 | */ |
||
744 | function getResponse() { |
||
0 ignored issues
–
show
|
|||
745 | // methodResponses can only have one param - return that |
||
746 | return $this->message->params[0]; |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * @return bool |
||
751 | */ |
||
752 | function isError() { |
||
0 ignored issues
–
show
|
|||
753 | return (is_object($this->xmlerror)); |
||
754 | } |
||
755 | |||
756 | /** |
||
757 | * @return int |
||
758 | */ |
||
759 | function getErrorCode() { |
||
0 ignored issues
–
show
|
|||
760 | return $this->xmlerror->code; |
||
761 | } |
||
762 | |||
763 | /** |
||
764 | * @return string |
||
765 | */ |
||
766 | function getErrorMessage() { |
||
0 ignored issues
–
show
|
|||
767 | return $this->xmlerror->message; |
||
768 | } |
||
769 | } |
||
770 | |||
771 | /** |
||
772 | * IXR_Error |
||
773 | * |
||
774 | * @package IXR |
||
775 | * @since 1.5 |
||
776 | */ |
||
777 | class IXR_Error { |
||
778 | var $code; |
||
779 | var $message; |
||
780 | |||
781 | /** |
||
782 | * @param int $code |
||
783 | * @param string $message |
||
784 | */ |
||
785 | function __construct($code, $message) { |
||
0 ignored issues
–
show
|
|||
786 | $this->code = $code; |
||
787 | $this->message = htmlspecialchars($message); |
||
788 | } |
||
789 | |||
790 | /** |
||
791 | * @return string |
||
792 | */ |
||
793 | function getXml() { |
||
0 ignored issues
–
show
|
|||
794 | $xml = <<<EOD |
||
795 | <methodResponse> |
||
796 | <fault> |
||
797 | <value> |
||
798 | <struct> |
||
799 | <member> |
||
800 | <name>faultCode</name> |
||
801 | <value><int>{$this->code}</int></value> |
||
802 | </member> |
||
803 | <member> |
||
804 | <name>faultString</name> |
||
805 | <value><string>{$this->message}</string></value> |
||
806 | </member> |
||
807 | </struct> |
||
808 | </value> |
||
809 | </fault> |
||
810 | </methodResponse> |
||
811 | |||
812 | EOD; |
||
813 | return $xml; |
||
814 | } |
||
815 | } |
||
816 | |||
817 | /** |
||
818 | * IXR_Date |
||
819 | * |
||
820 | * @package IXR |
||
821 | * @since 1.5 |
||
822 | */ |
||
823 | class IXR_Date { |
||
824 | |||
825 | const XMLRPC_ISO8601 = "Ymd\TH:i:sO" ; |
||
826 | /** @var DateTime */ |
||
827 | protected $date; |
||
828 | |||
829 | /** |
||
830 | * @param int|string $time |
||
831 | */ |
||
832 | public function __construct($time) { |
||
833 | // $time can be a PHP timestamp or an ISO one |
||
834 | if(is_numeric($time)) { |
||
835 | $this->parseTimestamp($time); |
||
836 | } else { |
||
837 | $this->parseIso($time); |
||
838 | } |
||
839 | } |
||
840 | |||
841 | /** |
||
842 | * Parse unix timestamp |
||
843 | * |
||
844 | * @param int $timestamp |
||
845 | */ |
||
846 | protected function parseTimestamp($timestamp) { |
||
847 | $this->date = new DateTime('@' . $timestamp); |
||
848 | } |
||
849 | |||
850 | /** |
||
851 | * Parses less or more complete iso dates and much more, if no timezone given assumes UTC |
||
852 | * |
||
853 | * @param string $iso |
||
854 | */ |
||
855 | protected function parseIso($iso) { |
||
856 | $this->date = new DateTime($iso, new DateTimeZone("UTC")); |
||
857 | } |
||
858 | |||
859 | /** |
||
860 | * Returns date in ISO 8601 format |
||
861 | * |
||
862 | * @return string |
||
863 | */ |
||
864 | public function getIso() { |
||
865 | return $this->date->format(self::XMLRPC_ISO8601); |
||
866 | } |
||
867 | |||
868 | /** |
||
869 | * Returns date in valid xml |
||
870 | * |
||
871 | * @return string |
||
872 | */ |
||
873 | public function getXml() { |
||
874 | return '<dateTime.iso8601>' . $this->getIso() . '</dateTime.iso8601>'; |
||
875 | } |
||
876 | |||
877 | /** |
||
878 | * Returns Unix timestamp |
||
879 | * |
||
880 | * @return int |
||
881 | */ |
||
882 | function getTimestamp() { |
||
0 ignored issues
–
show
|
|||
883 | return $this->date->getTimestamp(); |
||
884 | } |
||
885 | } |
||
886 | |||
887 | /** |
||
888 | * IXR_Base64 |
||
889 | * |
||
890 | * @package IXR |
||
891 | * @since 1.5 |
||
892 | */ |
||
893 | class IXR_Base64 { |
||
894 | var $data; |
||
895 | |||
896 | /** |
||
897 | * @param string $data |
||
898 | */ |
||
899 | function __construct($data) { |
||
0 ignored issues
–
show
|
|||
900 | $this->data = $data; |
||
901 | } |
||
902 | |||
903 | /** |
||
904 | * @return string |
||
905 | */ |
||
906 | function getXml() { |
||
0 ignored issues
–
show
|
|||
907 | return '<base64>' . base64_encode($this->data) . '</base64>'; |
||
908 | } |
||
909 | } |
||
910 | |||
911 | /** |
||
912 | * IXR_IntrospectionServer |
||
913 | * |
||
914 | * @package IXR |
||
915 | * @since 1.5 |
||
916 | */ |
||
917 | class IXR_IntrospectionServer extends IXR_Server { |
||
918 | /** @var array[] */ |
||
919 | var $signatures; |
||
920 | /** @var string[] */ |
||
921 | var $help; |
||
922 | |||
923 | /** |
||
924 | * Constructor |
||
925 | */ |
||
926 | function __construct() { |
||
0 ignored issues
–
show
|
|||
927 | $this->setCallbacks(); |
||
928 | $this->setCapabilities(); |
||
929 | $this->capabilities['introspection'] = array( |
||
930 | 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', |
||
931 | 'specVersion' => 1 |
||
932 | ); |
||
933 | $this->addCallback( |
||
934 | 'system.methodSignature', |
||
935 | 'this:methodSignature', |
||
936 | array('array', 'string'), |
||
937 | 'Returns an array describing the return type and required parameters of a method' |
||
938 | ); |
||
939 | $this->addCallback( |
||
940 | 'system.getCapabilities', |
||
941 | 'this:getCapabilities', |
||
942 | array('struct'), |
||
943 | 'Returns a struct describing the XML-RPC specifications supported by this server' |
||
944 | ); |
||
945 | $this->addCallback( |
||
946 | 'system.listMethods', |
||
947 | 'this:listMethods', |
||
948 | array('array'), |
||
949 | 'Returns an array of available methods on this server' |
||
950 | ); |
||
951 | $this->addCallback( |
||
952 | 'system.methodHelp', |
||
953 | 'this:methodHelp', |
||
954 | array('string', 'string'), |
||
955 | 'Returns a documentation string for the specified method' |
||
956 | ); |
||
957 | } |
||
958 | |||
959 | /** |
||
960 | * @param string $method |
||
961 | * @param string $callback |
||
962 | * @param string[] $args |
||
963 | * @param string $help |
||
964 | */ |
||
965 | function addCallback($method, $callback, $args, $help) { |
||
0 ignored issues
–
show
|
|||
966 | $this->callbacks[$method] = $callback; |
||
967 | $this->signatures[$method] = $args; |
||
968 | $this->help[$method] = $help; |
||
969 | } |
||
970 | |||
971 | /** |
||
972 | * @param string $methodname |
||
973 | * @param array $args |
||
974 | * @return IXR_Error|mixed |
||
975 | */ |
||
976 | function call($methodname, $args) { |
||
0 ignored issues
–
show
|
|||
977 | // Make sure it's in an array |
||
978 | if($args && !is_array($args)) { |
||
0 ignored issues
–
show
The expression
$args of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
979 | $args = array($args); |
||
980 | } |
||
981 | |||
982 | // Over-rides default call method, adds signature check |
||
983 | if(!$this->hasMethod($methodname)) { |
||
984 | return new IXR_Error(-32601, 'server error. requested method "' . $this->message->methodName . '" not specified.'); |
||
985 | } |
||
986 | $method = $this->callbacks[$methodname]; |
||
0 ignored issues
–
show
$method is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
987 | $signature = $this->signatures[$methodname]; |
||
988 | $returnType = array_shift($signature); |
||
0 ignored issues
–
show
$returnType is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
989 | // Check the number of arguments. Check only, if the minimum count of parameters is specified. More parameters are possible. |
||
990 | // This is a hack to allow optional parameters... |
||
991 | if(count($args) < count($signature)) { |
||
992 | // print 'Num of args: '.count($args).' Num in signature: '.count($signature); |
||
993 | return new IXR_Error(-32602, 'server error. wrong number of method parameters'); |
||
994 | } |
||
995 | |||
996 | // Check the argument types |
||
997 | $ok = true; |
||
998 | $argsbackup = $args; |
||
999 | for($i = 0, $j = count($args); $i < $j; $i++) { |
||
1000 | $arg = array_shift($args); |
||
1001 | $type = array_shift($signature); |
||
1002 | switch($type) { |
||
1003 | case 'int': |
||
1004 | case 'i4': |
||
1005 | if(is_array($arg) || !is_int($arg)) { |
||
1006 | $ok = false; |
||
1007 | } |
||
1008 | break; |
||
1009 | case 'base64': |
||
1010 | case 'string': |
||
1011 | if(!is_string($arg)) { |
||
1012 | $ok = false; |
||
1013 | } |
||
1014 | break; |
||
1015 | case 'boolean': |
||
1016 | if($arg !== false && $arg !== true) { |
||
1017 | $ok = false; |
||
1018 | } |
||
1019 | break; |
||
1020 | case 'float': |
||
1021 | case 'double': |
||
1022 | if(!is_float($arg)) { |
||
1023 | $ok = false; |
||
1024 | } |
||
1025 | break; |
||
1026 | case 'date': |
||
1027 | case 'dateTime.iso8601': |
||
1028 | if(!is_a($arg, 'IXR_Date')) { |
||
1029 | $ok = false; |
||
1030 | } |
||
1031 | break; |
||
1032 | } |
||
1033 | if(!$ok) { |
||
1034 | return new IXR_Error(-32602, 'server error. invalid method parameters'); |
||
1035 | } |
||
1036 | } |
||
1037 | // It passed the test - run the "real" method call |
||
1038 | return parent::call($methodname, $argsbackup); |
||
1039 | } |
||
1040 | |||
1041 | /** |
||
1042 | * @param string $method |
||
1043 | * @return array|IXR_Error |
||
1044 | */ |
||
1045 | function methodSignature($method) { |
||
0 ignored issues
–
show
|
|||
1046 | if(!$this->hasMethod($method)) { |
||
1047 | return new IXR_Error(-32601, 'server error. requested method "' . $method . '" not specified.'); |
||
1048 | } |
||
1049 | // We should be returning an array of types |
||
1050 | $types = $this->signatures[$method]; |
||
1051 | $return = array(); |
||
1052 | foreach($types as $type) { |
||
1053 | switch($type) { |
||
1054 | case 'string': |
||
1055 | $return[] = 'string'; |
||
1056 | break; |
||
1057 | case 'int': |
||
1058 | case 'i4': |
||
1059 | $return[] = 42; |
||
1060 | break; |
||
1061 | case 'double': |
||
1062 | $return[] = 3.1415; |
||
1063 | break; |
||
1064 | case 'dateTime.iso8601': |
||
1065 | $return[] = new IXR_Date(time()); |
||
1066 | break; |
||
1067 | case 'boolean': |
||
1068 | $return[] = true; |
||
1069 | break; |
||
1070 | case 'base64': |
||
1071 | $return[] = new IXR_Base64('base64'); |
||
1072 | break; |
||
1073 | case 'array': |
||
1074 | $return[] = array('array'); |
||
1075 | break; |
||
1076 | case 'struct': |
||
1077 | $return[] = array('struct' => 'struct'); |
||
1078 | break; |
||
1079 | } |
||
1080 | } |
||
1081 | return $return; |
||
1082 | } |
||
1083 | |||
1084 | /** |
||
1085 | * @param string $method |
||
1086 | * @return mixed |
||
1087 | */ |
||
1088 | function methodHelp($method) { |
||
0 ignored issues
–
show
|
|||
1089 | return $this->help[$method]; |
||
1090 | } |
||
1091 | } |
||
1092 | |||
1093 | /** |
||
1094 | * IXR_ClientMulticall |
||
1095 | * |
||
1096 | * @package IXR |
||
1097 | * @since 1.5 |
||
1098 | */ |
||
1099 | class IXR_ClientMulticall extends IXR_Client { |
||
1100 | |||
1101 | /** @var array[] */ |
||
1102 | var $calls = array(); |
||
1103 | |||
1104 | /** |
||
1105 | * @param string $server |
||
1106 | * @param string|bool $path |
||
1107 | * @param int $port |
||
1108 | */ |
||
1109 | function __construct($server, $path = false, $port = 80) { |
||
0 ignored issues
–
show
|
|||
1110 | parent::__construct($server, $path, $port); |
||
1111 | //$this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)'; |
||
1112 | } |
||
1113 | |||
1114 | /** |
||
1115 | * Add a call |
||
1116 | */ |
||
1117 | function addCall() { |
||
0 ignored issues
–
show
|
|||
1118 | $args = func_get_args(); |
||
1119 | $methodName = array_shift($args); |
||
1120 | $struct = array( |
||
1121 | 'methodName' => $methodName, |
||
1122 | 'params' => $args |
||
1123 | ); |
||
1124 | $this->calls[] = $struct; |
||
1125 | } |
||
1126 | |||
1127 | /** |
||
1128 | * @return bool |
||
1129 | */ |
||
1130 | function query() { |
||
0 ignored issues
–
show
|
|||
1131 | // Prepare multicall, then call the parent::query() method |
||
1132 | return parent::query('system.multicall', $this->calls); |
||
1133 | } |
||
1134 | } |
||
1135 | |||
1136 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: