Passed
Push — master ( ebef44...752d49 )
by Gaetano
05:28
created

Client::__get()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
eloc 18
nc 8
nop 1
dl 0
loc 22
ccs 0
cts 0
cp 0
crap 72
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
namespace PhpXmlRpc;
4
5
use PhpXmlRpc\Exception\ValueErrorException;
6
use PhpXmlRpc\Helper\XMLParser;
7
use PhpXmlRpc\Traits\CharsetEncoderAware;
8
use PhpXmlRpc\Traits\DeprecationLogger;
9
10
/**
11
 * Used to represent a client of an XML-RPC server.
12
 *
13
 * @property int $errno deprecated - public access left in purely for BC.
14
 * @property string $errstr deprecated - public access left in purely for BC.
15
 * @property string $method deprecated - public access left in purely for BC. Access via getUrl()/__construct()
16
 * @property string $server deprecated - public access left in purely for BC. Access via getUrl()/__construct()
17
 * @property int $port deprecated - public access left in purely for BC. Access via getUrl()/__construct()
18
 * @property string $path deprecated - public access left in purely for BC. Access via getUrl()/__construct()
19
 */
20
class Client
21
{
22
    use DeprecationLogger;
23
    //use CharsetEncoderAware;
24
25
    const USE_CURL_NEVER = 0;
26
    const USE_CURL_ALWAYS = 1;
27
    const USE_CURL_AUTO = 2;
28
29
    const OPT_ACCEPTED_CHARSET_ENCODINGS = 'accepted_charset_encodings';
30
    const OPT_ACCEPTED_COMPRESSION = 'accepted_compression';
31
    const OPT_AUTH_TYPE = 'authtype';
32
    const OPT_CA_CERT = 'cacert';
33
    const OPT_CA_CERT_DIR = 'cacertdir';
34
    const OPT_CERT = 'cert';
35
    const OPT_CERT_PASS = 'certpass';
36
    const OPT_COOKIES = 'cookies';
37
    const OPT_DEBUG = 'debug';
38
    const OPT_EXTRA_CURL_OPTS = 'extracurlopts';
39
    const OPT_KEEPALIVE = 'keepalive';
40
    const OPT_KEY = 'key';
41
    const OPT_KEY_PASS = 'keypass';
42
    const OPT_NO_MULTICALL = 'no_multicall';
43
    const OPT_PASSWORD = 'password';
44
    const OPT_PROXY = 'proxy';
45
    const OPT_PROXY_AUTH_TYPE = 'proxy_authtype';
46
    const OPT_PROXY_PASS = 'proxy_pass';
47
    const OPT_PROXY_PORT = 'proxyport';
48
    const OPT_PROXY_USER = 'proxy_user';
49
    const OPT_REQUEST_CHARSET_ENCODING = 'request_charset_encoding';
50
    const OPT_REQUEST_COMPRESSION = 'request_compression';
51
    const OPT_RETURN_TYPE = 'return_type';
52
    const OPT_SSL_VERSION = 'sslversion';
53
    const OPT_TIMEOUT = 'timeout';
54
    const OPT_USERNAME = 'username';
55
    const OPT_USER_AGENT = 'user_agent';
56
    const OPT_USE_CURL = 'use_curl';
57
    const OPT_VERIFY_HOST = 'verifyhost';
58
    const OPT_VERIFY_PEER = 'verifypeer';
59
60
    /** @var string */
61
    protected static $requestClass = '\\PhpXmlRpc\\Request';
62
    /** @var string */
63
    protected static $responseClass = '\\PhpXmlRpc\\Response';
64
65
    /**
66
     * @var int
67
     * @deprecated will be removed in the future
68
     */
69
    protected $errno;
70
    /**
71
     * @var string
72
     * @deprecated will be removed in the future
73
     */
74
    protected $errstr;
75
76
    /// @todo: do all the ones below need to be public?
77
78
    /**
79
     * @var string
80
     */
81
    protected $method = 'http';
82
    /**
83
     * @var string
84
     */
85
    protected $server;
86
    /**
87
     * @var int
88
     */
89
    protected $port = 0;
90
    /**
91
     * @var string
92
     */
93
    protected $path;
94
95
    /**
96
     * @var int
97
     */
98
    protected $debug = 0;
99
    /**
100
     * @var string
101
     */
102
    protected $username = '';
103
    /**
104
     * @var string
105
     */
106
    protected $password = '';
107
    /**
108
     * @var int
109
     */
110
    protected $authtype = 1;
111
    /**
112
     * @var string
113
     */
114
    protected $cert = '';
115
    /**
116
     * @var string
117
     */
118
    protected $certpass = '';
119
    /**
120
     * @var string
121
     */
122 2
    protected $cacert = '';
123
    /**
124 2
     * @var string
125 2
     */
126
    protected $cacertdir = '';
127 2
    /**
128
     * @var string
129
     */
130
    protected $key = '';
131
    /**
132
     * @var string
133
     */
134
    protected $keypass = '';
135
    /**
136
     * @var bool
137
     */
138
    protected $verifypeer = true;
139
    /**
140
     * @var int
141
     */
142
    protected $verifyhost = 2;
143
    /**
144
     * @var int
145
     */
146
    protected $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT
147
    /**
148
     * @var string
149
     */
150
    protected $proxy = '';
151
    /**
152 718
     * @var int
153
     */
154
    protected $proxyport = 0;
155 718
    /**
156 7
     * @var string
157 7
     */
158 7
    protected $proxy_user = '';
159 7
    /**
160
     * @var string
161
     */
162 7
    protected $proxy_pass = '';
163
    /**
164
     * @var int
165 7
     */
166
    protected $proxy_authtype = 1;
167
    /**
168 7
     * @var array
169 7
     */
170
    protected $cookies = array();
171 7
    /**
172
     * @var array
173
     */
174 7
    protected $extracurlopts = array();
175
    /**
176
     * @var int
177
     */
178 718
    protected $timeout = 0;
179
    /**
180
     * @var int
181 718
     */
182
    protected $use_curl = self::USE_CURL_AUTO;
183 718
    /**
184 718
     * @var bool
185 3
     *
186
     * This determines whether the multicall() method will try to take advantage of the system.multicall xml-rpc method
187 718
     * to dispatch to the server an array of requests in a single http roundtrip or simply execute many consecutive http
188 7
     * calls. Defaults to FALSE, but it will be enabled automatically on the first failure of execution of
189
     * system.multicall.
190
     */
191
    protected $no_multicall = false;
192 718
    /**
193
     * @var array
194 711
     *
195
     * List of http compression methods accepted by the client for responses.
196
     * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib.
197 718
     *
198
     * NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since in those cases it will be up to CURL to
199
     * decide the compression methods it supports. You might check for the presence of 'zlib' in the output of
200
     * curl_version() to determine whether compression is supported or not
201 718
     */
202
    protected $accepted_compression = array();
203
    /**
204 718
     * @var string|null
205
     *
206
     * Name of compression scheme to be used for sending requests.
207
     * Either null, 'gzip' or 'deflate'.
208
     */
209
    protected $request_compression = '';
210
    /**
211
     * @var bool
212
     *
213
     * Whether to use persistent connections for http 1.1 and https. Value set at constructor time.
214
     */
215
    protected $keepalive = false;
216
    /**
217 718
     * @var string[]
218 718
     *
219
     * Charset encodings that can be decoded without problems by the client. Value set at constructor time
220
     */
221
    protected $accepted_charset_encodings = array();
222
    /**
223
     * @var string
224
     *
225
     * The charset encoding that will be used for serializing request sent by the client.
226
     * It defaults to NULL, which means using US-ASCII and encoding all characters outside the ASCII printable range
227
     * using their xml character entity representation (this has the benefit that line end characters will not be mangled
228
     * in the transfer, a CR-LF will be preserved as well as a singe LF).
229
     * Valid values are 'US-ASCII', 'UTF-8' and 'ISO-8859-1'.
230
     * For the fastest mode of operation, set your both your app internal encoding and this to UTF-8.
231
     */
232
    protected $request_charset_encoding = '';
233 714
    /**
234
     * @var string
235 714
     *
236 714
     * Decides the content of Response objects returned by calls to send() and multicall().
237
     * Valid values are 'xmlrpcvals', 'phpvals' or 'xml'.
238
     *
239
     * Determines whether the value returned inside a Response object as results of calls to the send() and multicall()
240
     * methods will be a Value object, a plain php value or a raw xml string.
241
     * Allowed values are 'xmlrpcvals' (the default), 'phpvals' and 'xml'.
242
     * To allow the user to differentiate between a correct and a faulty response, fault responses will be returned as
243
     * Response objects in any case.
244
     * Note that the 'phpvals' setting will yield faster execution times, but some of the information from the original
245
     * response will be lost. It will be e.g. impossible to tell whether a particular php string value was sent by the
246
     * server as an xml-rpc string or base64 value.
247
     */
248
    protected $return_type = XMLParser::RETURN_XMLRPCVALS;
249
    /**
250
     * @var string
251
     *
252 66
     * Sent to servers in http headers. Value set at constructor time.
253
     */
254 66
    protected $user_agent;
255 66
256 66
    /**
257 66
     * CURL handle: used for keep-alive
258
     * @internal
259
     */
260
    public $xmlrpc_curl_handle = null;
261
262
    /**
263
     * @var array
264
     */
265
    protected static $options = array(
266
        self::OPT_ACCEPTED_CHARSET_ENCODINGS,
267
        self::OPT_ACCEPTED_COMPRESSION,
268
        self::OPT_AUTH_TYPE,
269
        self::OPT_CA_CERT,
270
        self::OPT_CA_CERT_DIR,
271
        self::OPT_CERT,
272
        self::OPT_CERT_PASS,
273
        self::OPT_COOKIES,
274
        self::OPT_DEBUG,
275
        self::OPT_EXTRA_CURL_OPTS,
276
        self::OPT_KEEPALIVE,
277
        self::OPT_KEY,
278
        self::OPT_KEY_PASS,
279
        self::OPT_NO_MULTICALL,
280
        self::OPT_PASSWORD,
281
        self::OPT_PROXY,
282
        self::OPT_PROXY_AUTH_TYPE,
283
        self::OPT_PROXY_PASS,
284
        self::OPT_PROXY_USER,
285
        self::OPT_PROXY_PORT,
286
        self::OPT_REQUEST_CHARSET_ENCODING,
287
        self::OPT_REQUEST_COMPRESSION,
288
        self::OPT_RETURN_TYPE,
289
        self::OPT_SSL_VERSION,
290
        self::OPT_TIMEOUT,
291
        self::OPT_USE_CURL,
292
        self::OPT_USER_AGENT,
293
        self::OPT_USERNAME,
294
        self::OPT_VERIFY_HOST,
295
        self::OPT_VERIFY_PEER,
296
    );
297
298
    /**
299
     * @param string $path either the PATH part of the xml-rpc server URL, or complete server URL (in which case you
300
     *                     should use an empty string for all other parameters)
301
     *                     e.g. /xmlrpc/server.php
302
     *                     e.g. http://phpxmlrpc.sourceforge.net/server.php
303
     *                     e.g. https://james:[email protected]:444/xmlrpcserver?agent=007
304
     *                     e.g. h2://fast-and-secure-services.org/endpoint
305
     * @param string $server the server name / ip address
306
     * @param integer $port the port the server is listening on, when omitted defaults to 80 or 443 depending on
307
     *                      protocol used
308
     * @param string $method the http protocol variant: defaults to 'http'; 'https', 'http11', 'h2' and 'h2c' can
309
     *                       be used if CURL is installed. The value set here can be overridden in any call to $this->send().
310
     *                       Use 'h2' to make the lib attempt to use http/2 over a secure connection, and 'h2c'
311
     *                       for http/2 without tls. Note that 'h2c' will not use the h2c 'upgrade' method, and be
312
     *                       thus incompatible with any server/proxy not supporting http/2. This is because POST
313
     *                       request are not compatible with h2c upgrade.
314
     */
315
    public function __construct($path, $server = '', $port = '', $method = '')
316 132
    {
317
        // allow user to specify all params in $path
318 132
        if ($server == '' && $port == '' && $method == '') {
319 132
            $parts = parse_url($path);
320
            $server = $parts['host'];
321
            $path = isset($parts['path']) ? $parts['path'] : '';
322
            if (isset($parts['query'])) {
323
                $path .= '?' . $parts['query'];
324
            }
325
            if (isset($parts['fragment'])) {
326
                $path .= '#' . $parts['fragment'];
327
            }
328 132
            if (isset($parts['port'])) {
329
                $port = $parts['port'];
330 132
            }
331 132
            if (isset($parts['scheme'])) {
332
                $method = $parts['scheme'];
333
            }
334
            if (isset($parts['user'])) {
335
                $this->username = $parts['user'];
336
            }
337
            if (isset($parts['pass'])) {
338 132
                $this->password = $parts['pass'];
339
            }
340 132
        }
341 132
        if ($path == '' || $path[0] != '/') {
342
            $this->path = '/' . $path;
343
        } else {
344
            $this->path = $path;
345
        }
346
        $this->server = $server;
347
        if ($port != '') {
348
            $this->port = $port;
349
        }
350
        if ($method != '') {
351
            $this->method = $method;
352
        }
353
354
        // if ZLIB is enabled, let the client by default accept compressed responses
355 99
        if (function_exists('gzinflate') || (
356
                function_exists('curl_version') && (($info = curl_version()) &&
357 99
                    ((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
358 99
            )
359 99
        ) {
360 99
            $this->accepted_compression = array('gzip', 'deflate');
361 99
        }
362 99
363
        // keepalives: enabled by default
364
        $this->keepalive = true;
365
366
        // by default the xml parser can support these 3 charset encodings
367
        $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
368
369
        // NB: this is disabled to avoid making all the requests sent huge... mbstring supports more than 80 charsets!
370
        //$ch = $this->getCharsetEncoder();
371
        //$this->accepted_charset_encodings = $ch->knownCharsets();
372
373
        // initialize user_agent string
374
        $this->user_agent = PhpXmlRpc::$xmlrpcName . ' ' . PhpXmlRpc::$xmlrpcVersion;
375
    }
376
377
    /**
378
     * @param string $name see all the OPT_ constants
379
     * @param mixed $value
380
     * @return $this
381
     * @throws ValueErrorException on unsupported option
382
     */
383
    public function setOption($name, $value)
384
    {
385
        if (in_array($name, static::$options)) {
386
            $this->$name = $value;
387
            return $this;
388
        }
389
390
        throw new ValueErrorException("Unsupported option '$name'");
391
    }
392
393
    /**
394
     * @param string $name see all the OPT_ constants
395
     * @return mixed
396
     * @throws ValueErrorException on unsupported option
397
     */
398
    public function getOption($name)
399
    {
400
        if (in_array($name, static::$options)) {
401
            return $this->$name;
402
        }
403
404
        throw new ValueErrorException("Unsupported option '$name'");
405
    }
406
407
    /**
408
     * Returns the complete list of Client options, with their value.
409
     * @return array
410
     */
411
    public function getOptions()
412
    {
413
        $values = array();
414
        foreach (static::$options as $opt) {
415
            $values[$opt] = $this->getOption($opt);
416
        }
417
        return $values;
418 580
    }
419
420 580
    /**
421 580
     * @param array $options key: any valid option (see all the OPT_ constants)
422
     * @return $this
423
     * @throws ValueErrorException on unsupported option
424
     */
425
    public function setOptions($options)
426
    {
427 580
        foreach ($options as $name => $value) {
428
            $this->setOption($name, $value);
429 580
        }
430
431
        return $this;
432
    }
433
434
    /**
435
     * Enable/disable the echoing to screen of the xml-rpc responses received. The default is not to output anything.
436
     *
437
     * The debugging information at level 1 includes the raw data returned from the XML-RPC server it was querying
438
     * (including bot HTTP headers and the full XML payload), and the PHP value the client attempts to create to
439
     * represent the value returned by the server.
440
     * At level 2, the complete payload of the xml-rpc request is also printed, before being sent to the server.
441
     * At level -1, the Response objects returned by send() calls will not carry information about the http response's
442
     * cookies, headers and body, which might save some memory
443
     *
444
     * This option can be very useful when debugging servers as it allows you to see exactly what the client sends and
445
     * the server returns. Never leave it enabled for production!
446 66
     *
447
     * @param integer $level values -1, 0, 1 and 2 are supported
448 66
     * @return $this
449 66
     */
450
    public function setDebug($level)
451
    {
452
        $this->debug = $level;
453
        return $this;
454
    }
455
456
    /**
457
     * Sets the username and password for authorizing the client to the server.
458
     *
459
     * With the default (HTTP) transport, this information is used for HTTP Basic authorization.
460
     * Note that username and password can also be set using the class constructor.
461
     * With HTTP 1.1 and HTTPS transport, NTLM and Digest authentication protocols are also supported. To enable them use
462
     * the constants CURLAUTH_DIGEST and CURLAUTH_NTLM as values for the auth type parameter.
463
     *
464
     * @param string $user username
465
     * @param string $password password
466
     * @param integer $authType auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC
467
     *                          (basic auth). Note that auth types NTLM and Digest will only work if the Curl php
468
     *                          extension is enabled.
469
     * @return $this
470
     */
471
    public function setCredentials($user, $password, $authType = 1)
472
    {
473
        $this->username = $user;
474
        $this->password = $password;
475
        $this->authtype = $authType;
476
        return $this;
477
    }
478
479
    /**
480
     * Set the optional certificate and passphrase used in SSL-enabled communication with a remote server.
481
     *
482
     * Note: to retrieve information about the client certificate on the server side, you will need to look into the
483
     * environment variables which are set up by the webserver. Different webservers will typically set up different
484
     * variables.
485
     *
486
     * @param string $cert the name of a file containing a PEM formatted certificate
487
     * @param string $certPass the password required to use it
488
     * @return $this
489
     */
490
    public function setCertificate($cert, $certPass = '')
491
    {
492
        $this->cert = $cert;
493
        $this->certpass = $certPass;
494
        return $this;
495 697
    }
496
497
    /**
498
     * Add a CA certificate to verify server with in SSL-enabled communication when SetSSLVerifypeer has been set to TRUE.
499 697
     *
500 117
     * See the php manual page about CURLOPT_CAINFO for more details.
501
     *
502
     * @param string $caCert certificate file name (or dir holding certificates)
503 697
     * @param bool $isDir set to true to indicate cacert is a dir. defaults to false
504
     * @return $this
505 66
     */
506
    public function setCaCertificate($caCert, $isDir = false)
507 66
    {
508 697
        if ($isDir) {
509 28
            $this->cacertdir = $caCert;
510 28
        } else {
511 28
            $this->cacert = $caCert;
512
        }
513
        return $this;
514
    }
515 697
516
    /**
517
     * Set attributes for SSL communication: private SSL key.
518
     *
519 697
     * NB: does not work in older php/curl installs.
520 697
     * Thanks to Daniel Convissor.
521
     *
522 697
     * @param string $key The name of a file containing a private SSL key
523 322
     * @param string $keyPass The secret password needed to use the private SSL key
524 322
     * @return $this
525 322
     */
526 322
    public function setKey($key, $keyPass)
527
    {
528 322
        $this->key = $key;
529 322
        $this->keypass = $keyPass;
530 322
        return $this;
531 322
    }
532 322
533 322
    /**
534 322
     * Set attributes for SSL communication: verify the remote host's SSL certificate, and cause the connection to fail
535 322
     * if the cert verification fails.
536 322
     *
537 322
     * By default, verification is enabled.
538 322
     * To specify custom SSL certificates to validate the server with, use the setCaCertificate method.
539 322
     *
540
     * @param bool $i enable/disable verification of peer certificate
541 322
     * @return $this
542 322
     * @deprecated use setOption
543 322
     */
544 322
    public function setSSLVerifyPeer($i)
545 322
    {
546
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
547
548
        $this->verifypeer = $i;
549 375
        return $this;
550 375
    }
551 375
552 375
    /**
553
     * Set attributes for SSL communication: verify the remote host's SSL certificate's common name (CN).
554 375
     *
555 375
     * Note that support for value 1 has been removed in cURL 7.28.1
556 375
     *
557 375
     * @param int $i Set to 1 to only the existence of a CN, not that it matches
558 375
     * @return $this
559 375
     * @deprecated use setOption
560 375
     */
561 375
    public function setSSLVerifyHost($i)
562 375
    {
563 375
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
564 375
565 375
        $this->verifyhost = $i;
566
        return $this;
567 375
    }
568 375
569 375
    /**
570
     * Set attributes for SSL communication: SSL version to use. Best left at 0 (default value): let cURL decide
571
     *
572
     * @param int $i
573 697
     * @return $this
574
     * @deprecated use setOption
575
     */
576
    public function setSSLVersion($i)
577
    {
578
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
579
580
        $this->sslversion = $i;
581
        return $this;
582
    }
583
584
    /**
585
     * Set proxy info.
586
     *
587
     * NB: CURL versions before 7.11.10 cannot use a proxy to communicate with https servers.
588
     *
589
     * @param string $proxyHost
590
     * @param string $proxyPort Defaults to 8080 for HTTP and 443 for HTTPS
591
     * @param string $proxyUsername Leave blank if proxy has public access
592
     * @param string $proxyPassword Leave blank if proxy has public access
593
     * @param int $proxyAuthType defaults to CURLAUTH_BASIC (Basic authentication protocol); set to constant CURLAUTH_NTLM
594
     *                           to use NTLM auth with proxy (has effect only when the client uses the HTTP 1.1 protocol)
595
     * @return $this
596
     */
597
    public function setProxy($proxyHost, $proxyPort, $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1)
598
    {
599
        $this->proxy = $proxyHost;
600
        $this->proxyport = $proxyPort;
0 ignored issues
show
Documentation Bug introduced by
The property $proxyport was declared of type integer, but $proxyPort is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
601
        $this->proxy_user = $proxyUsername;
602
        $this->proxy_pass = $proxyPassword;
603
        $this->proxy_authtype = $proxyAuthType;
604
        return $this;
605
    }
606
607
    /**
608
     * Enables/disables reception of compressed xml-rpc responses.
609
     *
610
     * This requires the "zlib" extension to be enabled in your php install. If it is, by default xmlrpc_client
611
     * instances will enable reception of compressed content.
612
     * Note that enabling reception of compressed responses merely adds some standard http headers to xml-rpc requests.
613
     * It is up to the xml-rpc server to return compressed responses when receiving such requests.
614
     *
615
     * @param string $compMethod either 'gzip', 'deflate', 'any' or ''
616
     * @return $this
617
     */
618
    public function setAcceptedCompression($compMethod)
619
    {
620
        if ($compMethod == 'any') {
621
            $this->accepted_compression = array('gzip', 'deflate');
622
        } elseif ($compMethod == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $compMethod of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
623
            $this->accepted_compression = array();
624
        } else {
625
            $this->accepted_compression = array($compMethod);
626
        }
627
        return $this;
628
    }
629
630
    /**
631
     * Enables/disables http compression of xml-rpc request.
632
     *
633
     * This requires the "zlib" extension to be enabled in your php install.
634
     * Take care when sending compressed requests: servers might not support them (and automatic fallback to
635
     * uncompressed requests is not yet implemented).
636
     *
637
     * @param string $compMethod either 'gzip', 'deflate' or ''
638
     * @return $this
639
     * @deprecated use setOption
640
     */
641
    public function setRequestCompression($compMethod)
642
    {
643
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
644
645
        $this->request_compression = $compMethod;
646
        return $this;
647
    }
648
649
    /**
650
     * Adds a cookie to list of cookies that will be sent to server with every further request (useful e.g. for keeping
651
     * session info outside the xml-rpc payload).
652
     *
653
     * NB: by default all cookies set via this method are sent to the server, regardless of path/domain/port. Taking
654
     * advantage of those values is left to the single developer.
655
     *
656
     * @param string $name nb: will not be escaped in the request's http headers. Take care not to use CTL chars or
657
     *                     separators!
658
     * @param string $value
659
     * @param string $path
660
     * @param string $domain
661
     * @param int $port do not use! Cookies are not separated by port
662
     * @return $this
663
     *
664 375
     * @todo check correctness of urlencoding cookie value (copied from php way of doing it, but php is generally sending
665
     *       response not requests. We do the opposite...)
666
     * @todo strip invalid chars from cookie name? As per RFC6265, we should follow RFC2616, Section 2.2
667
     * @todo drop/rename $port parameter. Cookies are not isolated by port!
668
     * @todo feature-creep allow storing 'expires', 'secure', 'httponly' and 'samesite' cookie attributes (we could do
669
     *       as php, and allow $path to be an array of attributes...)
670
     */
671 375
    public function setCookie($name, $value = '', $path = '', $domain = '', $port = null)
672 373
    {
673
        $this->cookies[$name]['value'] = rawurlencode($value);
674
        if ($path || $domain || $port) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $port of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
675
            $this->cookies[$name]['path'] = $path;
676 375
            $this->cookies[$name]['domain'] = $domain;
677 346
            $this->cookies[$name]['port'] = $port;
678
        }
679
        return $this;
680 375
    }
681
682 375
    /**
683 375
     * Directly set cURL options, for extra flexibility (when in cURL mode).
684 64
     *
685 32
     * It allows e.g. to bind client to a specific IP interface / address.
686 32
     *
687 32
     * @param array $options
688 32
     * @return $this
689
     * @deprecated use setOption
690
     */
691 32
    public function setCurlOptions($options)
692 32
    {
693 32
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
694 32
695
        $this->extracurlopts = $options;
696
        return $this;
697
    }
698
699
    /**
700 375
     * @param int $useCurlMode self::USE_CURL_ALWAYS, self::USE_CURL_AUTO or self::USE_CURL_NEVER
701 375
     * @return $this
702 32
     * @deprecated use setOption
703 32
     */
704
    public function setUseCurl($useCurlMode)
705
    {
706
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
707
708 375
        $this->use_curl = $useCurlMode;
709 375
        return $this;
710 73
    }
711
712
713 375
    /**
714 375
     * Set user-agent string that will be used by this client instance in http headers sent to the server.
715 32
     *
716
     * The default user agent string includes the name of this library and the version number.
717
     *
718 32
     * @param string $agentString
719 32
     * @return $this
720 32
     * @deprecated use setOption
721 32
     */
722 32
    public function setUserAgent($agentString)
723
    {
724
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
725
726 32
        $this->user_agent = $agentString;
727
        return $this;
728
    }
729 343
730 343
    /**
731 343
     * @param null|int $component allowed values: PHP_URL_SCHEME, PHP_URL_HOST, PHP_URL_PORT, PHP_URL_PATH
732 343
     * @return string|int Notes: the path component will include query string and fragment; NULL is a valid value for port
733
     *                    (in which case the default port for http/https will be used);
734
     * @throws ValueErrorException on unsupported component
735
     */
736 375
    public function getUrl($component = null)
737 375
    {
738 309
        if (is_int($component) || ctype_digit($component)) {
739 309
            switch ($component) {
740 309
                case PHP_URL_SCHEME:
741
                    return $this->method;
742
                case PHP_URL_HOST:
743
                    return $this->server;
744
                case PHP_URL_PORT:
745
                    return $this->port;
746
                case  PHP_URL_PATH:
747
                    return $this->path;
748
                case '':
749
750
                default:
751
                    throw new ValueErrorException("Unsupported component '$component'");
752
            }
753 309
        }
754
755
        $url = $this->method . '://' . $this->server;
756 309
        if ($this->port == 0 || ($this->port == 80 && in_array($this->method, array('http', 'http10', 'http11', 'h2c'))) ||
757
            ($this->port == 443 && in_array($this->method, array('https', 'h2')))) {
758
            return $url . $this->path;
759
        } else {
760 375
            return $url . ':' . $this->port . $this->path;
761 375
        }
762
    }
763
764
    /**
765
     * Send an xml-rpc request to the server.
766 375
     *
767 375
     * @param Request|Request[]|string $req The Request object, or an array of requests for using multicall, or the
768 375
     *                                      complete xml representation of a request.
769 375
     *                                      When sending an array of Request objects, the client will try to make use of
770 375
     *                                      a single 'system.multicall' xml-rpc method call to forward to the server all
771 375
     *                                      the requests in a single HTTP round trip, unless $this->no_multicall has
772 375
     *                                      been previously set to TRUE (see the multicall method below), in which case
773 375
     *                                      many consecutive xml-rpc requests will be sent. The method will return an
774 375
     *                                      array of Response objects in both cases.
775 375
     *                                      The third variant allows to build by hand (or any other means) a complete
776 375
     *                                      xml-rpc request message, and send it to the server. $req should be a string
777 375
     *                                      containing the complete xml representation of the request. It is e.g. useful
778
     *                                      when, for maximal speed of execution, the request is serialized into a
779 375
     *                                      string using the native php xml-rpc functions (see http://www.php.net/xmlrpc)
780 2
     * @param integer $timeout deprecated. Connection timeout, in seconds, If unspecified, the timeout set with setOption
781
     *                         will be used. If that is 0, a platform specific timeout will apply.
782
     *                         This timeout value is passed to fsockopen(). It is also used for detecting server
783 375
     *                         timeouts during communication (i.e. if the server does not send anything to the client
784 375
     *                         for $timeout seconds, the connection will be closed).
785 32
     * @param string $method deprecated. Use the same value in the constructor instead.
786
     *                       Valid values are 'http', 'http11', 'https', 'h2' and 'h2c'. If left empty,
787
     *                       the http protocol chosen during creation of the object will be used.
788
     *                       Use 'h2' to make the lib attempt to use http/2 over a secure connection, and 'h2c'
789
     *                       for http/2 without tls. Note that 'h2c' will not use the h2c 'upgrade' method, and be
790
     *                       thus incompatible with any server/proxy not supporting http/2. This is because POST
791 32
     *                       request are not compatible with h2c upgrade.
792
     * @return Response|Response[] Note that the client will always return a Response object, even if the call fails
793
     *
794 32
     * @todo allow throwing exceptions instead of returning responses in case of failed calls and/or Fault responses
795
     * @todo refactor: we now support many options besides connection timeout and http version to use. Why only privilege those?
796
     */
797 32
    public function send($req, $timeout = 0, $method = '')
798
    {
799
        if ($method !== '' || $timeout !== 0) {
800 32
            $this->logDeprecation("Using non-default values for arguments 'method' and 'timeout' when calling method " . __METHOD__ . ' is deprecated');
801 32
        }
802
803
        // if user does not specify http protocol, use native method of this client
804 375
        // (i.e. method set during call to constructor)
805
        if ($method == '') {
806 375
            $method = $this->method;
807 64
        }
808
809 311
        if ($timeout == 0) {
810
            $timeout = $this->timeout;
811
        }
812 375
813 375
        if (is_array($req)) {
814
            // $req is an array of Requests
815 375
            return $this->multicall($req, $timeout, $method);
816 375
        } elseif (is_string($req)) {
817 375
            $n = new static::$requestClass('');
818 374
            $n->setPayload($req);
819 367
            $req = $n;
820
        }
821
822 1
        // where req is a Request
823
        $req->setDebug($this->debug);
824
825
        /// @todo we could be smarter about this and force usage of curl in scenarios where it is both available and
826
        ///       needed, such as digest or ntlm auth. Do not attempt to use it for https if not present
827 1
        $useCurl = ($this->use_curl == self::USE_CURL_ALWAYS) || ($this->use_curl == self::USE_CURL_AUTO &&
828 1
                (in_array($method, array('https', 'http11', 'h2c', 'h2'))));
829
830 1
        // BC - we go through sendPayloadCURL/sendPayloadSocket in case some subclass reimplemented those
831
        if ($useCurl) {
832
            $r = $this->sendPayloadCURL(
0 ignored issues
show
Deprecated Code introduced by
The function PhpXmlRpc\Client::sendPayloadCURL() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

832
            $r = /** @scrutinizer ignore-deprecated */ $this->sendPayloadCURL(
Loading history...
833 374
                $req,
834
                $this->server,
835
                $this->port,
836
                $timeout,
837
                $this->username,
838
                $this->password,
839
                $this->authtype,
840
                $this->cert,
841
                $this->certpass,
842
                $this->cacert,
843 374
                $this->cacertdir,
844
                $this->proxy,
845
                $this->proxyport,
846
                $this->proxy_user,
847 374
                $this->proxy_pass,
848 374
                $this->proxy_authtype,
849 374
                // BC
850
                $method == 'http11' ? 'http' : $method,
851 374
                $this->keepalive,
852
                $this->key,
853 374
                $this->keypass,
854
                $this->sslversion
855
            );
856
        } else {
857
            $r = $this->sendPayloadSocket(
0 ignored issues
show
Deprecated Code introduced by
The function PhpXmlRpc\Client::sendPayloadSocket() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

857
            $r = /** @scrutinizer ignore-deprecated */ $this->sendPayloadSocket(
Loading history...
858
                $req,
859
                $this->server,
860
                $this->port,
861
                $timeout,
862
                $this->username,
863
                $this->password,
864
                $this->authtype,
865
                $this->cert,
866
                $this->certpass,
867
                $this->cacert,
868
                $this->cacertdir,
869
                $this->proxy,
870
                $this->proxyport,
871
                $this->proxy_user,
872
                $this->proxy_pass,
873
                $this->proxy_authtype,
874
                $method,
875
                $this->key,
876
                $this->keypass,
877
                $this->sslversion
878
            );
879
        }
880
881
        return $r;
882
    }
883
884
    /**
885
     * @param Request $req
886 322
     * @param string $method
887
     * @param string $server
888
     * @param int $port
889
     * @param string $path
890
     * @param array $opts
891 322
     * @return Response
892
     */
893
    protected function sendViaSocket($req, $method, $server, $port, $path, $opts)
894
    {
895 322
        /// @todo log a warning if passed an unsupported method
896
897 96
        // Only create the payload if it was not created previously
898 96
        /// @todo what if the request's payload was created with a different encoding?
899
        ///       Also, if we do not call serialize(), the request will not set its content-type to have the charset declared
900
        $payload = $req->getPayload();
901
        if (empty($payload)) {
902
            $payload = $req->serialize($opts['request_charset_encoding']);
903
        }
904 322
905 322
        // Deflate request body and set appropriate request headers
906
        $encodingHdr = '';
907
        if (function_exists('gzdeflate') && ($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate')) {
908
            if ($opts['request_compression'] == 'gzip') {
909
                $a = @gzencode($payload);
910 322
                if ($a) {
911
                    $payload = $a;
912
                    $encodingHdr = "Content-Encoding: gzip\r\n";
913
                }
914
            } else {
915 322
                $a = @gzcompress($payload);
916
                if ($a) {
917 322
                    $payload = $a;
918
                    $encodingHdr = "Content-Encoding: deflate\r\n";
919
                }
920
            }
921
        }
922
923
        // thanks to Grant Rauscher <[email protected]> for this
924
        $credentials = '';
925
        if ($opts['username'] != '') {
926
            $credentials = 'Authorization: Basic ' . base64_encode($opts['username'] . ':' . $opts['password']) . "\r\n";
927
            if ($opts['authtype'] != 1) {
928
                /// @todo make this a proper error, i.e. return a failure
929 322
                $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported with HTTP 1.0');
930
            }
931
        }
932 1
933 1
        $acceptedEncoding = '';
934 1
        if (is_array($opts['accepted_compression']) && count($opts['accepted_compression'])) {
935 1
            $acceptedEncoding = 'Accept-Encoding: ' . implode(', ', $opts['accepted_compression']) . "\r\n";
936 1
        }
937
938
        if ($port == 0) {
939 322
            $port = ($method === 'https') ? 443 : 80;
940 160
        }
941
942 322
        $proxyCredentials = '';
943
        if ($opts['proxy']) {
944 322
            if ($opts['proxyport'] == 0) {
945
                $opts['proxyport'] = 8080;
946
            }
947
            $connectServer = $opts['proxy'];
948
            $connectPort = $opts['proxyport'];
949
            $transport = 'tcp';
950 322
            /// @todo check: should we not use https in some cases?
951
            $uri = 'http://' . $server . ':' . $port . $path;
952
            if ($opts['proxy_user'] != '') {
953 323
                if ($opts['proxy_authtype'] != 1) {
954
                    /// @todo make this a proper error, i.e. return a failure
955
                    $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported with HTTP 1.0');
956
                }
957
                $proxyCredentials = 'Proxy-Authorization: Basic ' . base64_encode($opts['proxy_user'] . ':' .
958 323
                    $opts['proxy_pass']) . "\r\n";
959 322
            }
960 226
        } else {
961
            $connectServer = $server;
962 96
            $connectPort = $port;
963
            $transport = ($method === 'https') ? 'tls' : 'tcp';
964
            $uri = $path;
965
        }
966
967 323
        // Cookie generation, as per RFC6265
968 302
        // NB: the following code does not honour 'expires', 'path' and 'domain' cookie attributes set to client obj by the user...
969
        $cookieHeader = '';
970
        if (count($opts['cookies'])) {
971
            $version = '';
972 323
            foreach ($opts['cookies'] as $name => $cookie) {
973 323
                /// @todo should we sanitize the cookie value on behalf of the user? See setCookie comments
974 64
                $cookieHeader .= ' ' . $name . '=' . $cookie['value'] . ";";
975 32
            }
976 32
            $cookieHeader = 'Cookie:' . $version . substr($cookieHeader, 0, -1) . "\r\n";
977 32
        }
978 32
979
        // omit port if default
980
        if (($port == 80 && in_array($method, array('http', 'http10'))) || ($port == 443 && $method == 'https')) {
981 32
            $port = '';
982 32
        } else {
983 32
            $port = ':' . $port;
984 64
        }
985
986
        $op = 'POST ' . $uri . " HTTP/1.0\r\n" .
987
            'User-Agent: ' . $opts['user_agent'] . "\r\n" .
988 259
            'Host: ' . $server . $port . "\r\n" .
989
            $credentials .
990
            $proxyCredentials .
991 323
            $acceptedEncoding .
992 323
            $encodingHdr .
993 64
            'Accept-Charset: ' . implode(',', $opts['accepted_charset_encodings']) . "\r\n" .
994
            $cookieHeader .
995 259
            'Content-Type: ' . $req->getContentType() . "\r\nContent-Length: " .
996 32
            strlen($payload) . "\r\n\r\n" .
997
            $payload;
998
999 227
        if ($opts['debug'] > 1) {
1000
            $this->getLogger()->debug("---SENDING---\n$op\n---END---");
1001
        }
1002 323
1003 323
        $contextOptions = array();
1004 322
        if ($method == 'https') {
1005
            if ($opts['cert'] != '') {
1006
                $contextOptions['ssl']['local_cert'] = $opts['cert'];
1007 56
                if ($opts['certpass'] != '') {
1008
                    $contextOptions['ssl']['passphrase'] = $opts['certpass'];
1009
                }
1010
            }
1011 323
            if ($opts['cacert'] != '') {
1012
                $contextOptions['ssl']['cafile'] = $opts['cacert'];
1013 323
            }
1014
            if ($opts['cacertdir'] != '') {
1015
                $contextOptions['ssl']['capath'] = $opts['cacertdir'];
1016
            }
1017 323
            if ($opts['key'] != '') {
1018
                $contextOptions['ssl']['local_pk'] = $opts['key'];
1019 323
            }
1020
            $contextOptions['ssl']['verify_peer'] = $opts['verifypeer'];
1021 323
            $contextOptions['ssl']['verify_peer_name'] = $opts['verifypeer'];
1022
        }
1023
1024 323
        $context = stream_context_create($contextOptions);
1025
1026
        if ($opts['timeout'] <= 0) {
1027
            $connectTimeout = ini_get('default_socket_timeout');
1028 323
        } else {
1029
            $connectTimeout = $opts['timeout'];
1030
        }
1031 66
1032 64
        $this->errno = 0;
1033
        $this->errstr = '';
1034 2
1035
        $fp = @stream_socket_client("$transport://$connectServer:$connectPort", $this->errno, $this->errstr, $connectTimeout,
1036
            STREAM_CLIENT_CONNECT, $context);
1037
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
1038 323
            if ($opts['timeout'] > 0) {
1039
                stream_set_timeout($fp, $opts['timeout'], 0);
1040 323
            }
1041 161
        } else {
1042
            if ($this->errstr == '') {
1043
                $err = error_get_last();
1044 323
                $this->errstr = $err['message'];
1045 64
            }
1046
1047
            $this->errstr = 'Connect error: ' . $this->errstr;
1048
            $r = new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['http_error'], $this->errstr . ' (' . $this->errno . ')');
1049
1050 323
            return $r;
1051
        }
1052 323
1053
        if (!fputs($fp, $op, strlen($op))) {
1054 323
            fclose($fp);
1055 272
            $this->errstr = 'Write error';
1056
            return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['http_error'], $this->errstr);
1057
        }
1058 323
1059 323
        // Close socket before parsing.
1060 32
        // It should yield slightly better execution times, and make easier recursive calls (e.g. to follow http redirects)
1061 32
        $ipd = '';
1062 291
        do {
1063
            // shall we check for $data === FALSE?
1064
            // as per the manual, it signals an error
1065 291
            $ipd .= fread($fp, 32768);
1066 32
        } while (!feof($fp));
1067 32
        fclose($fp);
1068 259
1069 32
        return $req->parseResponse($ipd, false, $opts['return_type']);
1070 32
    }
1071
1072
    /**
1073 323
     * Contributed by Justin Miller <[email protected]>
1074 32
     * Requires curl to be built into PHP
1075 32
     * NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
1076 32
     *
1077
     * @param Request $req
1078
     * @param string $method
1079
     * @param string $server
1080
     * @param int $port
1081
     * @param string $path
1082 323
     * @param array $opts the keys/values match self::getOptions
1083
     * @return Response
1084 96
     *
1085
     * @todo the $path arg atm is ignored. What to do if it is != $this->path?
1086
     */
1087
    protected function sendViaCURL($req, $method, $server, $port, $path, $opts)
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1087
    protected function sendViaCURL($req, $method, $server, $port, /** @scrutinizer ignore-unused */ $path, $opts)

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

Loading history...
1088 96
    {
1089
        if (!function_exists('curl_init')) {
1090
            $this->errstr = 'CURL unavailable on this install';
1091
            return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['no_curl'], PhpXmlRpc::$xmlrpcstr['no_curl']);
1092 96
        }
1093
        if ($method == 'https' || $method == 'h2') {
1094 96
            // q: what about installs where we get back a string, but curl is linked to other ssl libs than openssl?
1095
            if (($info = curl_version()) &&
1096
                ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version'])))
0 ignored issues
show
introduced by
The condition is_string($info) is always false.
Loading history...
1097 96
            ) {
1098
                $this->errstr = 'SSL unavailable on this install';
1099
                return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['no_ssl'], PhpXmlRpc::$xmlrpcstr['no_ssl']);
1100
            }
1101 96
        }
1102
        if (($method == 'h2' && !defined('CURL_HTTP_VERSION_2_0')) ||
1103
            ($method == 'h2c' && !defined('CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE'))) {
1104
            $this->errstr = 'HTTP/2 unavailable on this install';
1105 96
            return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['no_http2'], PhpXmlRpc::$xmlrpcstr['no_http2']);
1106
        }
1107
1108
        // BC - we go through prepareCurlHandle in case some subclass reimplemented it
1109
        $curl = $this->prepareCurlHandle($req, $server, $port, $opts['timeout'], $opts['username'], $opts['password'],
0 ignored issues
show
Deprecated Code introduced by
The function PhpXmlRpc\Client::prepareCurlHandle() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1109
        $curl = /** @scrutinizer ignore-deprecated */ $this->prepareCurlHandle($req, $server, $port, $opts['timeout'], $opts['username'], $opts['password'],
Loading history...
1110 96
            $opts['authtype'], $opts['cert'], $opts['certpass'], $opts['cacert'], $opts['cacertdir'], $opts['proxy'],
1111
            $opts['proxyport'], $opts['proxy_user'], $opts['proxy_pass'], $opts['proxy_authtype'], $method,
1112 96
            $opts['keepalive'], $opts['key'], $opts['keypass'], $opts['sslversion']);
1113
1114
        if (!$curl) {
1115
            return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['curl_fail'], PhpXmlRpc::$xmlrpcstr['curl_fail'] .
1116 323
                ': error during curl initialization. Check php error log for details');
1117 64
        }
1118
1119
        $result = curl_exec($curl);
1120 64
1121 64
        if ($opts['debug'] > 1) {
1122
            $message = "---CURL INFO---\n";
1123
            foreach (curl_getinfo($curl) as $name => $val) {
1124
                if (is_array($val)) {
1125
                    $val = implode("\n", $val);
1126
                }
1127
                $message .= $name . ': ' . $val . "\n";
1128
            }
1129
            $message .= '---END---';
1130
            $this->getLogger()->debug($message);
1131
        }
1132
1133 323
        if (!$result) {
1134 271
            /// @todo we should use a better check here - what if we get back '' or '0'?
1135 271
1136 271
            $this->errstr = 'no response';
1137
            $resp = new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['curl_fail'], PhpXmlRpc::$xmlrpcstr['curl_fail'] .
1138 271
                ': ' . curl_error($curl));
1139
            curl_close($curl);
1140
            if ($opts['keepalive']) {
1141 323
                $this->xmlrpc_curl_handle = null;
1142
            }
1143
        } else {
1144
            if (!$opts['keepalive']) {
1145 323
                curl_close($curl);
1146
            }
1147
            $resp = $req->parseResponse($result, true, $opts['return_type']);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type true; however, parameter $data of PhpXmlRpc\Request::parseResponse() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1147
            $resp = $req->parseResponse(/** @scrutinizer ignore-type */ $result, true, $opts['return_type']);
Loading history...
1148
            if ($opts['keepalive']) {
1149 323
                /// @todo if we got back a 302 or 308, we should not reuse the curl handle for later calls
1150
                if ($resp->faultCode() == PhpXmlRpc::$xmlrpcerr['http_error']) {
1151
                    curl_close($curl);
1152
                    $this->xmlrpc_curl_handle = null;
1153
                }
1154
            }
1155
        }
1156
1157
        return $resp;
1158
    }
1159
1160
    /**
1161
     * @param Request $req
1162
     * @param string $method
1163
     * @param string $server
1164
     * @param int $port
1165
     * @param string $path
1166
     * @param array $opts the keys/values match self::getOptions
1167
     * @return \CurlHandle|resource|false
1168
     */
1169
    protected function createCURLHandle($req, $method, $server, $port, $path, $opts)
1170
    {
1171
        if ($port == 0) {
1172
            if (in_array($method, array('http', 'http10', 'http11', 'h2c'))) {
1173
                $port = 80;
1174 66
            } else {
1175
                $port = 443;
1176 66
            }
1177
        }
1178
1179 66
        // Only create the payload if it was not created previously
1180 45
        $payload = $req->getPayload();
1181 45
        if (empty($payload)) {
1182
            $payload = $req->serialize($opts['request_charset_encoding']);
1183 45
        }
1184
1185
        // Deflate request body and set appropriate request headers
1186
        $encodingHdr = '';
1187
        /// @todo test for existence of proper function, in case of polyfills
1188
        if (function_exists('gzdeflate') && ($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate')) {
1189
            if ($opts['request_compression'] == 'gzip') {
1190
                $a = @gzencode($payload);
1191
                if ($a) {
1192
                    $payload = $a;
1193
                    $encodingHdr = 'Content-Encoding: gzip';
1194
                }
1195
            } else {
1196
                $a = @gzcompress($payload);
1197
                if ($a) {
1198
                    $payload = $a;
1199
                    $encodingHdr = 'Content-Encoding: deflate';
1200
                }
1201 23
            }
1202
        }
1203
1204 23
        if (!$opts['keepalive'] || !$this->xmlrpc_curl_handle) {
1205 23
            if ($method == 'http11' || $method == 'http10' || $method == 'h2c') {
1206
                $protocol = 'http';
1207
            } else {
1208
                if ($method == 'h2') {
1209 23
                    $protocol = 'https';
1210 23
                } else {
1211
                    // http, https
1212
                    $protocol = $method;
1213
                    if (strpos($protocol, ':') !== false) {
1214
                        $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ": warning - attempted hacking attempt?. The curl protocol requested for the call is: '$protocol'");
1215
                        return false;
1216
                    }
1217
                }
1218
            }
1219
            $curl = curl_init($protocol . '://' . $server . ':' . $port . $path);
1220
            if (!$curl) {
1221 23
                return false;
1222
            }
1223
            if ($opts['keepalive']) {
1224
                $this->xmlrpc_curl_handle = $curl;
1225
            }
1226
        } else {
1227
            $curl = $this->xmlrpc_curl_handle;
1228
        }
1229
1230
        // results into variable
1231
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
1232
1233
        if ($opts['debug'] > 1) {
1234
            curl_setopt($curl, CURLOPT_VERBOSE, true);
1235 45
            /// @todo redirect curlopt_stderr to some stream which can be piped to the logger
1236
        }
1237
        curl_setopt($curl, CURLOPT_USERAGENT, $opts['user_agent']);
1238 45
        // required for XMLRPC: post the data
1239 45
        curl_setopt($curl, CURLOPT_POST, 1);
1240 45
        // the data
1241 45
        curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
1242 45
1243 45
        // return the header too
1244 45
        curl_setopt($curl, CURLOPT_HEADER, 1);
1245
1246 45
        // NB: if we set an empty string, CURL will add http header indicating
1247 45
        // ALL methods it is supporting. This is possibly a better option than letting the user tell what curl can / cannot do...
1248
        if (is_array($opts['accepted_compression']) && count($opts['accepted_compression'])) {
1249 45
            //curl_setopt($curl, CURLOPT_ENCODING, implode(',', $opts['accepted_compression']));
1250 45
            // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
1251
            if (count($opts['accepted_compression']) == 1) {
1252
                curl_setopt($curl, CURLOPT_ENCODING, $opts['accepted_compression'][0]);
1253 45
            } else {
1254
                curl_setopt($curl, CURLOPT_ENCODING, '');
1255 45
            }
1256
        }
1257
        // extra headers
1258
        $headers = array('Content-Type: ' . $req->getContentType(), 'Accept-Charset: ' . implode(',', $opts['accepted_charset_encodings']));
1259
        // if no keepalive is wanted, let the server know it in advance
1260
        if (!$opts['keepalive']) {
1261 45
            $headers[] = 'Connection: close';
1262
        }
1263 45
        // request compression header
1264
        if ($encodingHdr) {
1265 45
            $headers[] = $encodingHdr;
1266
        }
1267 22
1268 22
        // Fix the HTTP/1.1 417 Expectation Failed Bug (curl by default adds a 'Expect: 100-continue' header when POST
1269
        // size exceeds 1025 bytes, apparently)
1270
        $headers[] = 'Expect:';
1271 22
1272 22
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
1273
        // timeout is borked
1274
        if ($opts['timeout']) {
1275
            curl_setopt($curl, CURLOPT_TIMEOUT, $opts['timeout'] == 1 ? 1 : $opts['timeout'] - 1);
1276 22
        }
1277 22
1278 22
        switch ($method) {
1279 22
            case 'http10':
1280
                curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
1281
                break;
1282 22
            case 'http11':
1283 22
                curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
1284 22
                break;
1285
            case 'h2c':
1286
                if (defined('CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE')) {
1287
                    curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
1288 22
                } else {
1289 22
                    /// @todo make this a proper error, i.e. return a failure
1290 22
                    $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. HTTP2 is not supported by the current PHP/curl install');
1291
                }
1292 22
                break;
1293 22
            case 'h2':
1294
                curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
1295
                break;
1296 22
        }
1297 22
1298
        if ($opts['username'] && $opts['password']) {
1299
            curl_setopt($curl, CURLOPT_USERPWD, $opts['username'] . ':' . $opts['password']);
1300 22
            if (defined('CURLOPT_HTTPAUTH')) {
1301 22
                curl_setopt($curl, CURLOPT_HTTPAUTH, $opts['authtype']);
1302
            } elseif ($opts['authtype'] != 1) {
1303
                /// @todo make this a proper error, i.e. return a failure
1304
                $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported by the current PHP/curl install');
1305
            }
1306
        }
1307 22
1308
        // note: h2c is http2 without the https. No need to have it in this IF
1309
        if ($method == 'https' || $method == 'h2') {
1310
            // set cert file
1311 24
            if ($opts['cert']) {
1312 24
                curl_setopt($curl, CURLOPT_SSLCERT, $opts['cert']);
1313
            }
1314
            // set cert password
1315 24
            if ($opts['certpass']) {
1316 24
                curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $opts['certpass']);
1317
            }
1318
            // whether to verify remote host's cert
1319
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $opts['verifypeer']);
1320 24
            // set ca certificates file/dir
1321 24
            if ($opts['cacert']) {
1322 24
                curl_setopt($curl, CURLOPT_CAINFO, $opts['cacert']);
1323 24
            }
1324 24
            if ($opts['cacertdir']) {
1325
                curl_setopt($curl, CURLOPT_CAPATH, $opts['cacertdir']);
1326
            }
1327
            // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
1328 24
            if ($opts['key']) {
1329 24
                curl_setopt($curl, CURLOPT_SSLKEY, $opts['key']);
1330 22
            }
1331 22
            // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
1332
            if ($opts['keypass']) {
1333 22
                curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $opts['keypass']);
1334
            }
1335
            // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that
1336 22
            // it matches the hostname used
1337
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $opts['verifyhost']);
1338 22
            // allow usage of different SSL versions
1339
            curl_setopt($curl, CURLOPT_SSLVERSION, $opts['sslversion']);
1340
        }
1341 22
1342 22
        // proxy info
1343
        if ($opts['proxy']) {
1344
            if ($opts['proxyport'] == 0) {
1345
                $opts['proxyport'] = 8080; // NB: even for HTTPS, local connection is on port 8080
1346
            }
1347
            curl_setopt($curl, CURLOPT_PROXY, $opts['proxy'] . ':' . $opts['proxyport']);
1348 24
            if ($opts['proxy_user']) {
1349
                curl_setopt($curl, CURLOPT_PROXYUSERPWD, $opts['proxy_user'] . ':' . $opts['proxy_pass']);
1350
                if (defined('CURLOPT_PROXYAUTH')) {
1351
                    curl_setopt($curl, CURLOPT_PROXYAUTH, $opts['proxy_authtype']);
1352
                } elseif ($opts['proxy_authtype'] != 1) {
1353
                    /// @todo make this a proper error, i.e. return a failure
1354
                    $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported by the current PHP/curl install');
1355
                }
1356
            }
1357
        }
1358
1359
        // NB: should we build cookie http headers by hand rather than let CURL do it?
1360
        // NB: the following code does not honour 'expires', 'path' and 'domain' cookie attributes set to client obj by the user...
1361
        if (count($opts['cookies'])) {
1362
            $cookieHeader = '';
1363
            foreach ($opts['cookies'] as $name => $cookie) {
1364
                $cookieHeader .= $name . '=' . $cookie['value'] . '; ';
1365
            }
1366
            curl_setopt($curl, CURLOPT_COOKIE, substr($cookieHeader, 0, -2));
1367
        }
1368
1369
        foreach ($opts['extracurlopts'] as $opt => $val) {
1370
            curl_setopt($curl, $opt, $val);
1371
        }
1372
1373
        if ($opts['debug'] > 1) {
1374
            $this->getLogger()->debug("---SENDING---\n$payload\n---END---");
1375
        }
1376
1377
        return $curl;
1378
    }
1379
1380
    /**
1381
     * Send an array of requests and return an array of responses.
1382
     *
1383
     * Unless $this->no_multicall has been set to true, it will try first to use one single xml-rpc call to server method
1384
     * system.multicall, and revert to sending many successive calls in case of failure.
1385
     * This failure is also stored in $this->no_multicall for subsequent calls.
1386
     * Unfortunately, there is no server error code universally used to denote the fact that multicall is unsupported,
1387
     * so there is no way to reliably distinguish between that and a temporary failure.
1388
     * If you are sure that server supports multicall and do not want to fallback to using many single calls, set the
1389
     * fourth parameter to FALSE.
1390
     *
1391
     * NB: trying to shoehorn extra functionality into existing syntax has resulted
1392
     * in pretty much convoluted code...
1393
     *
1394
     * @param Request[] $reqs an array of Request objects
1395
     * @param integer $timeout deprecated - connection timeout (in seconds). See the details in the docs for the send() method
1396
     * @param string $method deprecated - the http protocol variant to be used. See the details in the docs for the send() method
1397
     * @param boolean $fallback When true, upon receiving an error during multicall, multiple single calls will be
1398
     *                         attempted
1399
     * @return Response[]
1400
     */
1401
    public function multicall($reqs, $timeout = 0, $method = '', $fallback = true)
1402
    {
1403
        if ($method == '') {
1404
            $method = $this->method;
1405
        }
1406
1407
        if (!$this->no_multicall) {
1408
            $results = $this->_try_multicall($reqs, $timeout, $method);
1409
            /// @todo how to handle the case of $this->return_type = xml?
1410
            if (is_array($results)) {
1411
                // System.multicall succeeded
1412
                return $results;
1413
            } else {
1414
                // either system.multicall is unsupported by server, or the call failed for some other reason.
1415
                // Feature creep: is there a way to tell apart unsupported multicall from other faults?
1416
                if ($fallback) {
1417
                    // Don't try it next time...
1418
                    $this->no_multicall = true;
1419
                } else {
1420
                    $result = $results;
1421
                }
1422
            }
1423
        } else {
1424
            // override fallback, in case careless user tries to do two
1425
            // opposite things at the same time
1426
            $fallback = true;
1427
        }
1428
1429
        $results = array();
1430
        if ($fallback) {
1431
            // system.multicall is (probably) unsupported by server: emulate multicall via multiple requests
1432
            /// @todo use curl multi_ functions to make this quicker (see the implementation in the parallel.php demo)
1433
            foreach ($reqs as $req) {
1434
                $results[] = $this->send($req, $timeout, $method);
1435
            }
1436
        } else {
1437
            // user does NOT want to fallback on many single calls: since we should always return an array of responses,
1438
            // we return an array with the same error repeated n times
1439
            foreach ($reqs as $req) {
1440
                $results[] = $result;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
1441
            }
1442
        }
1443
1444
        return $results;
1445
    }
1446
1447
    /**
1448
     * Attempt to boxcar $reqs via system.multicall.
1449
     *
1450
     * @param Request[] $reqs
1451
     * @param int $timeout
1452
     * @param string $method
1453
     * @return Response[]|Response a single Response when the call returned a fault / does not conform to what we expect
1454
     *                             from a multicall response
1455
     */
1456
    private function _try_multicall($reqs, $timeout, $method)
1457
    {
1458
        // Construct multicall request
1459
        $calls = array();
1460
        foreach ($reqs as $req) {
1461
            $call['methodName'] = new Value($req->method(), 'string');
1462
            $numParams = $req->getNumParams();
1463
            $params = array();
1464
            for ($i = 0; $i < $numParams; $i++) {
1465
                $params[$i] = $req->getParam($i);
1466
            }
1467
            $call['params'] = new Value($params, 'array');
1468
            $calls[] = new Value($call, 'struct');
1469
        }
1470
        $multiCall = new Request('system.multicall');
1471
        $multiCall->addParam(new Value($calls, 'array'));
1472
1473
        // Attempt RPC call
1474
        $result = $this->send($multiCall, $timeout, $method);
1475
1476
        if ($result->faultCode() != 0) {
1477
            // call to system.multicall failed
1478
            return $result;
1479
        }
1480
1481
        // Unpack responses.
1482
        $rets = $result->value();
1483
        $response = array();
1484
1485
        if ($this->return_type == 'xml') {
1486
            for ($i = 0; $i < count($reqs); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1487
                $response[] = new Response($rets, 0, '', 'xml', $result->httpResponse());
1488
            }
1489
1490
        } elseif ($this->return_type == 'phpvals') {
1491
            if (!is_array($rets)) {
1492
                // bad return type from system.multicall
1493
                return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1494
                    PhpXmlRpc::$xmlrpcstr['multicall_error'] . ': not an array', 'phpvals', $result->httpResponse());
1495
            }
1496
            $numRets = count($rets);
1497
            if ($numRets != count($reqs)) {
1498
                // wrong number of return values.
1499
                return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1500
                    PhpXmlRpc::$xmlrpcstr['multicall_error'] . ': incorrect number of responses', 'phpvals',
1501
                    $result->httpResponse());
1502
            }
1503
1504
            for ($i = 0; $i < $numRets; $i++) {
1505
                $val = $rets[$i];
1506
                if (!is_array($val)) {
1507
                    return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1508
                        PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i is not an array or struct",
1509
                        'phpvals', $result->httpResponse());
1510
                }
1511
                switch (count($val)) {
1512
                    case 1:
1513
                        if (!isset($val[0])) {
1514
                            // Bad value
1515
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1516
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has no value",
1517
                                'phpvals', $result->httpResponse());
1518
                        }
1519
                        // Normal return value
1520
                        $response[$i] = new Response($val[0], 0, '', 'phpvals', $result->httpResponse());
1521
                        break;
1522
                    case 2:
1523
                        /// @todo remove usage of @: it is apparently quite slow
1524
                        $code = @$val['faultCode'];
1525
                        if (!is_int($code)) {
1526
                            /// @todo should we check that it is != 0?
1527
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1528
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no faultCode",
1529
                                'phpvals', $result->httpResponse());
1530
                        }
1531
                        $str = @$val['faultString'];
1532
                        if (!is_string($str)) {
1533
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1534
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no FaultString",
1535
                                'phpvals', $result->httpResponse());
1536
                        }
1537
                        $response[$i] = new Response(0, $code, $str, 'phpvals', $result->httpResponse());
1538
                        break;
1539
                    default:
1540
                        return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1541
                            PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has too many items",
1542
                            'phpvals', $result->httpResponse());
1543
                }
1544
            }
1545
1546
        } else {
1547
            // return type == 'xmlrpcvals'
1548
            if ($rets->kindOf() != 'array') {
1549
                return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1550
                    PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i is not an array", 'xmlrpcvals',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $i seems to be defined by a foreach iteration on line 1460. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1551
                    $result->httpResponse());
1552
            }
1553
            $numRets = $rets->count();
1554
            if ($numRets != count($reqs)) {
1555
                // wrong number of return values.
1556
                return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1557
                    PhpXmlRpc::$xmlrpcstr['multicall_error'] . ': incorrect number of responses', 'xmlrpcvals',
1558
                    $result->httpResponse());
1559
            }
1560
1561
            foreach ($rets as $i => $val) {
1562
                switch ($val->kindOf()) {
1563
                    case 'array':
1564
                        if ($val->count() != 1) {
1565
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1566
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has too many items",
1567
                                'phpvals', $result->httpResponse());
1568
                        }
1569
                        // Normal return value
1570
                        $response[] = new Response($val[0], 0, '', 'xmlrpcvals', $result->httpResponse());
1571
                        break;
1572
                    case 'struct':
1573
                        if ($val->count() != 2) {
1574
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1575
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has too many items",
1576
                                'phpvals', $result->httpResponse());
1577
                        }
1578
                        /** @var Value $code */
1579
                        $code = $val['faultCode'];
1580
                        if ($code->kindOf() != 'scalar' || $code->scalarTyp() != 'int') {
1581
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1582
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no faultCode",
1583
                                'xmlrpcvals', $result->httpResponse());
1584
                        }
1585
                        /** @var Value $str */
1586
                        $str = $val['faultString'];
1587
                        if ($str->kindOf() != 'scalar' || $str->scalarTyp() != 'string') {
1588
                            return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1589
                                PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no faultCode",
1590
                                'xmlrpcvals', $result->httpResponse());
1591
                        }
1592
                        $response[] = new Response(0, $code->scalarVal(), $str->scalarVal(), 'xmlrpcvals', $result->httpResponse());
1593
                        break;
1594
                    default:
1595
                        return new Response(0, PhpXmlRpc::$xmlrpcerr['multicall_error'],
1596
                            PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i is not an array or struct",
1597
                            'xmlrpcvals', $result->httpResponse());
1598
                }
1599
            }
1600
        }
1601
1602
        return $response;
1603
    }
1604
1605
    // *** BC layer ***
1606
1607
    /**
1608
     * @deprecated
1609
     *
1610
     * @param Request $req
1611
     * @param string $server
1612
     * @param int $port
1613
     * @param int $timeout
1614
     * @param string $username
1615
     * @param string $password
1616
     * @param int $authType
1617
     * @param string $proxyHost
1618
     * @param int $proxyPort
1619
     * @param string $proxyUsername
1620
     * @param string $proxyPassword
1621
     * @param int $proxyAuthType
1622
     * @param string $method
1623
     * @return Response
1624
     */
1625
    protected function sendPayloadHTTP10($req, $server, $port, $timeout = 0, $username = '', $password = '',
1626
        $authType = 1, $proxyHost = '', $proxyPort = 0, $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1,
1627
        $method = 'http')
1628
    {
1629
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
1630
1631
        return $this->sendPayloadSocket($req, $server, $port, $timeout, $username, $password, $authType, null, null,
0 ignored issues
show
Deprecated Code introduced by
The function PhpXmlRpc\Client::sendPayloadSocket() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1631
        return /** @scrutinizer ignore-deprecated */ $this->sendPayloadSocket($req, $server, $port, $timeout, $username, $password, $authType, null, null,
Loading history...
1632
            null, null, $proxyHost, $proxyPort, $proxyUsername, $proxyPassword, $proxyAuthType, $method);
1633
    }
1634
1635
    /**
1636
     * @deprecated
1637
     *
1638
     * @param Request $req
1639
     * @param string $server
1640
     * @param int $port
1641
     * @param int $timeout
1642
     * @param string $username
1643
     * @param string $password
1644
     * @param int $authType
1645
     * @param string $cert
1646
     * @param string $certPass
1647
     * @param string $caCert
1648
     * @param string $caCertDir
1649
     * @param string $proxyHost
1650
     * @param int $proxyPort
1651
     * @param string $proxyUsername
1652
     * @param string $proxyPassword
1653
     * @param int $proxyAuthType
1654
     * @param bool $keepAlive
1655
     * @param string $key
1656
     * @param string $keyPass
1657
     * @param int $sslVersion
1658
     * @return Response
1659
     */
1660
    protected function sendPayloadHTTPS($req, $server, $port, $timeout = 0, $username = '', $password = '',
1661
        $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0,
1662
        $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $keepAlive = false, $key = '', $keyPass = '',
1663
        $sslVersion = 0)
1664
    {
1665
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
1666
1667
        return $this->sendPayloadCURL($req, $server, $port, $timeout, $username,
0 ignored issues
show
Deprecated Code introduced by
The function PhpXmlRpc\Client::sendPayloadCURL() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1667
        return /** @scrutinizer ignore-deprecated */ $this->sendPayloadCURL($req, $server, $port, $timeout, $username,
Loading history...
1668
            $password, $authType, $cert, $certPass, $caCert, $caCertDir, $proxyHost, $proxyPort,
1669
            $proxyUsername, $proxyPassword, $proxyAuthType, 'https', $keepAlive, $key, $keyPass, $sslVersion);
1670
    }
1671
1672
    /**
1673
     * @deprecated
1674
     *
1675
     * @param Request $req
1676
     * @param string $server
1677
     * @param int $port
1678
     * @param int $timeout
1679
     * @param string $username
1680
     * @param string $password
1681
     * @param int $authType only value supported is 1
1682
     * @param string $cert
1683
     * @param string $certPass
1684
     * @param string $caCert
1685
     * @param string $caCertDir
1686
     * @param string $proxyHost
1687
     * @param int $proxyPort
1688
     * @param string $proxyUsername
1689
     * @param string $proxyPassword
1690
     * @param int $proxyAuthType only value supported is 1
1691
     * @param string $method 'http' (synonym for 'http10'), 'http10' or 'https'
1692
     * @param string $key
1693
     * @param string $keyPass @todo not implemented yet.
1694
     * @param int $sslVersion @todo not implemented yet. See http://php.net/manual/en/migration56.openssl.php
1695
     * @return Response
1696
     */
1697
    protected function sendPayloadSocket($req, $server, $port, $timeout = 0, $username = '', $password = '',
1698
        $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0,
1699
        $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $method = 'http', $key = '', $keyPass = '',
1700
        $sslVersion = 0)
1701
    {
1702
        $this->logDeprecationUnlessCalledBy('send');
1703
1704
        return $this->sendViaSocket($req, $method, $server, $port, $this->path, array(
1705
            'accepted_charset_encodings' => $this->accepted_charset_encodings,
1706
            'accepted_compression' => $this->accepted_compression,
1707
            'authtype' => $authType,
1708
            'cacert' => $caCert,
1709
            'cacertdir' => $caCertDir,
1710
            'cert' => $cert,
1711
            'certpass' => $certPass,
1712
            'cookies' => $this->cookies,
1713
            'debug' => $this->debug,
1714
            'extracurlopts' => $this->extracurlopts,
1715
            'keepalive' => $this->keepalive,
1716
            'key' => $key,
1717
            'keypass' => $keyPass,
1718
            'no_multicall' => $this->no_multicall,
1719
            'password' => $password,
1720
            'proxy' => $proxyHost,
1721
            'proxy_authtype' => $proxyAuthType,
1722
            'proxy_pass' => $proxyPassword,
1723
            'proxyport' => $proxyPort,
1724
            'proxy_user' => $proxyUsername,
1725
            'request_charset_encoding' => $this->request_charset_encoding,
1726
            'request_compression' => $this->request_compression,
1727
            'return_type' => $this->return_type,
1728
            'sslversion' => $sslVersion,
1729
            'timeout' => $timeout,
1730
            'username' => $username,
1731
            'user_agent' => $this->user_agent,
1732
            'use_curl' => $this->use_curl,
1733
            'verifyhost' => $this->verifyhost,
1734
            'verifypeer' => $this->verifypeer,
1735
        ));
1736
    }
1737
1738
    /**
1739
     * @deprecated
1740
     *
1741
     * @param Request $req
1742
     * @param string $server
1743
     * @param int $port
1744
     * @param int $timeout
1745
     * @param string $username
1746
     * @param string $password
1747
     * @param int $authType
1748
     * @param string $cert
1749
     * @param string $certPass
1750
     * @param string $caCert
1751
     * @param string $caCertDir
1752
     * @param string $proxyHost
1753
     * @param int $proxyPort
1754
     * @param string $proxyUsername
1755
     * @param string $proxyPassword
1756
     * @param int $proxyAuthType
1757
     * @param string $method 'http' (let curl decide), 'http10', 'http11', 'https', 'h2c' or 'h2'
1758
     * @param bool $keepAlive
1759
     * @param string $key
1760
     * @param string $keyPass
1761
     * @param int $sslVersion
1762
     * @return Response
1763
     */
1764
    protected function sendPayloadCURL($req, $server, $port, $timeout = 0, $username = '', $password = '',
1765
        $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0,
1766
        $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $method = 'https', $keepAlive = false, $key = '',
1767
        $keyPass = '', $sslVersion = 0)
1768
    {
1769
        $this->logDeprecationUnlessCalledBy('send');
1770
1771
        return $this->sendViaCURL($req, $method, $server, $port, $this->path, array(
1772
            'accepted_charset_encodings' => $this->accepted_charset_encodings,
1773
            'accepted_compression' => $this->accepted_compression,
1774
            'authtype' => $authType,
1775
            'cacert' => $caCert,
1776
            'cacertdir' => $caCertDir,
1777
            'cert' => $cert,
1778
            'certpass' => $certPass,
1779
            'cookies' => $this->cookies,
1780
            'debug' => $this->debug,
1781
            'extracurlopts' => $this->extracurlopts,
1782
            'keepalive' => $keepAlive,
1783
            'key' => $key,
1784
            'keypass' => $keyPass,
1785
            'no_multicall' => $this->no_multicall,
1786
            'password' => $password,
1787
            'proxy' => $proxyHost,
1788
            'proxy_authtype' => $proxyAuthType,
1789
            'proxy_pass' => $proxyPassword,
1790
            'proxyport' => $proxyPort,
1791
            'proxy_user' => $proxyUsername,
1792
            'request_charset_encoding' => $this->request_charset_encoding,
1793
            'request_compression' => $this->request_compression,
1794
            'return_type' => $this->return_type,
1795
            'sslversion' => $sslVersion,
1796
            'timeout' => $timeout,
1797
            'username' => $username,
1798
            'user_agent' => $this->user_agent,
1799
            'use_curl' => $this->use_curl,
1800
            'verifyhost' => $this->verifyhost,
1801
            'verifypeer' => $this->verifypeer,
1802
        ));
1803
    }
1804
1805
    /**
1806
     * @deprecated
1807
     *
1808
     * @param $req
1809
     * @param $server
1810
     * @param $port
1811
     * @param $timeout
1812
     * @param $username
1813
     * @param $password
1814
     * @param $authType
1815
     * @param $cert
1816
     * @param $certPass
1817
     * @param $caCert
1818
     * @param $caCertDir
1819
     * @param $proxyHost
1820
     * @param $proxyPort
1821
     * @param $proxyUsername
1822
     * @param $proxyPassword
1823
     * @param $proxyAuthType
1824
     * @param $method
1825
     * @param $keepAlive
1826
     * @param $key
1827
     * @param $keyPass
1828
     * @param $sslVersion
1829
     * @return false|\CurlHandle|resource
1830
     */
1831
    protected function prepareCurlHandle($req, $server, $port, $timeout = 0, $username = '', $password = '',
1832
         $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0,
1833
         $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $method = 'https', $keepAlive = false, $key = '',
1834
         $keyPass = '', $sslVersion = 0)
1835
    {
1836
        $this->logDeprecationUnlessCalledBy('sendViaCURL');
1837
1838
        return $this->createCURLHandle($req, $method, $server, $port, $this->path, array(
1839
            'accepted_charset_encodings' => $this->accepted_charset_encodings,
1840
            'accepted_compression' => $this->accepted_compression,
1841
            'authtype' => $authType,
1842
            'cacert' => $caCert,
1843
            'cacertdir' => $caCertDir,
1844
            'cert' => $cert,
1845
            'certpass' => $certPass,
1846
            'cookies' => $this->cookies,
1847
            'debug' => $this->debug,
1848
            'extracurlopts' => $this->extracurlopts,
1849
            'keepalive' => $keepAlive,
1850
            'key' => $key,
1851
            'keypass' => $keyPass,
1852
            'no_multicall' => $this->no_multicall,
1853
            'password' => $password,
1854
            'proxy' => $proxyHost,
1855
            'proxy_authtype' => $proxyAuthType,
1856
            'proxy_pass' => $proxyPassword,
1857
            'proxyport' => $proxyPort,
1858
            'proxy_user' => $proxyUsername,
1859
            'request_charset_encoding' => $this->request_charset_encoding,
1860
            'request_compression' => $this->request_compression,
1861
            'return_type' => $this->return_type,
1862
            'sslversion' => $sslVersion,
1863
            'timeout' => $timeout,
1864
            'username' => $username,
1865
            'user_agent' => $this->user_agent,
1866
            'use_curl' => $this->use_curl,
1867
            'verifyhost' => $this->verifyhost,
1868
            'verifypeer' => $this->verifypeer,
1869
        ));
1870
    }
1871
1872
    // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
1873
    public function &__get($name)
1874
    {
1875
        if (in_array($name, static::$options)) {
1876
            $this->logDeprecation('Getting property Client::' . $name . ' is deprecated');
1877
            return $this->$name;
1878
        }
1879
1880
        switch ($name) {
1881
            case 'errno':
1882
            case 'errstr':
1883
            case 'method':
1884
            case 'server':
1885
            case 'port':
1886
            case 'path':
1887
                $this->logDeprecation('Getting property Client::' . $name . ' is deprecated');
1888
                return $this->$name;
1889
            default:
1890
                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
1891
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
1892
                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
1893
                $result = null;
1894
                return $result;
1895
        }
1896
    }
1897
1898
    public function __set($name, $value)
1899
    {
1900
        if (in_array($name, static::$options)) {
1901
            $this->logDeprecation('Setting property Client::' . $name . ' is deprecated');
1902
            $this->$name = $value;
1903
            return;
1904
        }
1905
1906
        switch ($name) {
1907
            case 'errno':
1908
            case 'errstr':
1909
            case 'method':
1910
            case 'server':
1911
            case 'port':
1912
            case 'path':
1913
                $this->logDeprecation('Setting property Client::' . $name . ' is deprecated');
1914
                $this->$name = $value;
1915
                return;
1916
            default:
1917
                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
1918
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
1919
                trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
1920
        }
1921
    }
1922
1923
    public function __isset($name)
1924
    {
1925
        if (in_array($name, static::$options)) {
1926
            $this->logDeprecation('Checking property Client::' . $name . ' is deprecated');
1927
            return isset($this->$name);
1928
        }
1929
1930
        switch ($name) {
1931
            case 'errno':
1932
            case 'errstr':
1933
            case 'method':
1934
            case 'server':
1935
            case 'port':
1936
            case 'path':
1937
                $this->logDeprecation('Checking property Client::' . $name . ' is deprecated');
1938
                return isset($this->$name);
1939
            default:
1940
                return false;
1941
        }
1942
    }
1943
1944
    public function __unset($name)
1945
    {
1946
        if (in_array($name, static::$options)) {
1947
            $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated');
1948
            unset($this->$name);
1949
            return;
1950
        }
1951
1952
        switch ($name) {
1953
            case 'errno':
1954
            case 'errstr':
1955
            case 'method':
1956
            case 'server':
1957
            case 'port':
1958
            case 'path':
1959
                $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated');
1960
                unset($this->$name);
1961
                return;
1962
            default:
1963
                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
1964
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
1965
                trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
1966
        }
1967
    }
1968
}
1969