Failed Conditions
Push — master ( cbaf27...ca549e )
by Andreas
04:42
created

IXR_IntrospectionServer::call()   D

Complexity

Conditions 23
Paths 82

Size

Total Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
nc 82
nop 2
dl 0
loc 64
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * IXR - The Incutio XML-RPC Library
5
 *
6
 * Copyright (c) 2010, Incutio Ltd.
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions are met:
11
 *
12
 *  - Redistributions of source code must retain the above copyright notice,
13
 *    this list of conditions and the following disclaimer.
14
 *  - Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *  - Neither the name of Incutio Ltd. nor the names of its contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 *
33
 * @package IXR
34
 * @since 1.5
35
 *
36
 * @copyright  Incutio Ltd 2010 (http://www.incutio.com)
37
 * @version    1.7.4 7th September 2010
38
 * @author     Simon Willison
39
 * @link       http://scripts.incutio.com/xmlrpc/ Site/manual
40
 *
41
 * Modified for DokuWiki
42
 * @author  Andreas Gohr <[email protected]>
43
 */
44
class IXR_Value {
45
46
    /** @var  IXR_Value[]|IXR_Date|IXR_Base64|int|bool|double|string */
47
    var $data;
48
    /** @var string */
49
    var $type;
50
51
    /**
52
     * @param mixed $data
53
     * @param bool $type
54
     */
55
    function __construct($data, $type = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
56
        $this->data = $data;
57
        if(!$type) {
58
            $type = $this->calculateType();
59
        }
60
        $this->type = $type;
0 ignored issues
show
Documentation Bug introduced by
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 $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

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;
}
Loading history...
61
        if($type == 'struct') {
62
            // Turn all the values in the array in to new IXR_Value objects
63
            foreach($this->data as $key => $value) {
64
                $this->data[$key] = new IXR_Value($value);
65
            }
66
        }
67
        if($type == 'array') {
68
            for($i = 0, $j = count($this->data); $i < $j; $i++) {
69
                $this->data[$i] = new IXR_Value($this->data[$i]);
70
            }
71
        }
72
    }
73
74
    /**
75
     * @return string
76
     */
77
    function calculateType() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
78
        if($this->data === true || $this->data === false) {
79
            return 'boolean';
80
        }
81
        if(is_integer($this->data)) {
82
            return 'int';
83
        }
84
        if(is_double($this->data)) {
85
            return 'double';
86
        }
87
88
        // Deal with IXR object types base64 and date
89
        if(is_object($this->data) && is_a($this->data, 'IXR_Date')) {
90
            return 'date';
91
        }
92
        if(is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
93
            return 'base64';
94
        }
95
96
        // If it is a normal PHP object convert it in to a struct
97
        if(is_object($this->data)) {
98
            $this->data = get_object_vars($this->data);
99
            return 'struct';
100
        }
101
        if(!is_array($this->data)) {
102
            return 'string';
103
        }
104
105
        // We have an array - is it an array or a struct?
106
        if($this->isStruct($this->data)) {
107
            return 'struct';
108
        } else {
109
            return 'array';
110
        }
111
    }
112
113
    /**
114
     * @return bool|string
115
     */
116
    function getXml() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
117
        // Return XML for this value
118
        switch($this->type) {
119
            case 'boolean':
120
                return '<boolean>' . (($this->data) ? '1' : '0') . '</boolean>';
121
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
122
            case 'int':
123
                return '<int>' . $this->data . '</int>';
124
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
125
            case 'double':
126
                return '<double>' . $this->data . '</double>';
127
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
128
            case 'string':
129
                return '<string>' . htmlspecialchars($this->data) . '</string>';
130
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
131
            case 'array':
132
                $return = '<array><data>' . "\n";
133
                foreach($this->data as $item) {
0 ignored issues
show
Bug introduced by
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.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
134
                    $return .= '  <value>' . $item->getXml() . "</value>\n";
135
                }
136
                $return .= '</data></array>';
137
                return $return;
138
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
139
            case 'struct':
140
                $return = '<struct>' . "\n";
141
                foreach($this->data as $name => $value) {
0 ignored issues
show
Bug introduced by
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.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
142
                    $return .= "  <member><name>$name</name><value>";
143
                    $return .= $value->getXml() . "</value></member>\n";
144
                }
145
                $return .= '</struct>';
146
                return $return;
147
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
148
            case 'date':
149
            case 'base64':
150
                return $this->data->getXml();
151
                break;
0 ignored issues
show
Unused Code introduced by
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.

Loading history...
152
        }
153
        return false;
154
    }
155
156
    /**
157
     * Checks whether or not the supplied array is a struct or not
158
     *
159
     * @param array $array
160
     * @return boolean
161
     */
162
    function isStruct($array) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
163
        $expected = 0;
164
        foreach($array as $key => $value) {
165
            if((string) $key != (string) $expected) {
166
                return true;
167
            }
168
            $expected++;
169
        }
170
        return false;
171
    }
172
}
173
174
/**
175
 * IXR_MESSAGE
176
 *
177
 * @package IXR
178
 * @since 1.5
179
 *
180
 */
181
class IXR_Message {
182
    var $message;
183
    var $messageType; // methodCall / methodResponse / fault
184
    var $faultCode;
185
    var $faultString;
186
    var $methodName;
187
    var $params;
188
189
    // Current variable stacks
190
    var $_arraystructs = array(); // The stack used to keep track of the current array/struct
191
    var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
192
    var $_currentStructName = array(); // A stack as well
193
    var $_param;
194
    var $_value;
195
    var $_currentTag;
196
    var $_currentTagContents;
197
    var $_lastseen;
198
    // The XML parser
199
    var $_parser;
200
201
    /**
202
     * @param string $message
203
     */
204
    function __construct($message) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
205
        $this->message =& $message;
206
    }
207
208
    /**
209
     * @return bool
210
     */
211
    function parse() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
212
        // first remove the XML declaration
213
        // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
214
        $header = preg_replace('/<\?xml.*?\?' . '>/', '', substr($this->message, 0, 100), 1);
215
        $this->message = substr_replace($this->message, $header, 0, 100);
216
217
        // workaround for a bug in PHP/libxml2, see http://bugs.php.net/bug.php?id=45996
218
        $this->message = str_replace('&lt;', '&#60;', $this->message);
219
        $this->message = str_replace('&gt;', '&#62;', $this->message);
220
        $this->message = str_replace('&amp;', '&#38;', $this->message);
221
        $this->message = str_replace('&apos;', '&#39;', $this->message);
222
        $this->message = str_replace('&quot;', '&#34;', $this->message);
223
        $this->message = str_replace("\x0b", ' ', $this->message); //vertical tab
224
        if(trim($this->message) == '') {
225
            return false;
226
        }
227
        $this->_parser = xml_parser_create();
228
        // Set XML parser to take the case of tags in to account
229
        xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
230
        // Set XML parser callback functions
231
        xml_set_object($this->_parser, $this);
232
        xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
233
        xml_set_character_data_handler($this->_parser, 'cdata');
234
        $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages
235
        $final = false;
236
        do {
237
            if(strlen($this->message) <= $chunk_size) {
238
                $final = true;
239
            }
240
            $part = substr($this->message, 0, $chunk_size);
241
            $this->message = substr($this->message, $chunk_size);
242
            if(!xml_parse($this->_parser, $part, $final)) {
243
                return false;
244
            }
245
            if($final) {
246
                break;
247
            }
248
        } while(true);
249
        xml_parser_free($this->_parser);
250
251
        // Grab the error messages, if any
252
        if($this->messageType == 'fault') {
253
            $this->faultCode = $this->params[0]['faultCode'];
254
            $this->faultString = $this->params[0]['faultString'];
255
        }
256
        return true;
257
    }
258
259
    /**
260
     * @param $parser
261
     * @param string $tag
262
     * @param $attr
263
     */
264
    function tag_open($parser, $tag, $attr) {
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $attr is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
265
        $this->_currentTagContents = '';
266
        $this->_currentTag = $tag;
267
268
        switch($tag) {
269
            case 'methodCall':
270
            case 'methodResponse':
271
            case 'fault':
272
                $this->messageType = $tag;
273
                break;
274
            /* Deal with stacks of arrays and structs */
275
            case 'data': // data is to all intents and purposes more interesting than array
276
                $this->_arraystructstypes[] = 'array';
277
                $this->_arraystructs[] = array();
278
                break;
279
            case 'struct':
280
                $this->_arraystructstypes[] = 'struct';
281
                $this->_arraystructs[] = array();
282
                break;
283
        }
284
        $this->_lastseen = $tag;
285
    }
286
287
    /**
288
     * @param $parser
289
     * @param string $cdata
290
     */
291
    function cdata($parser, $cdata) {
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
292
        $this->_currentTagContents .= $cdata;
293
    }
294
295
    /**
296
     * @param $parser
297
     * @param $tag
298
     */
299
    function tag_close($parser, $tag) {
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
300
        $value = null;
301
        $valueFlag = false;
302
        switch($tag) {
303
            case 'int':
304
            case 'i4':
305
                $value = (int) trim($this->_currentTagContents);
306
                $valueFlag = true;
307
                break;
308
            case 'double':
309
                $value = (double) trim($this->_currentTagContents);
310
                $valueFlag = true;
311
                break;
312
            case 'string':
313
                $value = (string) $this->_currentTagContents;
314
                $valueFlag = true;
315
                break;
316
            case 'dateTime.iso8601':
317
                $value = new IXR_Date(trim($this->_currentTagContents));
318
                $valueFlag = true;
319
                break;
320
            case 'value':
321
                // "If no type is indicated, the type is string."
322
                if($this->_lastseen == 'value') {
323
                    $value = (string) $this->_currentTagContents;
324
                    $valueFlag = true;
325
                }
326
                break;
327
            case 'boolean':
328
                $value = (boolean) trim($this->_currentTagContents);
329
                $valueFlag = true;
330
                break;
331
            case 'base64':
332
                $value = base64_decode($this->_currentTagContents);
333
                $valueFlag = true;
334
                break;
335
            /* Deal with stacks of arrays and structs */
336
            case 'data':
337
            case 'struct':
338
                $value = array_pop($this->_arraystructs);
339
                array_pop($this->_arraystructstypes);
340
                $valueFlag = true;
341
                break;
342
            case 'member':
343
                array_pop($this->_currentStructName);
344
                break;
345
            case 'name':
346
                $this->_currentStructName[] = trim($this->_currentTagContents);
347
                break;
348
            case 'methodName':
349
                $this->methodName = trim($this->_currentTagContents);
350
                break;
351
        }
352
353
        if($valueFlag) {
354
            if(count($this->_arraystructs) > 0) {
355
                // Add value to struct or array
356
                if($this->_arraystructstypes[count($this->_arraystructstypes) - 1] == 'struct') {
357
                    // Add to struct
358
                    $this->_arraystructs[count($this->_arraystructs) - 1][$this->_currentStructName[count($this->_currentStructName) - 1]] = $value;
359
                } else {
360
                    // Add to array
361
                    $this->_arraystructs[count($this->_arraystructs) - 1][] = $value;
362
                }
363
            } else {
364
                // Just add as a parameter
365
                $this->params[] = $value;
366
            }
367
        }
368
        $this->_currentTagContents = '';
369
        $this->_lastseen = $tag;
370
    }
371
}
372
373
/**
374
 * IXR_Server
375
 *
376
 * @package IXR
377
 * @since 1.5
378
 */
379
class IXR_Server {
380
    var $data;
381
    /** @var array */
382
    var $callbacks = array();
383
    var $message;
384
    /** @var array */
385
    var $capabilities;
386
387
    /**
388
     * @param array|bool $callbacks
389
     * @param bool $data
390
     * @param bool $wait
391
     */
392
    function __construct($callbacks = false, $data = false, $wait = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
393
        $this->setCapabilities();
394
        if($callbacks) {
395
            $this->callbacks = $callbacks;
0 ignored issues
show
Documentation Bug introduced by
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 $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

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;
}
Loading history...
396
        }
397
        $this->setCallbacks();
398
399
        if(!$wait) {
400
            $this->serve($data);
401
        }
402
    }
403
404
    /**
405
     * @param bool|string $data
406
     */
407
    function serve($data = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
408
        if(!$data) {
409
410
            $postData = trim(http_get_raw_post_data());
411
            if(!$postData) {
412
                header('Content-Type: text/plain'); // merged from WP #9093
413
                die('XML-RPC server accepts POST requests only.');
414
            }
415
            $data = $postData;
416
        }
417
        $this->message = new IXR_Message($data);
0 ignored issues
show
Bug introduced by
It seems like $data defined by parameter $data on line 407 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.

Loading history...
418
        if(!$this->message->parse()) {
419
            $this->error(-32700, 'parse error. not well formed');
420
        }
421
        if($this->message->messageType != 'methodCall') {
422
            $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
423
        }
424
        $result = $this->call($this->message->methodName, $this->message->params);
425
426
        // Is the result an error?
427
        if(is_a($result, 'IXR_Error')) {
428
            $this->error($result);
429
        }
430
431
        // Encode the result
432
        $r = new IXR_Value($result);
433
        $resultxml = $r->getXml();
434
435
        // Create the XML
436
        $xml = <<<EOD
437
<methodResponse>
438
  <params>
439
    <param>
440
      <value>
441
        $resultxml
442
      </value>
443
    </param>
444
  </params>
445
</methodResponse>
446
447
EOD;
448
        // Send it
449
        $this->output($xml);
450
    }
451
452
    /**
453
     * @param string $methodname
454
     * @param array $args
455
     * @return IXR_Error|mixed
456
     */
457
    function call($methodname, $args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
458
        if(!$this->hasMethod($methodname)) {
459
            return new IXR_Error(-32601, 'server error. requested method ' . $methodname . ' does not exist.');
460
        }
461
        $method = $this->callbacks[$methodname];
462
463
        // Perform the callback and send the response
464
465
        # Removed for DokuWiki to have a more consistent interface
466
        #        if (count($args) == 1) {
467
        #            // If only one parameter just send that instead of the whole array
468
        #            $args = $args[0];
469
        #        }
470
471
        # Adjusted for DokuWiki to use call_user_func_array
472
473
        // args need to be an array
474
        $args = (array) $args;
475
476
        // Are we dealing with a function or a method?
477
        if(is_string($method) && substr($method, 0, 5) == 'this:') {
478
            // It's a class method - check it exists
479
            $method = substr($method, 5);
480
            if(!method_exists($this, $method)) {
481
                return new IXR_Error(-32601, 'server error. requested class method "' . $method . '" does not exist.');
482
            }
483
            // Call the method
484
            #$result = $this->$method($args);
485
            $result = call_user_func_array(array(&$this, $method), $args);
486
        } elseif(substr($method, 0, 7) == 'plugin:') {
487
            list($pluginname, $callback) = explode(':', substr($method, 7), 2);
488
            if(!plugin_isdisabled($pluginname)) {
489
                $plugin = plugin_load('action', $pluginname);
490
                return call_user_func_array(array($plugin, $callback), $args);
491
            } else {
492
                return new IXR_Error(-99999, 'server error');
493
            }
494
        } else {
495
            // It's a function - does it exist?
496
            if(is_array($method)) {
497
                if(!is_callable(array($method[0], $method[1]))) {
498
                    return new IXR_Error(-32601, 'server error. requested object method "' . $method[1] . '" does not exist.');
499
                }
500
            } else if(!function_exists($method)) {
501
                return new IXR_Error(-32601, 'server error. requested function "' . $method . '" does not exist.');
502
            }
503
504
            // Call the function
505
            $result = call_user_func($method, $args);
506
        }
507
        return $result;
508
    }
509
510
    /**
511
     * @param int $error
512
     * @param string|bool $message
513
     */
514
    function error($error, $message = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
515
        // Accepts either an error object or an error code and message
516
        if($message && !is_object($error)) {
517
            $error = new IXR_Error($error, $message);
0 ignored issues
show
Bug introduced by
It seems like $message defined by parameter $message on line 514 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.

Loading history...
518
        }
519
        $this->output($error->getXml());
0 ignored issues
show
Bug introduced by
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();
    }
}
Loading history...
520
    }
521
522
    /**
523
     * @param string $xml
524
     */
525
    function output($xml) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
526
        header('Content-Type: text/xml; charset=utf-8');
527
        echo '<?xml version="1.0"?>', "\n", $xml;
528
        exit;
529
    }
530
531
    /**
532
     * @param string $method
533
     * @return bool
534
     */
535
    function hasMethod($method) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
536
        return in_array($method, array_keys($this->callbacks));
537
    }
538
539
    function setCapabilities() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
540
        // Initialises capabilities array
541
        $this->capabilities = array(
542
            'xmlrpc' => array(
543
                'specUrl' => 'http://www.xmlrpc.com/spec',
544
                'specVersion' => 1
545
            ),
546
            'faults_interop' => array(
547
                'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
548
                'specVersion' => 20010516
549
            ),
550
            'system.multicall' => array(
551
                'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
552
                'specVersion' => 1
553
            ),
554
        );
555
    }
556
557
    /**
558
     * @return mixed
559
     */
560
    function getCapabilities() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
561
        return $this->capabilities;
562
    }
563
564
    function setCallbacks() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
565
        $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
566
        $this->callbacks['system.listMethods'] = 'this:listMethods';
567
        $this->callbacks['system.multicall'] = 'this:multiCall';
568
    }
569
570
    /**
571
     * @return array
572
     */
573
    function listMethods() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
574
        // Returns a list of methods - uses array_reverse to ensure user defined
575
        // methods are listed before server defined methods
576
        return array_reverse(array_keys($this->callbacks));
577
    }
578
579
    /**
580
     * @param array $methodcalls
581
     * @return array
582
     */
583
    function multiCall($methodcalls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
584
        // See http://www.xmlrpc.com/discuss/msgReader$1208
585
        $return = array();
586
        foreach($methodcalls as $call) {
587
            $method = $call['methodName'];
588
            $params = $call['params'];
589
            if($method == 'system.multicall') {
590
                $result = new IXR_Error(-32800, 'Recursive calls to system.multicall are forbidden');
591
            } else {
592
                $result = $this->call($method, $params);
593
            }
594
            if(is_a($result, 'IXR_Error')) {
595
                $return[] = array(
596
                    'faultCode' => $result->code,
597
                    'faultString' => $result->message
598
                );
599
            } else {
600
                $return[] = array($result);
601
            }
602
        }
603
        return $return;
604
    }
605
}
606
607
/**
608
 * IXR_Request
609
 *
610
 * @package IXR
611
 * @since 1.5
612
 */
613
class IXR_Request {
614
    /** @var string */
615
    var $method;
616
    /** @var array */
617
    var $args;
618
    /** @var string */
619
    var $xml;
620
621
    /**
622
     * @param string $method
623
     * @param array $args
624
     */
625
    function __construct($method, $args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
626
        $this->method = $method;
627
        $this->args = $args;
628
        $this->xml = <<<EOD
629
<?xml version="1.0"?>
630
<methodCall>
631
<methodName>{$this->method}</methodName>
632
<params>
633
634
EOD;
635
        foreach($this->args as $arg) {
636
            $this->xml .= '<param><value>';
637
            $v = new IXR_Value($arg);
638
            $this->xml .= $v->getXml();
639
            $this->xml .= "</value></param>\n";
640
        }
641
        $this->xml .= '</params></methodCall>';
642
    }
643
644
    /**
645
     * @return int
646
     */
647
    function getLength() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
648
        return strlen($this->xml);
649
    }
650
651
    /**
652
     * @return string
653
     */
654
    function getXml() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
655
        return $this->xml;
656
    }
657
}
658
659
/**
660
 * IXR_Client
661
 *
662
 * @package IXR
663
 * @since 1.5
664
 *
665
 * Changed for DokuWiki to use DokuHTTPClient
666
 *
667
 * This should be compatible to the original class, but uses DokuWiki's
668
 * HTTP client library which will respect proxy settings
669
 *
670
 * Because the XMLRPC client is not used in DokuWiki currently this is completely
671
 * untested
672
 */
673
class IXR_Client extends DokuHTTPClient {
674
    var $posturl = '';
675
    /** @var IXR_Message|bool */
676
    var $message = false;
677
678
    // Storage place for an error message
679
    /** @var IXR_Error|bool */
680
    var $xmlerror = false;
681
682
    /**
683
     * @param string $server
684
     * @param string|bool $path
685
     * @param int $port
686
     * @param int $timeout
687
     */
688
    function __construct($server, $path = false, $port = 80, $timeout = 15) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
689
        parent::__construct();
690
        if(!$path) {
691
            // Assume we have been given a URL instead
692
            $this->posturl = $server;
693
        } else {
694
            $this->posturl = 'http://' . $server . ':' . $port . $path;
695
        }
696
        $this->timeout = $timeout;
697
    }
698
699
    /**
700
     * parameters: method and arguments
701
     * @return bool success or error
702
     */
703
    function query() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
704
        $args = func_get_args();
705
        $method = array_shift($args);
706
        $request = new IXR_Request($method, $args);
707
        $xml = $request->getXml();
708
709
        $this->headers['Content-Type'] = 'text/xml';
710
        if(!$this->sendRequest($this->posturl, $xml, 'POST')) {
711
            $this->xmlerror = new IXR_Error(-32300, 'transport error - ' . $this->error);
712
            return false;
713
        }
714
715
        // Check HTTP Response code
716
        if($this->status < 200 || $this->status > 206) {
717
            $this->xmlerror = new IXR_Error(-32300, 'transport error - HTTP status ' . $this->status);
718
            return false;
719
        }
720
721
        // Now parse what we've got back
722
        $this->message = new IXR_Message($this->resp_body);
723
        if(!$this->message->parse()) {
724
            // XML error
725
            $this->xmlerror = new IXR_Error(-32700, 'parse error. not well formed');
726
            return false;
727
        }
728
729
        // Is the message a fault?
730
        if($this->message->messageType == 'fault') {
731
            $this->xmlerror = new IXR_Error($this->message->faultCode, $this->message->faultString);
732
            return false;
733
        }
734
735
        // Message must be OK
736
        return true;
737
    }
738
739
    /**
740
     * @return mixed
741
     */
742
    function getResponse() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
743
        // methodResponses can only have one param - return that
744
        return $this->message->params[0];
745
    }
746
747
    /**
748
     * @return bool
749
     */
750
    function isError() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
751
        return (is_object($this->xmlerror));
752
    }
753
754
    /**
755
     * @return int
756
     */
757
    function getErrorCode() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
758
        return $this->xmlerror->code;
759
    }
760
761
    /**
762
     * @return string
763
     */
764
    function getErrorMessage() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
765
        return $this->xmlerror->message;
766
    }
767
}
768
769
/**
770
 * IXR_Error
771
 *
772
 * @package IXR
773
 * @since 1.5
774
 */
775
class IXR_Error {
776
    var $code;
777
    var $message;
778
779
    /**
780
     * @param int $code
781
     * @param string $message
782
     */
783
    function __construct($code, $message) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
784
        $this->code = $code;
785
        $this->message = htmlspecialchars($message);
786
    }
787
788
    /**
789
     * @return string
790
     */
791
    function getXml() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
792
        $xml = <<<EOD
793
<methodResponse>
794
  <fault>
795
    <value>
796
      <struct>
797
        <member>
798
          <name>faultCode</name>
799
          <value><int>{$this->code}</int></value>
800
        </member>
801
        <member>
802
          <name>faultString</name>
803
          <value><string>{$this->message}</string></value>
804
        </member>
805
      </struct>
806
    </value>
807
  </fault>
808
</methodResponse>
809
810
EOD;
811
        return $xml;
812
    }
813
}
814
815
/**
816
 * IXR_Date
817
 *
818
 * @package IXR
819
 * @since 1.5
820
 */
821
class IXR_Date {
822
823
    /** @var DateTime */
824
    protected $date;
825
826
    /**
827
     * @param int|string $time
828
     */
829
    public function __construct($time) {
830
        // $time can be a PHP timestamp or an ISO one
831
        if(is_numeric($time)) {
832
            $this->parseTimestamp($time);
833
        } else {
834
            $this->parseIso($time);
835
        }
836
    }
837
838
    /**
839
     * Parse unix timestamp
840
     *
841
     * @param int $timestamp
842
     */
843
    protected function parseTimestamp($timestamp) {
844
        $this->date = new DateTime('@' . $timestamp);
845
    }
846
847
    /**
848
     * Parses less or more complete iso dates and much more, if no timezone given assumes UTC
849
     *
850
     * @param string $iso
851
     */
852
    protected function parseIso($iso) {
853
        $this->date = new DateTime($iso, new DateTimeZone("UTC"));
854
    }
855
856
    /**
857
     * Returns date in ISO 8601 format
858
     *
859
     * @return string
860
     */
861
    public function getIso() {
862
        return $this->date->format(DateTime::ISO8601);
863
    }
864
865
    /**
866
     * Returns date in valid xml
867
     *
868
     * @return string
869
     */
870
    public function getXml() {
871
        return '<dateTime.iso8601>' . $this->getIso() . '</dateTime.iso8601>';
872
    }
873
874
    /**
875
     * Returns Unix timestamp
876
     *
877
     * @return int
878
     */
879
    function getTimestamp() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
880
        return $this->date->getTimestamp();
881
    }
882
}
883
884
/**
885
 * IXR_Base64
886
 *
887
 * @package IXR
888
 * @since 1.5
889
 */
890
class IXR_Base64 {
891
    var $data;
892
893
    /**
894
     * @param string $data
895
     */
896
    function __construct($data) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
897
        $this->data = $data;
898
    }
899
900
    /**
901
     * @return string
902
     */
903
    function getXml() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
904
        return '<base64>' . base64_encode($this->data) . '</base64>';
905
    }
906
}
907
908
/**
909
 * IXR_IntrospectionServer
910
 *
911
 * @package IXR
912
 * @since 1.5
913
 */
914
class IXR_IntrospectionServer extends IXR_Server {
915
    /** @var array[] */
916
    var $signatures;
917
    /** @var string[] */
918
    var $help;
919
920
    /**
921
     * Constructor
922
     */
923
    function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
924
        $this->setCallbacks();
925
        $this->setCapabilities();
926
        $this->capabilities['introspection'] = array(
927
            'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
928
            'specVersion' => 1
929
        );
930
        $this->addCallback(
931
            'system.methodSignature',
932
            'this:methodSignature',
933
            array('array', 'string'),
934
            'Returns an array describing the return type and required parameters of a method'
935
        );
936
        $this->addCallback(
937
            'system.getCapabilities',
938
            'this:getCapabilities',
939
            array('struct'),
940
            'Returns a struct describing the XML-RPC specifications supported by this server'
941
        );
942
        $this->addCallback(
943
            'system.listMethods',
944
            'this:listMethods',
945
            array('array'),
946
            'Returns an array of available methods on this server'
947
        );
948
        $this->addCallback(
949
            'system.methodHelp',
950
            'this:methodHelp',
951
            array('string', 'string'),
952
            'Returns a documentation string for the specified method'
953
        );
954
    }
955
956
    /**
957
     * @param string $method
958
     * @param string $callback
959
     * @param string[] $args
960
     * @param string $help
961
     */
962
    function addCallback($method, $callback, $args, $help) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
963
        $this->callbacks[$method] = $callback;
964
        $this->signatures[$method] = $args;
965
        $this->help[$method] = $help;
966
    }
967
968
    /**
969
     * @param string $methodname
970
     * @param array $args
971
     * @return IXR_Error|mixed
972
     */
973
    function call($methodname, $args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
974
        // Make sure it's in an array
975
        if($args && !is_array($args)) {
0 ignored issues
show
Bug Best Practice introduced by
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 empty(..) or ! empty(...) instead.

Loading history...
976
            $args = array($args);
977
        }
978
979
        // Over-rides default call method, adds signature check
980
        if(!$this->hasMethod($methodname)) {
981
            return new IXR_Error(-32601, 'server error. requested method "' . $this->message->methodName . '" not specified.');
982
        }
983
        $method = $this->callbacks[$methodname];
0 ignored issues
show
Unused Code introduced by
$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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
984
        $signature = $this->signatures[$methodname];
985
        $returnType = array_shift($signature);
0 ignored issues
show
Unused Code introduced by
$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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
986
        // Check the number of arguments. Check only, if the minimum count of parameters is specified. More parameters are possible.
987
        // This is a hack to allow optional parameters...
988
        if(count($args) < count($signature)) {
989
            // print 'Num of args: '.count($args).' Num in signature: '.count($signature);
990
            return new IXR_Error(-32602, 'server error. wrong number of method parameters');
991
        }
992
993
        // Check the argument types
994
        $ok = true;
995
        $argsbackup = $args;
996
        for($i = 0, $j = count($args); $i < $j; $i++) {
997
            $arg = array_shift($args);
998
            $type = array_shift($signature);
999
            switch($type) {
1000
                case 'int':
1001
                case 'i4':
1002
                    if(is_array($arg) || !is_int($arg)) {
1003
                        $ok = false;
1004
                    }
1005
                    break;
1006
                case 'base64':
1007
                case 'string':
1008
                    if(!is_string($arg)) {
1009
                        $ok = false;
1010
                    }
1011
                    break;
1012
                case 'boolean':
1013
                    if($arg !== false && $arg !== true) {
1014
                        $ok = false;
1015
                    }
1016
                    break;
1017
                case 'float':
1018
                case 'double':
1019
                    if(!is_float($arg)) {
1020
                        $ok = false;
1021
                    }
1022
                    break;
1023
                case 'date':
1024
                case 'dateTime.iso8601':
1025
                    if(!is_a($arg, 'IXR_Date')) {
1026
                        $ok = false;
1027
                    }
1028
                    break;
1029
            }
1030
            if(!$ok) {
1031
                return new IXR_Error(-32602, 'server error. invalid method parameters');
1032
            }
1033
        }
1034
        // It passed the test - run the "real" method call
1035
        return parent::call($methodname, $argsbackup);
1036
    }
1037
1038
    /**
1039
     * @param string $method
1040
     * @return array|IXR_Error
1041
     */
1042
    function methodSignature($method) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1043
        if(!$this->hasMethod($method)) {
1044
            return new IXR_Error(-32601, 'server error. requested method "' . $method . '" not specified.');
1045
        }
1046
        // We should be returning an array of types
1047
        $types = $this->signatures[$method];
1048
        $return = array();
1049
        foreach($types as $type) {
1050
            switch($type) {
1051
                case 'string':
1052
                    $return[] = 'string';
1053
                    break;
1054
                case 'int':
1055
                case 'i4':
1056
                    $return[] = 42;
1057
                    break;
1058
                case 'double':
1059
                    $return[] = 3.1415;
1060
                    break;
1061
                case 'dateTime.iso8601':
1062
                    $return[] = new IXR_Date(time());
1063
                    break;
1064
                case 'boolean':
1065
                    $return[] = true;
1066
                    break;
1067
                case 'base64':
1068
                    $return[] = new IXR_Base64('base64');
1069
                    break;
1070
                case 'array':
1071
                    $return[] = array('array');
1072
                    break;
1073
                case 'struct':
1074
                    $return[] = array('struct' => 'struct');
1075
                    break;
1076
            }
1077
        }
1078
        return $return;
1079
    }
1080
1081
    /**
1082
     * @param string $method
1083
     * @return mixed
1084
     */
1085
    function methodHelp($method) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1086
        return $this->help[$method];
1087
    }
1088
}
1089
1090
/**
1091
 * IXR_ClientMulticall
1092
 *
1093
 * @package IXR
1094
 * @since 1.5
1095
 */
1096
class IXR_ClientMulticall extends IXR_Client {
1097
1098
    /** @var array[] */
1099
    var $calls = array();
1100
1101
    /**
1102
     * @param string $server
1103
     * @param string|bool $path
1104
     * @param int $port
1105
     */
1106
    function __construct($server, $path = false, $port = 80) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1107
        parent::__construct($server, $path, $port);
1108
        //$this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
1109
    }
1110
1111
    /**
1112
     * Add a call
1113
     */
1114
    function addCall() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1115
        $args = func_get_args();
1116
        $methodName = array_shift($args);
1117
        $struct = array(
1118
            'methodName' => $methodName,
1119
            'params' => $args
1120
        );
1121
        $this->calls[] = $struct;
1122
    }
1123
1124
    /**
1125
     * @return bool
1126
     */
1127
    function query() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1128
        // Prepare multicall, then call the parent::query() method
1129
        return parent::query('system.multicall', $this->calls);
1130
    }
1131
}
1132
1133