Failed Conditions
Push — refctorHTTPCLient ( 0efa8d...5a8d6e )
by Michael
04:15
created

IXR_Value   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 129
rs 9.76
c 0
b 0
f 0
wmc 33
lcom 1
cbo 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 6
C calculateType() 0 35 12
C getXml() 0 39 12
A isStruct() 0 10 3
1
<?php
2
3
use dokuwiki\HTTP\DokuHTTPClient;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DokuHTTPClient.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/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 before OtherDir/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:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
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
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...
58
        $this->data = $data;
59
        if(!$type) {
60
            $type = $this->calculateType();
61
        }
62
        $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...
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
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...
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
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...
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
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...
124
            case 'int':
125
                return '<int>' . $this->data . '</int>';
126
                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...
127
            case 'double':
128
                return '<double>' . $this->data . '</double>';
129
                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...
130
            case 'string':
131
                return '<string>' . htmlspecialchars($this->data) . '</string>';
132
                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...
133
            case 'array':
134
                $return = '<array><data>' . "\n";
135
                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...
136
                    $return .= '  <value>' . $item->getXml() . "</value>\n";
137
                }
138
                $return .= '</data></array>';
139
                return $return;
140
                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...
141
            case 'struct':
142
                $return = '<struct>' . "\n";
143
                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...
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
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...
150
            case 'date':
151
            case 'base64':
152
                return $this->data->getXml();
153
                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...
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
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...
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
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...
207
        $this->message =& $message;
208
    }
209
210
    /**
211
     * @return bool
212
     */
213
    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...
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('&lt;', '&#60;', $this->message);
221
        $this->message = str_replace('&gt;', '&#62;', $this->message);
222
        $this->message = str_replace('&amp;', '&#38;', $this->message);
223
        $this->message = str_replace('&apos;', '&#39;', $this->message);
224
        $this->message = str_replace('&quot;', '&#34;', $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
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...
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
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...
294
        $this->_currentTagContents .= $cdata;
295
    }
296
297
    /**
298
     * @param $parser
299
     * @param $tag
300
     */
301
    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...
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
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...
395
        $this->setCapabilities();
396
        if($callbacks) {
397
            $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...
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
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...
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
Bug introduced by
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.

Loading history...
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
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...
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
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...
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
Bug introduced by
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.

Loading history...
520
        }
521
        $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...
522
    }
523
524
    /**
525
     * @param string $xml
526
     */
527
    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...
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
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...
538
        return in_array($method, array_keys($this->callbacks));
539
    }
540
541
    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...
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
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...
563
        return $this->capabilities;
564
    }
565
566
    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...
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
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...
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
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...
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
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...
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
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...
650
        return strlen($this->xml);
651
    }
652
653
    /**
654
     * @return string
655
     */
656
    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...
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
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...
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
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...
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
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...
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
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...
753
        return (is_object($this->xmlerror));
754
    }
755
756
    /**
757
     * @return int
758
     */
759
    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...
760
        return $this->xmlerror->code;
761
    }
762
763
    /**
764
     * @return string
765
     */
766
    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...
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
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...
786
        $this->code = $code;
787
        $this->message = htmlspecialchars($message);
788
    }
789
790
    /**
791
     * @return string
792
     */
793
    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...
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
    /** @var DateTime */
826
    protected $date;
827
828
    /**
829
     * @param int|string $time
830
     */
831
    public function __construct($time) {
832
        // $time can be a PHP timestamp or an ISO one
833
        if(is_numeric($time)) {
834
            $this->parseTimestamp($time);
835
        } else {
836
            $this->parseIso($time);
837
        }
838
    }
839
840
    /**
841
     * Parse unix timestamp
842
     *
843
     * @param int $timestamp
844
     */
845
    protected function parseTimestamp($timestamp) {
846
        $this->date = new DateTime('@' . $timestamp);
847
    }
848
849
    /**
850
     * Parses less or more complete iso dates and much more, if no timezone given assumes UTC
851
     *
852
     * @param string $iso
853
     */
854
    protected function parseIso($iso) {
855
        $this->date = new DateTime($iso, new DateTimeZone("UTC"));
856
    }
857
858
    /**
859
     * Returns date in ISO 8601 format
860
     *
861
     * @return string
862
     */
863
    public function getIso() {
864
        return $this->date->format(DateTime::ISO8601);
865
    }
866
867
    /**
868
     * Returns date in valid xml
869
     *
870
     * @return string
871
     */
872
    public function getXml() {
873
        return '<dateTime.iso8601>' . $this->getIso() . '</dateTime.iso8601>';
874
    }
875
876
    /**
877
     * Returns Unix timestamp
878
     *
879
     * @return int
880
     */
881
    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...
882
        return $this->date->getTimestamp();
883
    }
884
}
885
886
/**
887
 * IXR_Base64
888
 *
889
 * @package IXR
890
 * @since 1.5
891
 */
892
class IXR_Base64 {
893
    var $data;
894
895
    /**
896
     * @param string $data
897
     */
898
    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...
899
        $this->data = $data;
900
    }
901
902
    /**
903
     * @return string
904
     */
905
    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...
906
        return '<base64>' . base64_encode($this->data) . '</base64>';
907
    }
908
}
909
910
/**
911
 * IXR_IntrospectionServer
912
 *
913
 * @package IXR
914
 * @since 1.5
915
 */
916
class IXR_IntrospectionServer extends IXR_Server {
917
    /** @var array[] */
918
    var $signatures;
919
    /** @var string[] */
920
    var $help;
921
922
    /**
923
     * Constructor
924
     */
925
    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...
926
        $this->setCallbacks();
927
        $this->setCapabilities();
928
        $this->capabilities['introspection'] = array(
929
            'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
930
            'specVersion' => 1
931
        );
932
        $this->addCallback(
933
            'system.methodSignature',
934
            'this:methodSignature',
935
            array('array', 'string'),
936
            'Returns an array describing the return type and required parameters of a method'
937
        );
938
        $this->addCallback(
939
            'system.getCapabilities',
940
            'this:getCapabilities',
941
            array('struct'),
942
            'Returns a struct describing the XML-RPC specifications supported by this server'
943
        );
944
        $this->addCallback(
945
            'system.listMethods',
946
            'this:listMethods',
947
            array('array'),
948
            'Returns an array of available methods on this server'
949
        );
950
        $this->addCallback(
951
            'system.methodHelp',
952
            'this:methodHelp',
953
            array('string', 'string'),
954
            'Returns a documentation string for the specified method'
955
        );
956
    }
957
958
    /**
959
     * @param string $method
960
     * @param string $callback
961
     * @param string[] $args
962
     * @param string $help
963
     */
964
    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...
965
        $this->callbacks[$method] = $callback;
966
        $this->signatures[$method] = $args;
967
        $this->help[$method] = $help;
968
    }
969
970
    /**
971
     * @param string $methodname
972
     * @param array $args
973
     * @return IXR_Error|mixed
974
     */
975
    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...
976
        // Make sure it's in an array
977
        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...
978
            $args = array($args);
979
        }
980
981
        // Over-rides default call method, adds signature check
982
        if(!$this->hasMethod($methodname)) {
983
            return new IXR_Error(-32601, 'server error. requested method "' . $this->message->methodName . '" not specified.');
984
        }
985
        $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...
986
        $signature = $this->signatures[$methodname];
987
        $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...
988
        // Check the number of arguments. Check only, if the minimum count of parameters is specified. More parameters are possible.
989
        // This is a hack to allow optional parameters...
990
        if(count($args) < count($signature)) {
991
            // print 'Num of args: '.count($args).' Num in signature: '.count($signature);
992
            return new IXR_Error(-32602, 'server error. wrong number of method parameters');
993
        }
994
995
        // Check the argument types
996
        $ok = true;
997
        $argsbackup = $args;
998
        for($i = 0, $j = count($args); $i < $j; $i++) {
999
            $arg = array_shift($args);
1000
            $type = array_shift($signature);
1001
            switch($type) {
1002
                case 'int':
1003
                case 'i4':
1004
                    if(is_array($arg) || !is_int($arg)) {
1005
                        $ok = false;
1006
                    }
1007
                    break;
1008
                case 'base64':
1009
                case 'string':
1010
                    if(!is_string($arg)) {
1011
                        $ok = false;
1012
                    }
1013
                    break;
1014
                case 'boolean':
1015
                    if($arg !== false && $arg !== true) {
1016
                        $ok = false;
1017
                    }
1018
                    break;
1019
                case 'float':
1020
                case 'double':
1021
                    if(!is_float($arg)) {
1022
                        $ok = false;
1023
                    }
1024
                    break;
1025
                case 'date':
1026
                case 'dateTime.iso8601':
1027
                    if(!is_a($arg, 'IXR_Date')) {
1028
                        $ok = false;
1029
                    }
1030
                    break;
1031
            }
1032
            if(!$ok) {
1033
                return new IXR_Error(-32602, 'server error. invalid method parameters');
1034
            }
1035
        }
1036
        // It passed the test - run the "real" method call
1037
        return parent::call($methodname, $argsbackup);
1038
    }
1039
1040
    /**
1041
     * @param string $method
1042
     * @return array|IXR_Error
1043
     */
1044
    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...
1045
        if(!$this->hasMethod($method)) {
1046
            return new IXR_Error(-32601, 'server error. requested method "' . $method . '" not specified.');
1047
        }
1048
        // We should be returning an array of types
1049
        $types = $this->signatures[$method];
1050
        $return = array();
1051
        foreach($types as $type) {
1052
            switch($type) {
1053
                case 'string':
1054
                    $return[] = 'string';
1055
                    break;
1056
                case 'int':
1057
                case 'i4':
1058
                    $return[] = 42;
1059
                    break;
1060
                case 'double':
1061
                    $return[] = 3.1415;
1062
                    break;
1063
                case 'dateTime.iso8601':
1064
                    $return[] = new IXR_Date(time());
1065
                    break;
1066
                case 'boolean':
1067
                    $return[] = true;
1068
                    break;
1069
                case 'base64':
1070
                    $return[] = new IXR_Base64('base64');
1071
                    break;
1072
                case 'array':
1073
                    $return[] = array('array');
1074
                    break;
1075
                case 'struct':
1076
                    $return[] = array('struct' => 'struct');
1077
                    break;
1078
            }
1079
        }
1080
        return $return;
1081
    }
1082
1083
    /**
1084
     * @param string $method
1085
     * @return mixed
1086
     */
1087
    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...
1088
        return $this->help[$method];
1089
    }
1090
}
1091
1092
/**
1093
 * IXR_ClientMulticall
1094
 *
1095
 * @package IXR
1096
 * @since 1.5
1097
 */
1098
class IXR_ClientMulticall extends IXR_Client {
1099
1100
    /** @var array[] */
1101
    var $calls = array();
1102
1103
    /**
1104
     * @param string $server
1105
     * @param string|bool $path
1106
     * @param int $port
1107
     */
1108
    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...
1109
        parent::__construct($server, $path, $port);
1110
        //$this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
1111
    }
1112
1113
    /**
1114
     * Add a call
1115
     */
1116
    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...
1117
        $args = func_get_args();
1118
        $methodName = array_shift($args);
1119
        $struct = array(
1120
            'methodName' => $methodName,
1121
            'params' => $args
1122
        );
1123
        $this->calls[] = $struct;
1124
    }
1125
1126
    /**
1127
     * @return bool
1128
     */
1129
    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...
1130
        // Prepare multicall, then call the parent::query() method
1131
        return parent::query('system.multicall', $this->calls);
1132
    }
1133
}
1134
1135