Issues (847)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

inc/IXR_Library.php (64 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use dokuwiki\HTTP\DokuHTTPClient;
0 ignored issues
show
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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...
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...
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
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...
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
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...
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
    const XMLRPC_ISO8601 = "Ymd\TH:i:sO" ;
826
    /** @var DateTime */
827
    protected $date;
828
829
    /**
830
     * @param int|string $time
831
     */
832
    public function __construct($time) {
833
        // $time can be a PHP timestamp or an ISO one
834
        if(is_numeric($time)) {
835
            $this->parseTimestamp($time);
836
        } else {
837
            $this->parseIso($time);
838
        }
839
    }
840
841
    /**
842
     * Parse unix timestamp
843
     *
844
     * @param int $timestamp
845
     */
846
    protected function parseTimestamp($timestamp) {
847
        $this->date = new DateTime('@' . $timestamp);
848
    }
849
850
    /**
851
     * Parses less or more complete iso dates and much more, if no timezone given assumes UTC
852
     *
853
     * @param string $iso
854
     */
855
    protected function parseIso($iso) {
856
        $this->date = new DateTime($iso, new DateTimeZone("UTC"));
857
    }
858
859
    /**
860
     * Returns date in ISO 8601 format
861
     *
862
     * @return string
863
     */
864
    public function getIso() {
865
	      return $this->date->format(self::XMLRPC_ISO8601);
866
    }
867
868
    /**
869
     * Returns date in valid xml
870
     *
871
     * @return string
872
     */
873
    public function getXml() {
874
        return '<dateTime.iso8601>' . $this->getIso() . '</dateTime.iso8601>';
875
    }
876
877
    /**
878
     * Returns Unix timestamp
879
     *
880
     * @return int
881
     */
882
    function getTimestamp() {
0 ignored issues
show
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...
883
        return $this->date->getTimestamp();
884
    }
885
}
886
887
/**
888
 * IXR_Base64
889
 *
890
 * @package IXR
891
 * @since 1.5
892
 */
893
class IXR_Base64 {
894
    var $data;
895
896
    /**
897
     * @param string $data
898
     */
899
    function __construct($data) {
0 ignored issues
show
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...
900
        $this->data = $data;
901
    }
902
903
    /**
904
     * @return string
905
     */
906
    function getXml() {
0 ignored issues
show
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...
907
        return '<base64>' . base64_encode($this->data) . '</base64>';
908
    }
909
}
910
911
/**
912
 * IXR_IntrospectionServer
913
 *
914
 * @package IXR
915
 * @since 1.5
916
 */
917
class IXR_IntrospectionServer extends IXR_Server {
918
    /** @var array[] */
919
    var $signatures;
920
    /** @var string[] */
921
    var $help;
922
923
    /**
924
     * Constructor
925
     */
926
    function __construct() {
0 ignored issues
show
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...
927
        $this->setCallbacks();
928
        $this->setCapabilities();
929
        $this->capabilities['introspection'] = array(
930
            'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
931
            'specVersion' => 1
932
        );
933
        $this->addCallback(
934
            'system.methodSignature',
935
            'this:methodSignature',
936
            array('array', 'string'),
937
            'Returns an array describing the return type and required parameters of a method'
938
        );
939
        $this->addCallback(
940
            'system.getCapabilities',
941
            'this:getCapabilities',
942
            array('struct'),
943
            'Returns a struct describing the XML-RPC specifications supported by this server'
944
        );
945
        $this->addCallback(
946
            'system.listMethods',
947
            'this:listMethods',
948
            array('array'),
949
            'Returns an array of available methods on this server'
950
        );
951
        $this->addCallback(
952
            'system.methodHelp',
953
            'this:methodHelp',
954
            array('string', 'string'),
955
            'Returns a documentation string for the specified method'
956
        );
957
    }
958
959
    /**
960
     * @param string $method
961
     * @param string $callback
962
     * @param string[] $args
963
     * @param string $help
964
     */
965
    function addCallback($method, $callback, $args, $help) {
0 ignored issues
show
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...
966
        $this->callbacks[$method] = $callback;
967
        $this->signatures[$method] = $args;
968
        $this->help[$method] = $help;
969
    }
970
971
    /**
972
     * @param string $methodname
973
     * @param array $args
974
     * @return IXR_Error|mixed
975
     */
976
    function call($methodname, $args) {
0 ignored issues
show
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...
977
        // Make sure it's in an array
978
        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...
979
            $args = array($args);
980
        }
981
982
        // Over-rides default call method, adds signature check
983
        if(!$this->hasMethod($methodname)) {
984
            return new IXR_Error(-32601, 'server error. requested method "' . $this->message->methodName . '" not specified.');
985
        }
986
        $method = $this->callbacks[$methodname];
0 ignored issues
show
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $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...
987
        $signature = $this->signatures[$methodname];
988
        $returnType = array_shift($signature);
0 ignored issues
show
$returnType is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $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...
989
        // Check the number of arguments. Check only, if the minimum count of parameters is specified. More parameters are possible.
990
        // This is a hack to allow optional parameters...
991
        if(count($args) < count($signature)) {
992
            // print 'Num of args: '.count($args).' Num in signature: '.count($signature);
993
            return new IXR_Error(-32602, 'server error. wrong number of method parameters');
994
        }
995
996
        // Check the argument types
997
        $ok = true;
998
        $argsbackup = $args;
999
        for($i = 0, $j = count($args); $i < $j; $i++) {
1000
            $arg = array_shift($args);
1001
            $type = array_shift($signature);
1002
            switch($type) {
1003
                case 'int':
1004
                case 'i4':
1005
                    if(is_array($arg) || !is_int($arg)) {
1006
                        $ok = false;
1007
                    }
1008
                    break;
1009
                case 'base64':
1010
                case 'string':
1011
                    if(!is_string($arg)) {
1012
                        $ok = false;
1013
                    }
1014
                    break;
1015
                case 'boolean':
1016
                    if($arg !== false && $arg !== true) {
1017
                        $ok = false;
1018
                    }
1019
                    break;
1020
                case 'float':
1021
                case 'double':
1022
                    if(!is_float($arg)) {
1023
                        $ok = false;
1024
                    }
1025
                    break;
1026
                case 'date':
1027
                case 'dateTime.iso8601':
1028
                    if(!is_a($arg, 'IXR_Date')) {
1029
                        $ok = false;
1030
                    }
1031
                    break;
1032
            }
1033
            if(!$ok) {
1034
                return new IXR_Error(-32602, 'server error. invalid method parameters');
1035
            }
1036
        }
1037
        // It passed the test - run the "real" method call
1038
        return parent::call($methodname, $argsbackup);
1039
    }
1040
1041
    /**
1042
     * @param string $method
1043
     * @return array|IXR_Error
1044
     */
1045
    function methodSignature($method) {
0 ignored issues
show
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...
1046
        if(!$this->hasMethod($method)) {
1047
            return new IXR_Error(-32601, 'server error. requested method "' . $method . '" not specified.');
1048
        }
1049
        // We should be returning an array of types
1050
        $types = $this->signatures[$method];
1051
        $return = array();
1052
        foreach($types as $type) {
1053
            switch($type) {
1054
                case 'string':
1055
                    $return[] = 'string';
1056
                    break;
1057
                case 'int':
1058
                case 'i4':
1059
                    $return[] = 42;
1060
                    break;
1061
                case 'double':
1062
                    $return[] = 3.1415;
1063
                    break;
1064
                case 'dateTime.iso8601':
1065
                    $return[] = new IXR_Date(time());
1066
                    break;
1067
                case 'boolean':
1068
                    $return[] = true;
1069
                    break;
1070
                case 'base64':
1071
                    $return[] = new IXR_Base64('base64');
1072
                    break;
1073
                case 'array':
1074
                    $return[] = array('array');
1075
                    break;
1076
                case 'struct':
1077
                    $return[] = array('struct' => 'struct');
1078
                    break;
1079
            }
1080
        }
1081
        return $return;
1082
    }
1083
1084
    /**
1085
     * @param string $method
1086
     * @return mixed
1087
     */
1088
    function methodHelp($method) {
0 ignored issues
show
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...
1089
        return $this->help[$method];
1090
    }
1091
}
1092
1093
/**
1094
 * IXR_ClientMulticall
1095
 *
1096
 * @package IXR
1097
 * @since 1.5
1098
 */
1099
class IXR_ClientMulticall extends IXR_Client {
1100
1101
    /** @var array[] */
1102
    var $calls = array();
1103
1104
    /**
1105
     * @param string $server
1106
     * @param string|bool $path
1107
     * @param int $port
1108
     */
1109
    function __construct($server, $path = false, $port = 80) {
0 ignored issues
show
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...
1110
        parent::__construct($server, $path, $port);
1111
        //$this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
1112
    }
1113
1114
    /**
1115
     * Add a call
1116
     */
1117
    function addCall() {
0 ignored issues
show
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...
1118
        $args = func_get_args();
1119
        $methodName = array_shift($args);
1120
        $struct = array(
1121
            'methodName' => $methodName,
1122
            'params' => $args
1123
        );
1124
        $this->calls[] = $struct;
1125
    }
1126
1127
    /**
1128
     * @return bool
1129
     */
1130
    function query() {
0 ignored issues
show
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...
1131
        // Prepare multicall, then call the parent::query() method
1132
        return parent::query('system.multicall', $this->calls);
1133
    }
1134
}
1135
1136