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_EXTRA_SOCKET_OPTS = 'extrasockopts'; |
||||
40 | const OPT_KEEPALIVE = 'keepalive'; |
||||
41 | const OPT_KEY = 'key'; |
||||
42 | const OPT_KEY_PASS = 'keypass'; |
||||
43 | const OPT_NO_MULTICALL = 'no_multicall'; |
||||
44 | const OPT_PASSWORD = 'password'; |
||||
45 | const OPT_PROXY = 'proxy'; |
||||
46 | const OPT_PROXY_AUTH_TYPE = 'proxy_authtype'; |
||||
47 | const OPT_PROXY_PASS = 'proxy_pass'; |
||||
48 | const OPT_PROXY_PORT = 'proxyport'; |
||||
49 | const OPT_PROXY_USER = 'proxy_user'; |
||||
50 | const OPT_REQUEST_CHARSET_ENCODING = 'request_charset_encoding'; |
||||
51 | const OPT_REQUEST_COMPRESSION = 'request_compression'; |
||||
52 | const OPT_RETURN_TYPE = 'return_type'; |
||||
53 | const OPT_SSL_VERSION = 'sslversion'; |
||||
54 | const OPT_TIMEOUT = 'timeout'; |
||||
55 | const OPT_USERNAME = 'username'; |
||||
56 | const OPT_USER_AGENT = 'user_agent'; |
||||
57 | const OPT_USE_CURL = 'use_curl'; |
||||
58 | const OPT_VERIFY_HOST = 'verifyhost'; |
||||
59 | const OPT_VERIFY_PEER = 'verifypeer'; |
||||
60 | const OPT_EXTRA_HEADERS = 'extra_headers'; |
||||
61 | |||||
62 | /** @var string */ |
||||
63 | protected static $requestClass = '\\PhpXmlRpc\\Request'; |
||||
64 | /** @var string */ |
||||
65 | protected static $responseClass = '\\PhpXmlRpc\\Response'; |
||||
66 | |||||
67 | /** |
||||
68 | * @var int |
||||
69 | * @deprecated will be removed in the future |
||||
70 | */ |
||||
71 | protected $errno; |
||||
72 | /** |
||||
73 | * @var string |
||||
74 | * @deprecated will be removed in the future |
||||
75 | */ |
||||
76 | protected $errstr; |
||||
77 | |||||
78 | /// @todo: do all the ones below need to be public? |
||||
79 | |||||
80 | /** |
||||
81 | * @var string |
||||
82 | */ |
||||
83 | protected $method = 'http'; |
||||
84 | /** |
||||
85 | * @var string |
||||
86 | */ |
||||
87 | protected $server; |
||||
88 | /** |
||||
89 | * @var int |
||||
90 | */ |
||||
91 | protected $port = 0; |
||||
92 | /** |
||||
93 | * @var string |
||||
94 | */ |
||||
95 | protected $path; |
||||
96 | |||||
97 | /** |
||||
98 | * @var int |
||||
99 | */ |
||||
100 | protected $debug = 0; |
||||
101 | /** |
||||
102 | * @var string |
||||
103 | */ |
||||
104 | protected $username = ''; |
||||
105 | /** |
||||
106 | * @var string |
||||
107 | */ |
||||
108 | protected $password = ''; |
||||
109 | /** |
||||
110 | * @var int |
||||
111 | */ |
||||
112 | protected $authtype = 1; |
||||
113 | /** |
||||
114 | * @var string |
||||
115 | */ |
||||
116 | protected $cert = ''; |
||||
117 | /** |
||||
118 | * @var string |
||||
119 | */ |
||||
120 | protected $certpass = ''; |
||||
121 | /** |
||||
122 | 2 | * @var string |
|||
123 | */ |
||||
124 | 2 | protected $cacert = ''; |
|||
125 | 2 | /** |
|||
126 | * @var string |
||||
127 | 2 | */ |
|||
128 | protected $cacertdir = ''; |
||||
129 | /** |
||||
130 | * @var string |
||||
131 | */ |
||||
132 | protected $key = ''; |
||||
133 | /** |
||||
134 | * @var string |
||||
135 | */ |
||||
136 | protected $keypass = ''; |
||||
137 | /** |
||||
138 | * @var bool |
||||
139 | */ |
||||
140 | protected $verifypeer = true; |
||||
141 | /** |
||||
142 | * @var int |
||||
143 | */ |
||||
144 | protected $verifyhost = 2; |
||||
145 | /** |
||||
146 | * @var int |
||||
147 | */ |
||||
148 | protected $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT. Other CURL_SSLVERSION_ values are supported |
||||
149 | /** |
||||
150 | * @var string |
||||
151 | */ |
||||
152 | 718 | protected $proxy = ''; |
|||
153 | /** |
||||
154 | * @var int |
||||
155 | 718 | */ |
|||
156 | 7 | protected $proxyport = 0; |
|||
157 | 7 | /** |
|||
158 | 7 | * @var string |
|||
159 | 7 | */ |
|||
160 | protected $proxy_user = ''; |
||||
161 | /** |
||||
162 | 7 | * @var string |
|||
163 | */ |
||||
164 | protected $proxy_pass = ''; |
||||
165 | 7 | /** |
|||
166 | * @var int |
||||
167 | */ |
||||
168 | 7 | protected $proxy_authtype = 1; |
|||
169 | 7 | /** |
|||
170 | * @var array |
||||
171 | 7 | */ |
|||
172 | protected $cookies = array(); |
||||
173 | /** |
||||
174 | 7 | * @var array |
|||
175 | */ |
||||
176 | protected $extrasockopts = array(); |
||||
177 | /** |
||||
178 | 718 | * @var array |
|||
179 | */ |
||||
180 | protected $extracurlopts = array(); |
||||
181 | 718 | /** |
|||
182 | * @var int |
||||
183 | 718 | */ |
|||
184 | 718 | protected $timeout = 0; |
|||
185 | 3 | /** |
|||
186 | * @var int |
||||
187 | 718 | */ |
|||
188 | 7 | protected $use_curl = self::USE_CURL_AUTO; |
|||
189 | /** |
||||
190 | * @var bool |
||||
191 | * |
||||
192 | 718 | * This determines whether the multicall() method will try to take advantage of the system.multicall xml-rpc method |
|||
193 | * to dispatch to the server an array of requests in a single http roundtrip or simply execute many consecutive http |
||||
194 | 711 | * calls. Defaults to FALSE, but it will be enabled automatically on the first failure of execution of |
|||
195 | * system.multicall. |
||||
196 | */ |
||||
197 | 718 | protected $no_multicall = false; |
|||
198 | /** |
||||
199 | * @var array |
||||
200 | * |
||||
201 | 718 | * List of http compression methods accepted by the client for responses. |
|||
202 | * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib. |
||||
203 | * |
||||
204 | 718 | * 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 |
|||
205 | * decide the compression methods it supports. You might check for the presence of 'zlib' in the output of |
||||
206 | * curl_version() to determine whether compression is supported or not |
||||
207 | */ |
||||
208 | protected $accepted_compression = array(); |
||||
209 | /** |
||||
210 | * @var string|null |
||||
211 | * |
||||
212 | * Name of compression scheme to be used for sending requests. |
||||
213 | * Either null, 'gzip' or 'deflate'. |
||||
214 | */ |
||||
215 | protected $request_compression = ''; |
||||
216 | /** |
||||
217 | 718 | * @var bool |
|||
218 | 718 | * |
|||
219 | * Whether to use persistent connections for http 1.1 and https. Value set at constructor time. |
||||
220 | */ |
||||
221 | protected $keepalive = false; |
||||
222 | /** |
||||
223 | * @var string[] |
||||
224 | * |
||||
225 | * Charset encodings that can be decoded without problems by the client. Value set at constructor time |
||||
226 | */ |
||||
227 | protected $accepted_charset_encodings = array(); |
||||
228 | /** |
||||
229 | * @var string |
||||
230 | * |
||||
231 | * The charset encoding that will be used for serializing request sent by the client. |
||||
232 | * It defaults to NULL, which means using US-ASCII and encoding all characters outside the ASCII printable range |
||||
233 | 714 | * using their xml character entity representation (this has the benefit that line end characters will not be mangled |
|||
234 | * in the transfer, a CR-LF will be preserved as well as a singe LF). |
||||
235 | 714 | * Valid values are 'US-ASCII', 'UTF-8' and 'ISO-8859-1'. |
|||
236 | 714 | * For the fastest mode of operation, set your both your app internal encoding and this to UTF-8. |
|||
237 | */ |
||||
238 | protected $request_charset_encoding = ''; |
||||
239 | /** |
||||
240 | * @var string |
||||
241 | * |
||||
242 | * Decides the content of Response objects returned by calls to send() and multicall(). |
||||
243 | * Valid values are 'xmlrpcvals', 'phpvals' or 'xml'. |
||||
244 | * |
||||
245 | * Determines whether the value returned inside a Response object as results of calls to the send() and multicall() |
||||
246 | * methods will be a Value object, a plain php value or a raw xml string. |
||||
247 | * Allowed values are 'xmlrpcvals' (the default), 'phpvals' and 'xml'. |
||||
248 | * To allow the user to differentiate between a correct and a faulty response, fault responses will be returned as |
||||
249 | * Response objects in any case. |
||||
250 | * Note that the 'phpvals' setting will yield faster execution times, but some of the information from the original |
||||
251 | * response will be lost. It will be e.g. impossible to tell whether a particular php string value was sent by the |
||||
252 | 66 | * server as an xml-rpc string or base64 value. |
|||
253 | */ |
||||
254 | 66 | protected $return_type = XMLParser::RETURN_XMLRPCVALS; |
|||
255 | 66 | /** |
|||
256 | 66 | * @var string |
|||
257 | 66 | * |
|||
258 | * Sent to servers in http headers. Value set at constructor time. |
||||
259 | */ |
||||
260 | protected $user_agent; |
||||
261 | |||||
262 | /** |
||||
263 | * Additional headers to be included in the requests. |
||||
264 | * |
||||
265 | * @var string[] |
||||
266 | */ |
||||
267 | protected $extra_headers = array(); |
||||
268 | |||||
269 | /** |
||||
270 | * CURL handle: used for keep-alive |
||||
271 | * @internal |
||||
272 | */ |
||||
273 | public $xmlrpc_curl_handle = null; |
||||
274 | |||||
275 | /** |
||||
276 | * @var array |
||||
277 | */ |
||||
278 | protected static $options = array( |
||||
279 | self::OPT_ACCEPTED_CHARSET_ENCODINGS, |
||||
280 | self::OPT_ACCEPTED_COMPRESSION, |
||||
281 | self::OPT_AUTH_TYPE, |
||||
282 | self::OPT_CA_CERT, |
||||
283 | self::OPT_CA_CERT_DIR, |
||||
284 | self::OPT_CERT, |
||||
285 | self::OPT_CERT_PASS, |
||||
286 | self::OPT_COOKIES, |
||||
287 | self::OPT_DEBUG, |
||||
288 | self::OPT_EXTRA_CURL_OPTS, |
||||
289 | self::OPT_EXTRA_SOCKET_OPTS, |
||||
290 | self::OPT_KEEPALIVE, |
||||
291 | self::OPT_KEY, |
||||
292 | self::OPT_KEY_PASS, |
||||
293 | self::OPT_NO_MULTICALL, |
||||
294 | self::OPT_PASSWORD, |
||||
295 | self::OPT_PROXY, |
||||
296 | self::OPT_PROXY_AUTH_TYPE, |
||||
297 | self::OPT_PROXY_PASS, |
||||
298 | self::OPT_PROXY_USER, |
||||
299 | self::OPT_PROXY_PORT, |
||||
300 | self::OPT_REQUEST_CHARSET_ENCODING, |
||||
301 | self::OPT_REQUEST_COMPRESSION, |
||||
302 | self::OPT_RETURN_TYPE, |
||||
303 | self::OPT_SSL_VERSION, |
||||
304 | self::OPT_TIMEOUT, |
||||
305 | self::OPT_USE_CURL, |
||||
306 | self::OPT_USER_AGENT, |
||||
307 | self::OPT_USERNAME, |
||||
308 | self::OPT_VERIFY_HOST, |
||||
309 | self::OPT_VERIFY_PEER, |
||||
310 | self::OPT_EXTRA_HEADERS, |
||||
311 | ); |
||||
312 | |||||
313 | /** |
||||
314 | * @param string $path either the PATH part of the xml-rpc server URL, or complete server URL (in which case you |
||||
315 | * should use an empty string for all other parameters) |
||||
316 | 132 | * e.g. /xmlrpc/server.php |
|||
317 | * e.g. http://phpxmlrpc.sourceforge.net/server.php |
||||
318 | 132 | * e.g. https://james:[email protected]:444/xmlrpcserver?agent=007 |
|||
319 | 132 | * e.g. h2://fast-and-secure-services.org/endpoint |
|||
320 | * @param string $server the server name / ip address |
||||
321 | * @param integer $port the port the server is listening on, when omitted defaults to 80 or 443 depending on |
||||
322 | * protocol used |
||||
323 | * @param string $method the http protocol variant: defaults to 'http'; 'https', 'http11', 'h2' and 'h2c' can |
||||
324 | * be used if CURL is installed. The value set here can be overridden in any call to $this->send(). |
||||
325 | * Use 'h2' to make the lib attempt to use http/2 over a secure connection, and 'h2c' |
||||
326 | * for http/2 without tls. Note that 'h2c' will not use the h2c 'upgrade' method, and be |
||||
327 | * thus incompatible with any server/proxy not supporting http/2. This is because POST |
||||
328 | 132 | * request are not compatible with h2c upgrade. |
|||
329 | */ |
||||
330 | 132 | public function __construct($path, $server = '', $port = '', $method = '') |
|||
331 | 132 | { |
|||
332 | // allow user to specify all params in $path |
||||
333 | if ($server == '' && $port == '' && $method == '') { |
||||
334 | $parts = parse_url($path); |
||||
335 | $server = $parts['host']; |
||||
336 | $path = isset($parts['path']) ? $parts['path'] : ''; |
||||
337 | if (isset($parts['query'])) { |
||||
338 | 132 | $path .= '?' . $parts['query']; |
|||
339 | } |
||||
340 | 132 | if (isset($parts['fragment'])) { |
|||
341 | 132 | $path .= '#' . $parts['fragment']; |
|||
342 | } |
||||
343 | if (isset($parts['port'])) { |
||||
344 | $port = $parts['port']; |
||||
345 | } |
||||
346 | if (isset($parts['scheme'])) { |
||||
347 | $method = $parts['scheme']; |
||||
348 | } |
||||
349 | if (isset($parts['user'])) { |
||||
350 | $this->username = $parts['user']; |
||||
351 | } |
||||
352 | if (isset($parts['pass'])) { |
||||
353 | $this->password = $parts['pass']; |
||||
354 | } |
||||
355 | 99 | } |
|||
356 | if ($path == '' || $path[0] != '/') { |
||||
357 | 99 | $this->path = '/' . $path; |
|||
358 | 99 | } else { |
|||
359 | 99 | $this->path = $path; |
|||
360 | 99 | } |
|||
361 | 99 | $this->server = $server; |
|||
362 | 99 | if ($port != '') { |
|||
363 | $this->port = $port; |
||||
364 | } |
||||
365 | if ($method != '') { |
||||
366 | $this->method = $method; |
||||
367 | } |
||||
368 | |||||
369 | // if ZLIB is enabled, let the client by default accept compressed responses |
||||
370 | if (function_exists('gzinflate') || ( |
||||
371 | function_exists('curl_version') && (($info = curl_version()) && |
||||
372 | ((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version']))) |
||||
373 | ) |
||||
374 | ) { |
||||
375 | $this->accepted_compression = array('gzip', 'deflate'); |
||||
376 | } |
||||
377 | |||||
378 | // keepalives: enabled by default |
||||
379 | $this->keepalive = true; |
||||
380 | |||||
381 | // by default the xml parser can support these 3 charset encodings |
||||
382 | $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); |
||||
383 | |||||
384 | // NB: this is disabled to avoid making all the requests sent huge... mbstring supports more than 80 charsets! |
||||
385 | //$ch = $this->getCharsetEncoder(); |
||||
386 | //$this->accepted_charset_encodings = $ch->knownCharsets(); |
||||
387 | |||||
388 | // initialize user_agent string |
||||
389 | $this->user_agent = PhpXmlRpc::$xmlrpcName . ' ' . PhpXmlRpc::$xmlrpcVersion; |
||||
390 | } |
||||
391 | |||||
392 | /** |
||||
393 | * @param string $name see all the OPT_ constants |
||||
394 | * @param mixed $value |
||||
395 | * @return $this |
||||
396 | * @throws ValueErrorException on unsupported option |
||||
397 | */ |
||||
398 | public function setOption($name, $value) |
||||
399 | { |
||||
400 | if (in_array($name, static::$options)) { |
||||
401 | $this->$name = $value; |
||||
402 | return $this; |
||||
403 | } |
||||
404 | |||||
405 | throw new ValueErrorException("Unsupported option '$name'"); |
||||
406 | } |
||||
407 | |||||
408 | /** |
||||
409 | * @param string $name see all the OPT_ constants |
||||
410 | * @return mixed |
||||
411 | * @throws ValueErrorException on unsupported option |
||||
412 | */ |
||||
413 | public function getOption($name) |
||||
414 | { |
||||
415 | if (in_array($name, static::$options)) { |
||||
416 | return $this->$name; |
||||
417 | } |
||||
418 | 580 | ||||
419 | throw new ValueErrorException("Unsupported option '$name'"); |
||||
420 | 580 | } |
|||
421 | 580 | ||||
422 | /** |
||||
423 | * Returns the complete list of Client options, with their value. |
||||
424 | * @return array |
||||
425 | */ |
||||
426 | public function getOptions() |
||||
427 | 580 | { |
|||
428 | $values = array(); |
||||
429 | 580 | foreach (static::$options as $opt) { |
|||
430 | $values[$opt] = $this->getOption($opt); |
||||
431 | } |
||||
432 | return $values; |
||||
433 | } |
||||
434 | |||||
435 | /** |
||||
436 | * @param array $options key: any valid option (see all the OPT_ constants) |
||||
437 | * @return $this |
||||
438 | * @throws ValueErrorException on unsupported option |
||||
439 | */ |
||||
440 | public function setOptions($options) |
||||
441 | { |
||||
442 | foreach ($options as $name => $value) { |
||||
443 | $this->setOption($name, $value); |
||||
444 | } |
||||
445 | |||||
446 | 66 | return $this; |
|||
447 | } |
||||
448 | 66 | ||||
449 | 66 | /** |
|||
450 | * Enable/disable the echoing to screen of the xml-rpc responses received. The default is not to output anything. |
||||
451 | * |
||||
452 | * The debugging information at level 1 includes the raw data returned from the XML-RPC server it was querying |
||||
453 | * (including bot HTTP headers and the full XML payload), and the PHP value the client attempts to create to |
||||
454 | * represent the value returned by the server. |
||||
455 | * At level 2, the complete payload of the xml-rpc request is also printed, before being sent to the server. |
||||
456 | * At level -1, the Response objects returned by send() calls will not carry information about the http response's |
||||
457 | * cookies, headers and body, which might save some memory |
||||
458 | * |
||||
459 | * This option can be very useful when debugging servers as it allows you to see exactly what the client sends and |
||||
460 | * the server returns. Never leave it enabled for production! |
||||
461 | * |
||||
462 | * @param integer $level values -1, 0, 1 and 2 are supported |
||||
463 | * @return $this |
||||
464 | */ |
||||
465 | public function setDebug($level) |
||||
466 | { |
||||
467 | $this->debug = $level; |
||||
468 | return $this; |
||||
469 | } |
||||
470 | |||||
471 | /** |
||||
472 | * Sets the username and password for authorizing the client to the server. |
||||
473 | * |
||||
474 | * With the default (HTTP) transport, this information is used for HTTP Basic authorization. |
||||
475 | * Note that username and password can also be set using the class constructor. |
||||
476 | * With HTTP 1.1 and HTTPS transport, NTLM and Digest authentication protocols are also supported. To enable them use |
||||
477 | * the constants CURLAUTH_DIGEST and CURLAUTH_NTLM as values for the auth type parameter. |
||||
478 | * |
||||
479 | * @param string $user username |
||||
480 | * @param string $password password |
||||
481 | * @param integer $authType auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC |
||||
482 | * (basic auth). Note that auth types NTLM and Digest will only work if the Curl php |
||||
483 | * extension is enabled. |
||||
484 | * @return $this |
||||
485 | */ |
||||
486 | public function setCredentials($user, $password, $authType = 1) |
||||
487 | { |
||||
488 | $this->username = $user; |
||||
489 | $this->password = $password; |
||||
490 | $this->authtype = $authType; |
||||
491 | return $this; |
||||
492 | } |
||||
493 | |||||
494 | /** |
||||
495 | 697 | * Set the optional certificate and passphrase used in SSL-enabled communication with a remote server. |
|||
496 | * |
||||
497 | * Note: to retrieve information about the client certificate on the server side, you will need to look into the |
||||
498 | * environment variables which are set up by the webserver. Different webservers will typically set up different |
||||
499 | 697 | * variables. |
|||
500 | 117 | * |
|||
501 | * @param string $cert the name of a file containing a PEM formatted certificate |
||||
502 | * @param string $certPass the password required to use it |
||||
503 | 697 | * @return $this |
|||
504 | */ |
||||
505 | 66 | public function setCertificate($cert, $certPass = '') |
|||
506 | { |
||||
507 | 66 | $this->cert = $cert; |
|||
508 | 697 | $this->certpass = $certPass; |
|||
509 | 28 | return $this; |
|||
510 | 28 | } |
|||
511 | 28 | ||||
512 | /** |
||||
513 | * Add a CA certificate to verify server with in SSL-enabled communication when SetSSLVerifypeer has been set to TRUE. |
||||
514 | * |
||||
515 | 697 | * See the php manual page about CURLOPT_CAINFO for more details. |
|||
516 | * |
||||
517 | * @param string $caCert certificate file name (or dir holding certificates) |
||||
518 | * @param bool $isDir set to true to indicate cacert is a dir. defaults to false |
||||
519 | 697 | * @return $this |
|||
520 | 697 | */ |
|||
521 | public function setCaCertificate($caCert, $isDir = false) |
||||
522 | 697 | { |
|||
523 | 322 | if ($isDir) { |
|||
524 | 322 | $this->cacertdir = $caCert; |
|||
525 | 322 | } else { |
|||
526 | 322 | $this->cacert = $caCert; |
|||
527 | } |
||||
528 | 322 | return $this; |
|||
529 | 322 | } |
|||
530 | 322 | ||||
531 | 322 | /** |
|||
532 | 322 | * Set attributes for SSL communication: private SSL key. |
|||
533 | 322 | * |
|||
534 | 322 | * NB: does not work in older php/curl installs. |
|||
535 | 322 | * Thanks to Daniel Convissor. |
|||
536 | 322 | * |
|||
537 | 322 | * @param string $key The name of a file containing a private SSL key |
|||
538 | 322 | * @param string $keyPass The secret password needed to use the private SSL key |
|||
539 | 322 | * @return $this |
|||
540 | */ |
||||
541 | 322 | public function setKey($key, $keyPass) |
|||
542 | 322 | { |
|||
543 | 322 | $this->key = $key; |
|||
544 | 322 | $this->keypass = $keyPass; |
|||
545 | 322 | return $this; |
|||
546 | } |
||||
547 | |||||
548 | /** |
||||
549 | 375 | * Set attributes for SSL communication: verify the remote host's SSL certificate, and cause the connection to fail |
|||
550 | 375 | * if the cert verification fails. |
|||
551 | 375 | * |
|||
552 | 375 | * By default, verification is enabled. |
|||
553 | * To specify custom SSL certificates to validate the server with, use the setCaCertificate method. |
||||
554 | 375 | * |
|||
555 | 375 | * @param bool $i enable/disable verification of peer certificate |
|||
556 | 375 | * @return $this |
|||
557 | 375 | * @deprecated use setOption |
|||
558 | 375 | */ |
|||
559 | 375 | public function setSSLVerifyPeer($i) |
|||
560 | 375 | { |
|||
561 | 375 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
|||
562 | 375 | ||||
563 | 375 | $this->verifypeer = $i; |
|||
564 | 375 | return $this; |
|||
565 | 375 | } |
|||
566 | |||||
567 | 375 | /** |
|||
568 | 375 | * Set attributes for SSL communication: verify the remote host's SSL certificate's common name (CN). |
|||
569 | 375 | * |
|||
570 | * Note that support for value 1 has been removed in cURL 7.28.1 |
||||
571 | * |
||||
572 | * @param int $i Set to 1 to only the existence of a CN, not that it matches |
||||
573 | 697 | * @return $this |
|||
574 | * @deprecated use setOption |
||||
575 | */ |
||||
576 | public function setSSLVerifyHost($i) |
||||
577 | { |
||||
578 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||||
579 | |||||
580 | $this->verifyhost = $i; |
||||
581 | return $this; |
||||
582 | } |
||||
583 | |||||
584 | /** |
||||
585 | * Set attributes for SSL communication: SSL version to use. Best left at 0 (default value): let PHP decide. |
||||
586 | * |
||||
587 | * @param int $i use CURL_SSLVERSION_ constants. When in socket mode, use values 2 (SSLv2) to 7 (TLSv1.3). 0 for auto |
||||
588 | * @return $this |
||||
589 | * @deprecated use setOption |
||||
590 | */ |
||||
591 | public function setSSLVersion($i) |
||||
592 | { |
||||
593 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||||
594 | |||||
595 | $this->sslversion = $i; |
||||
596 | return $this; |
||||
597 | } |
||||
598 | |||||
599 | /** |
||||
600 | * Set proxy info. |
||||
601 | * |
||||
602 | * NB: CURL versions before 7.11.10 cannot use a proxy to communicate with https servers. |
||||
603 | * |
||||
604 | * @param string $proxyHost |
||||
605 | * @param string $proxyPort Defaults to 8080 for HTTP and 443 for HTTPS |
||||
606 | * @param string $proxyUsername Leave blank if proxy has public access |
||||
607 | * @param string $proxyPassword Leave blank if proxy has public access |
||||
608 | * @param int $proxyAuthType defaults to CURLAUTH_BASIC (Basic authentication protocol); set to constant CURLAUTH_NTLM |
||||
609 | * to use NTLM auth with proxy (has effect only when the client uses the HTTP 1.1 protocol) |
||||
610 | * @return $this |
||||
611 | */ |
||||
612 | public function setProxy($proxyHost, $proxyPort, $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1) |
||||
613 | { |
||||
614 | $this->proxy = $proxyHost; |
||||
615 | $this->proxyport = $proxyPort; |
||||
616 | $this->proxy_user = $proxyUsername; |
||||
617 | $this->proxy_pass = $proxyPassword; |
||||
618 | $this->proxy_authtype = $proxyAuthType; |
||||
619 | return $this; |
||||
620 | } |
||||
621 | |||||
622 | /** |
||||
623 | * Enables/disables reception of compressed xml-rpc responses. |
||||
624 | * |
||||
625 | * This requires the "zlib" extension to be enabled in your php install. If it is, by default xmlrpc_client |
||||
626 | * instances will enable reception of compressed content. |
||||
627 | * Note that enabling reception of compressed responses merely adds some standard http headers to xml-rpc requests. |
||||
628 | * It is up to the xml-rpc server to return compressed responses when receiving such requests. |
||||
629 | * |
||||
630 | * @param string $compMethod either 'gzip', 'deflate', 'any' or '' |
||||
631 | * @return $this |
||||
632 | */ |
||||
633 | public function setAcceptedCompression($compMethod) |
||||
634 | { |
||||
635 | if ($compMethod == 'any') { |
||||
636 | $this->accepted_compression = array('gzip', 'deflate'); |
||||
637 | } elseif ($compMethod == false) { |
||||
638 | $this->accepted_compression = array(); |
||||
639 | } else { |
||||
640 | $this->accepted_compression = array($compMethod); |
||||
641 | } |
||||
642 | return $this; |
||||
643 | } |
||||
644 | |||||
645 | /** |
||||
646 | * Enables/disables http compression of xml-rpc request. |
||||
647 | * |
||||
648 | * This requires the "zlib" extension to be enabled in your php install. |
||||
649 | * Take care when sending compressed requests: servers might not support them (and automatic fallback to |
||||
650 | * uncompressed requests is not yet implemented). |
||||
651 | * |
||||
652 | * @param string $compMethod either 'gzip', 'deflate' or '' |
||||
653 | * @return $this |
||||
654 | * @deprecated use setOption |
||||
655 | */ |
||||
656 | public function setRequestCompression($compMethod) |
||||
657 | { |
||||
658 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||||
659 | |||||
660 | $this->request_compression = $compMethod; |
||||
661 | return $this; |
||||
662 | } |
||||
663 | |||||
664 | 375 | /** |
|||
665 | * Adds a cookie to list of cookies that will be sent to server with every further request (useful e.g. for keeping |
||||
666 | * session info outside the xml-rpc payload). |
||||
667 | * |
||||
668 | * NB: by default all cookies set via this method are sent to the server, regardless of path/domain/port. Taking |
||||
669 | * advantage of those values is left to the single developer. |
||||
670 | * |
||||
671 | 375 | * @param string $name nb: will not be escaped in the request's http headers. Take care not to use CTL chars or |
|||
672 | 373 | * separators! |
|||
673 | * @param string $value |
||||
674 | * @param string $path |
||||
675 | * @param string $domain |
||||
676 | 375 | * @param int $port do not use! Cookies are not separated by port |
|||
677 | 346 | * @return $this |
|||
678 | * |
||||
679 | * @todo check correctness of urlencoding cookie value (copied from php way of doing it, but php is generally sending |
||||
680 | 375 | * response not requests. We do the opposite...) |
|||
681 | * @todo strip invalid chars from cookie name? As per RFC 6265, we should follow RFC 2616, Section 2.2 |
||||
682 | 375 | * @todo drop/rename $port parameter. Cookies are not isolated by port! |
|||
683 | 375 | * @todo feature-creep allow storing 'expires', 'secure', 'httponly' and 'samesite' cookie attributes (we could do |
|||
684 | 64 | * as php, and allow $path to be an array of attributes...) |
|||
685 | 32 | */ |
|||
686 | 32 | public function setCookie($name, $value = '', $path = '', $domain = '', $port = null) |
|||
687 | 32 | { |
|||
688 | 32 | $this->cookies[$name]['value'] = rawurlencode($value); |
|||
689 | if ($path || $domain || $port) { |
||||
690 | $this->cookies[$name]['path'] = $path; |
||||
691 | 32 | $this->cookies[$name]['domain'] = $domain; |
|||
692 | 32 | $this->cookies[$name]['port'] = $port; |
|||
693 | 32 | } |
|||
694 | 32 | return $this; |
|||
695 | } |
||||
696 | |||||
697 | /** |
||||
698 | * Directly set cURL options, for extra flexibility (when in cURL mode). |
||||
699 | * |
||||
700 | 375 | * It allows e.g. to bind client to a specific IP interface / address. |
|||
701 | 375 | * |
|||
702 | 32 | * @param array $options |
|||
703 | 32 | * @return $this |
|||
704 | * @deprecated use setOption |
||||
705 | */ |
||||
706 | public function setCurlOptions($options) |
||||
707 | { |
||||
708 | 375 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
|||
709 | 375 | ||||
710 | 73 | $this->extracurlopts = $options; |
|||
711 | return $this; |
||||
712 | } |
||||
713 | 375 | ||||
714 | 375 | /** |
|||
715 | 32 | * @param int $useCurlMode self::USE_CURL_ALWAYS, self::USE_CURL_AUTO or self::USE_CURL_NEVER |
|||
716 | * @return $this |
||||
717 | * @deprecated use setOption |
||||
718 | 32 | */ |
|||
719 | 32 | public function setUseCurl($useCurlMode) |
|||
720 | 32 | { |
|||
721 | 32 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
|||
722 | 32 | ||||
723 | $this->use_curl = $useCurlMode; |
||||
724 | return $this; |
||||
725 | } |
||||
726 | 32 | ||||
727 | |||||
728 | /** |
||||
729 | 343 | * Set user-agent string that will be used by this client instance in http headers sent to the server. |
|||
730 | 343 | * |
|||
731 | 343 | * The default user agent string includes the name of this library and the version number. |
|||
732 | 343 | * |
|||
733 | * @param string $agentString |
||||
734 | * @return $this |
||||
735 | * @deprecated use setOption |
||||
736 | 375 | */ |
|||
737 | 375 | public function setUserAgent($agentString) |
|||
738 | 309 | { |
|||
739 | 309 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
|||
740 | 309 | ||||
741 | $this->user_agent = $agentString; |
||||
742 | return $this; |
||||
743 | } |
||||
744 | |||||
745 | /** |
||||
746 | * @param null|int $component allowed values: PHP_URL_SCHEME, PHP_URL_HOST, PHP_URL_PORT, PHP_URL_PATH |
||||
747 | * @return string|int Notes: the path component will include query string and fragment; NULL is a valid value for port |
||||
748 | * (in which case the default port for http/https will be used); |
||||
749 | * @throws ValueErrorException on unsupported component |
||||
750 | */ |
||||
751 | public function getUrl($component = null) |
||||
752 | { |
||||
753 | 309 | if (is_int($component) || ctype_digit($component)) { |
|||
754 | switch ($component) { |
||||
755 | case PHP_URL_SCHEME: |
||||
756 | 309 | return $this->method; |
|||
757 | case PHP_URL_HOST: |
||||
758 | return $this->server; |
||||
759 | case PHP_URL_PORT: |
||||
760 | 375 | return $this->port; |
|||
761 | 375 | case PHP_URL_PATH: |
|||
762 | return $this->path; |
||||
763 | case '': |
||||
764 | |||||
765 | default: |
||||
766 | 375 | throw new ValueErrorException("Unsupported component '$component'"); |
|||
767 | 375 | } |
|||
768 | 375 | } |
|||
769 | 375 | ||||
770 | 375 | $url = $this->method . '://' . $this->server; |
|||
771 | 375 | if ($this->port == 0 || ($this->port == 80 && in_array($this->method, array('http', 'http10', 'http11', 'h2c'))) || |
|||
772 | 375 | ($this->port == 443 && in_array($this->method, array('https', 'h2')))) { |
|||
773 | 375 | return $url . $this->path; |
|||
774 | 375 | } else { |
|||
775 | 375 | return $url . ':' . $this->port . $this->path; |
|||
776 | 375 | } |
|||
777 | 375 | } |
|||
778 | |||||
779 | 375 | /** |
|||
780 | 2 | * Send an xml-rpc request to the server. |
|||
781 | * |
||||
782 | * @param Request|Request[]|string $req The Request object, or an array of requests for using multicall, or the |
||||
783 | 375 | * complete xml representation of a request. |
|||
784 | 375 | * When sending an array of Request objects, the client will try to make use of |
|||
785 | 32 | * a single 'system.multicall' xml-rpc method call to forward to the server all |
|||
786 | * the requests in a single HTTP round trip, unless $this->no_multicall has |
||||
787 | * been previously set to TRUE (see the multicall method below), in which case |
||||
788 | * many consecutive xml-rpc requests will be sent. The method will return an |
||||
789 | * array of Response objects in both cases. |
||||
790 | * The third variant allows to build by hand (or any other means) a complete |
||||
791 | 32 | * xml-rpc request message, and send it to the server. $req should be a string |
|||
792 | * containing the complete xml representation of the request. It is e.g. useful |
||||
793 | * when, for maximal speed of execution, the request is serialized into a |
||||
794 | 32 | * string using the native php xml-rpc functions (see http://www.php.net/xmlrpc) |
|||
795 | * @param integer $timeout deprecated. Connection timeout, in seconds, If unspecified, the timeout set with setOption |
||||
796 | * will be used. If that is 0, a platform specific timeout will apply. |
||||
797 | 32 | * This timeout value is passed to fsockopen(). It is also used for detecting server |
|||
798 | * timeouts during communication (i.e. if the server does not send anything to the client |
||||
799 | * for $timeout seconds, the connection will be closed). When in CURL mode, this is the |
||||
800 | 32 | * CURL timeout. |
|||
801 | 32 | * NB: in both CURL and Socket modes, some conditions might lead to the client not |
|||
802 | * respecting the given timeout. Eg. if the network is not connected |
||||
803 | * @param string $method deprecated. Use the same value in the constructor instead. |
||||
804 | 375 | * Valid values are 'http', 'http11', 'https', 'h2' and 'h2c'. If left empty, |
|||
805 | * the http protocol chosen during creation of the object will be used. |
||||
806 | 375 | * Use 'h2' to make the lib attempt to use http/2 over a secure connection, and 'h2c' |
|||
807 | 64 | * for http/2 without tls. Note that 'h2c' will not use the h2c 'upgrade' method, and be |
|||
808 | * thus incompatible with any server/proxy not supporting http/2. This is because POST |
||||
809 | 311 | * request are not compatible with h2c upgrade. |
|||
810 | * @return Response|Response[] Note that the client will always return a Response object, even if the call fails |
||||
811 | * |
||||
812 | 375 | * @todo allow throwing exceptions instead of returning responses in case of failed calls and/or Fault responses |
|||
813 | 375 | * @todo refactor: we now support many options besides connection timeout and http version to use. Why only privilege those? |
|||
814 | */ |
||||
815 | 375 | public function send($req, $timeout = 0, $method = '') |
|||
816 | 375 | { |
|||
817 | 375 | if ($method !== '' || $timeout !== 0) { |
|||
818 | 374 | $this->logDeprecation("Using non-default values for arguments 'method' and 'timeout' when calling method " . __METHOD__ . ' is deprecated'); |
|||
819 | 367 | } |
|||
820 | |||||
821 | // if user does not specify http protocol, use native method of this client |
||||
822 | 1 | // (i.e. method set during call to constructor) |
|||
823 | if ($method == '') { |
||||
824 | $method = $this->method; |
||||
825 | } |
||||
826 | |||||
827 | 1 | if ($timeout == 0) { |
|||
828 | 1 | $timeout = $this->timeout; |
|||
829 | } |
||||
830 | 1 | ||||
831 | if (is_array($req)) { |
||||
832 | // $req is an array of Requests |
||||
833 | 374 | /// @todo switch to the new syntax for multicall |
|||
834 | return $this->multicall($req, $timeout, $method); |
||||
835 | } elseif (is_string($req)) { |
||||
836 | $n = new static::$requestClass(''); |
||||
837 | /// @todo we should somehow allow the caller to declare a custom contenttype too, esp. for the charset declaration |
||||
838 | $n->setPayload($req); |
||||
839 | $req = $n; |
||||
840 | } |
||||
841 | |||||
842 | // where req is a Request |
||||
843 | 374 | $req->setDebug($this->debug); |
|||
844 | |||||
845 | /// @todo we could be smarter about this and not force usage of curl for https if not present as well as use the |
||||
846 | /// presence of curl_extra_opts or socket_extra_opts as a hint |
||||
847 | 374 | $useCurl = ($this->use_curl == self::USE_CURL_ALWAYS) || ($this->use_curl == self::USE_CURL_AUTO && ( |
|||
848 | 374 | in_array($method, array('https', 'http11', 'h2c', 'h2')) || |
|||
849 | 374 | ($this->username != '' && $this->authtype != 1) || |
|||
850 | ($this->proxy != '' && $this->proxy_user != '' && $this->proxy_authtype != 1) |
||||
851 | 374 | )); |
|||
852 | |||||
853 | 374 | // BC - we go through sendPayloadCURL/sendPayloadSocket in case some subclass reimplemented those |
|||
854 | if ($useCurl) { |
||||
855 | $r = $this->sendPayloadCURL( |
||||
0 ignored issues
–
show
Deprecated Code
introduced
by
![]() |
|||||
856 | $req, |
||||
857 | $this->server, |
||||
858 | $this->port, |
||||
859 | $timeout, |
||||
860 | $this->username, |
||||
861 | $this->password, |
||||
862 | $this->authtype, |
||||
863 | $this->cert, |
||||
864 | $this->certpass, |
||||
865 | $this->cacert, |
||||
866 | $this->cacertdir, |
||||
867 | $this->proxy, |
||||
868 | $this->proxyport, |
||||
869 | $this->proxy_user, |
||||
870 | $this->proxy_pass, |
||||
871 | $this->proxy_authtype, |
||||
872 | // BC |
||||
873 | $method == 'http11' ? 'http' : $method, |
||||
874 | $this->keepalive, |
||||
875 | $this->key, |
||||
876 | $this->keypass, |
||||
877 | $this->sslversion |
||||
878 | ); |
||||
879 | } else { |
||||
880 | $r = $this->sendPayloadSocket( |
||||
0 ignored issues
–
show
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
![]() |
|||||
881 | $req, |
||||
882 | $this->server, |
||||
883 | $this->port, |
||||
884 | $timeout, |
||||
885 | $this->username, |
||||
886 | 322 | $this->password, |
|||
887 | $this->authtype, |
||||
888 | $this->cert, |
||||
889 | $this->certpass, |
||||
890 | $this->cacert, |
||||
891 | 322 | $this->cacertdir, |
|||
892 | $this->proxy, |
||||
893 | $this->proxyport, |
||||
894 | $this->proxy_user, |
||||
895 | 322 | $this->proxy_pass, |
|||
896 | $this->proxy_authtype, |
||||
897 | 96 | $method, |
|||
898 | 96 | $this->key, |
|||
899 | $this->keypass, |
||||
900 | $this->sslversion |
||||
901 | ); |
||||
902 | } |
||||
903 | |||||
904 | 322 | return $r; |
|||
905 | 322 | } |
|||
906 | |||||
907 | /** |
||||
908 | * @param Request $req |
||||
909 | * @param string $method |
||||
910 | 322 | * @param string $server |
|||
911 | * @param int $port |
||||
912 | * @param string $path |
||||
913 | * @param array $opts |
||||
914 | * @return Response |
||||
915 | 322 | */ |
|||
916 | protected function sendViaSocket($req, $method, $server, $port, $path, $opts) |
||||
917 | 322 | { |
|||
918 | /// @todo log a warning if passed an unsupported method |
||||
919 | |||||
920 | // Only create the payload if it was not created previously |
||||
921 | /// @todo what if the request's payload was created with a different encoding? |
||||
922 | /// Also, if we do not call serialize(), the request will not set its content-type to have the charset declared |
||||
923 | $payload = $req->getPayload(); |
||||
924 | if (empty($payload)) { |
||||
925 | $payload = $req->serialize($opts['request_charset_encoding']); |
||||
926 | } |
||||
927 | |||||
928 | // Deflate request body and set appropriate request headers |
||||
929 | 322 | $encodingHdr = ''; |
|||
930 | if ($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate') { |
||||
931 | if ($opts['request_compression'] == 'gzip' && function_exists('gzencode')) { |
||||
932 | 1 | $a = @gzencode($payload); |
|||
933 | 1 | if ($a) { |
|||
934 | 1 | $payload = $a; |
|||
935 | 1 | $encodingHdr = "Content-Encoding: gzip\r\n"; |
|||
936 | 1 | } else { |
|||
937 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzencode failure in compressing request'); |
||||
938 | } |
||||
939 | 322 | } else if (function_exists('gzcompress')) { |
|||
940 | 160 | $a = @gzcompress($payload); |
|||
941 | if ($a) { |
||||
942 | 322 | $payload = $a; |
|||
943 | $encodingHdr = "Content-Encoding: deflate\r\n"; |
||||
944 | 322 | } else { |
|||
945 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzcompress failure in compressing request'); |
||||
946 | } |
||||
947 | } else { |
||||
948 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported by this PHP install'); |
||||
949 | } |
||||
950 | 322 | } else { |
|||
951 | if ($opts['request_compression'] != '') { |
||||
952 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported'); |
||||
953 | 323 | } |
|||
954 | } |
||||
955 | |||||
956 | // thanks to Grant Rauscher |
||||
957 | $credentials = ''; |
||||
958 | 323 | if ($opts['username'] != '') { |
|||
959 | 322 | if ($opts['authtype'] != 1) { |
|||
960 | 226 | $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported with HTTP 1.0'); |
|||
961 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['unsupported_option'], |
||||
962 | 96 | PhpXmlRpc::$xmlrpcerr['unsupported_option'] . ': only Basic auth is supported with HTTP 1.0'); |
|||
963 | } |
||||
964 | $credentials = 'Authorization: Basic ' . base64_encode($opts['username'] . ':' . $opts['password']) . "\r\n"; |
||||
965 | } |
||||
966 | |||||
967 | 323 | $acceptedEncoding = ''; |
|||
968 | 302 | if (is_array($opts['accepted_compression']) && count($opts['accepted_compression'])) { |
|||
969 | $acceptedEncoding = 'Accept-Encoding: ' . implode(', ', $opts['accepted_compression']) . "\r\n"; |
||||
970 | } |
||||
971 | |||||
972 | 323 | if ($port == 0) { |
|||
973 | 323 | $port = ($method === 'https') ? 443 : 80; |
|||
974 | 64 | } |
|||
975 | 32 | ||||
976 | 32 | $proxyCredentials = ''; |
|||
977 | 32 | if ($opts['proxy']) { |
|||
978 | 32 | if ($opts['proxyport'] == 0) { |
|||
979 | $opts['proxyport'] = 8080; |
||||
980 | } |
||||
981 | 32 | $connectServer = $opts['proxy']; |
|||
982 | 32 | $connectPort = $opts['proxyport']; |
|||
983 | 32 | $transport = 'tcp'; |
|||
984 | 64 | /// @todo check: should we not use https in some cases? |
|||
985 | $uri = 'http://' . $server . ':' . $port . $path; |
||||
986 | if ($opts['proxy_user'] != '') { |
||||
987 | if ($opts['proxy_authtype'] != 1) { |
||||
988 | 259 | $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported with HTTP 1.0'); |
|||
989 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['unsupported_option'], |
||||
990 | PhpXmlRpc::$xmlrpcerr['unsupported_option'] . ': only Basic auth to proxy is supported with HTTP 1.0'); |
||||
991 | 323 | } |
|||
992 | 323 | $proxyCredentials = 'Proxy-Authorization: Basic ' . base64_encode($opts['proxy_user'] . ':' . |
|||
993 | 64 | $opts['proxy_pass']) . "\r\n"; |
|||
994 | } |
||||
995 | 259 | } else { |
|||
996 | 32 | $connectServer = $server; |
|||
997 | $connectPort = $port; |
||||
998 | $transport = ($method === 'https') ? 'tls' : 'tcp'; |
||||
999 | 227 | $uri = $path; |
|||
1000 | } |
||||
1001 | |||||
1002 | 323 | // Cookie generation, as per RFC 6265 |
|||
1003 | 323 | // NB: the following code does not honour 'expires', 'path' and 'domain' cookie attributes set to client obj by the user... |
|||
1004 | 322 | $cookieHeader = ''; |
|||
1005 | if (count($opts['cookies'])) { |
||||
1006 | $version = ''; |
||||
1007 | 56 | foreach ($opts['cookies'] as $name => $cookie) { |
|||
1008 | /// @todo should we sanitize the cookie value on behalf of the user? See setCookie comments |
||||
1009 | $cookieHeader .= ' ' . $name . '=' . $cookie['value'] . ";"; |
||||
1010 | } |
||||
1011 | 323 | $cookieHeader = 'Cookie:' . $version . substr($cookieHeader, 0, -1) . "\r\n"; |
|||
1012 | } |
||||
1013 | 323 | ||||
1014 | $extraHeaders = ''; |
||||
1015 | if (is_array($this->extra_headers) && $this->extra_headers) { |
||||
1016 | $extraHeaders = implode("\r\n", $this->extra_headers) . "\r\n"; |
||||
1017 | 323 | } |
|||
1018 | |||||
1019 | 323 | // omit port if default |
|||
1020 | if (($port == 80 && in_array($method, array('http', 'http10'))) || ($port == 443 && $method == 'https')) { |
||||
1021 | 323 | $port = ''; |
|||
1022 | } else { |
||||
1023 | $port = ':' . $port; |
||||
1024 | 323 | } |
|||
1025 | |||||
1026 | $op = 'POST ' . $uri . " HTTP/1.0\r\n" . |
||||
1027 | 'User-Agent: ' . $opts['user_agent'] . "\r\n" . |
||||
1028 | 323 | 'Host: ' . $server . $port . "\r\n" . |
|||
1029 | $credentials . |
||||
1030 | $proxyCredentials . |
||||
1031 | 66 | $acceptedEncoding . |
|||
1032 | 64 | $encodingHdr . |
|||
1033 | 'Accept-Charset: ' . implode(',', $opts['accepted_charset_encodings']) . "\r\n" . |
||||
1034 | 2 | $cookieHeader . |
|||
1035 | 'Content-Type: ' . $req->getContentType() . "\r\n" . |
||||
1036 | $extraHeaders . |
||||
1037 | 'Content-Length: ' . strlen($payload) . "\r\n\r\n" . |
||||
1038 | 323 | $payload; |
|||
1039 | |||||
1040 | 323 | if ($opts['debug'] > 1) { |
|||
1041 | 161 | $this->getLogger()->debug("---SENDING---\n$op\n---END---"); |
|||
1042 | } |
||||
1043 | |||||
1044 | 323 | $contextOptions = array(); |
|||
1045 | 64 | if ($method == 'https') { |
|||
1046 | if ($opts['cert'] != '') { |
||||
1047 | $contextOptions['ssl']['local_cert'] = $opts['cert']; |
||||
1048 | if ($opts['certpass'] != '') { |
||||
1049 | $contextOptions['ssl']['passphrase'] = $opts['certpass']; |
||||
1050 | 323 | } |
|||
1051 | } |
||||
1052 | 323 | if ($opts['cacert'] != '') { |
|||
1053 | $contextOptions['ssl']['cafile'] = $opts['cacert']; |
||||
1054 | 323 | } |
|||
1055 | 272 | if ($opts['cacertdir'] != '') { |
|||
1056 | $contextOptions['ssl']['capath'] = $opts['cacertdir']; |
||||
1057 | } |
||||
1058 | 323 | if ($opts['key'] != '') { |
|||
1059 | 323 | $contextOptions['ssl']['local_pk'] = $opts['key']; |
|||
1060 | 32 | } |
|||
1061 | 32 | $contextOptions['ssl']['verify_peer'] = $opts['verifypeer']; |
|||
1062 | 291 | $contextOptions['ssl']['verify_peer_name'] = $opts['verifypeer']; |
|||
1063 | |||||
1064 | if ($opts['sslversion'] != 0) { |
||||
1065 | 291 | /// @see https://www.php.net/manual/en/function.curl-setopt.php, https://www.php.net/manual/en/migration56.openssl.php |
|||
1066 | 32 | switch($opts['sslversion']) { |
|||
1067 | 32 | /// @todo what does this map to? 1.0-1.3? |
|||
1068 | 259 | //case 1: // TLSv1 |
|||
1069 | 32 | // break; |
|||
1070 | 32 | case 2: // SSLv2 |
|||
1071 | $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_SSLv2_CLIENT; |
||||
1072 | break; |
||||
1073 | 323 | case 3: // SSLv3 |
|||
1074 | 32 | $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; |
|||
1075 | 32 | break; |
|||
1076 | 32 | case 4: // TLSv1.0 |
|||
1077 | $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; |
||||
1078 | break; |
||||
1079 | case 5: // TLSv1.1 |
||||
1080 | $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; |
||||
1081 | break; |
||||
1082 | 323 | case 6: // TLSv1.2 |
|||
1083 | $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; |
||||
1084 | 96 | break; |
|||
1085 | case 7: // TLSv1.3 |
||||
1086 | if (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT')) { |
||||
1087 | $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT; |
||||
1088 | 96 | } else { |
|||
1089 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['unsupported_option'], |
||||
1090 | PhpXmlRpc::$xmlrpcerr['unsupported_option'] . ': TLS-1.3 only is supported with PHP 7.4 or later'); |
||||
1091 | } |
||||
1092 | 96 | break; |
|||
1093 | default: |
||||
1094 | 96 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['unsupported_option'], |
|||
1095 | PhpXmlRpc::$xmlrpcerr['unsupported_option'] . ': Unsupported required TLS version'); |
||||
1096 | } |
||||
1097 | 96 | } |
|||
1098 | } |
||||
1099 | |||||
1100 | foreach ($opts['extrasockopts'] as $proto => $protoOpts) { |
||||
1101 | 96 | foreach ($protoOpts as $key => $val) { |
|||
1102 | $contextOptions[$proto][$key] = $val; |
||||
1103 | } |
||||
1104 | } |
||||
1105 | 96 | ||||
1106 | $context = stream_context_create($contextOptions); |
||||
1107 | |||||
1108 | if ($opts['timeout'] <= 0) { |
||||
1109 | $connectTimeout = ini_get('default_socket_timeout'); |
||||
1110 | 96 | } else { |
|||
1111 | $connectTimeout = $opts['timeout']; |
||||
1112 | 96 | } |
|||
1113 | |||||
1114 | $this->errno = 0; |
||||
1115 | $this->errstr = ''; |
||||
1116 | 323 | ||||
1117 | 64 | $fp = @stream_socket_client("$transport://$connectServer:$connectPort", $this->errno, $this->errstr, $connectTimeout, |
|||
1118 | STREAM_CLIENT_CONNECT, $context); |
||||
1119 | if ($fp) { |
||||
1120 | 64 | if ($opts['timeout'] > 0) { |
|||
1121 | 64 | stream_set_timeout($fp, $opts['timeout'], 0); |
|||
1122 | } |
||||
1123 | } else { |
||||
1124 | if ($this->errstr == '') { |
||||
1125 | $err = error_get_last(); |
||||
1126 | $this->errstr = $err['message']; |
||||
1127 | } |
||||
1128 | |||||
1129 | $this->errstr = 'Connect error: ' . $this->errstr; |
||||
1130 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['http_error'], $this->errstr . ' (' . $this->errno . ')'); |
||||
1131 | } |
||||
1132 | |||||
1133 | 323 | if (!fputs($fp, $op, strlen($op))) { |
|||
1134 | 271 | fclose($fp); |
|||
1135 | 271 | $this->errstr = 'Write error'; |
|||
1136 | 271 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['http_error'], $this->errstr); |
|||
1137 | } |
||||
1138 | 271 | ||||
1139 | $info = stream_get_meta_data($fp); |
||||
1140 | if ($info['timed_out']) { |
||||
1141 | 323 | fclose($fp); |
|||
1142 | $this->errstr = 'Write timeout'; |
||||
1143 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['http_error'], $this->errstr); |
||||
1144 | } |
||||
1145 | 323 | ||||
1146 | // Close socket before parsing. |
||||
1147 | // It should yield slightly better execution times, and make easier recursive calls (e.g. to follow http redirects) |
||||
1148 | $ipd = ''; |
||||
1149 | 323 | do { |
|||
1150 | // shall we check for $data === FALSE? |
||||
1151 | // as per the manual, it signals an error |
||||
1152 | $ipd .= fread($fp, 32768); |
||||
1153 | |||||
1154 | $info = stream_get_meta_data($fp); |
||||
1155 | if ($info['timed_out']) { |
||||
1156 | fclose($fp); |
||||
1157 | $this->errstr = 'Read timeout'; |
||||
1158 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['http_error'], $this->errstr); |
||||
1159 | } |
||||
1160 | |||||
1161 | } while (!feof($fp)); |
||||
1162 | fclose($fp); |
||||
1163 | |||||
1164 | return $req->parseResponse($ipd, false, $opts['return_type']); |
||||
1165 | } |
||||
1166 | |||||
1167 | /** |
||||
1168 | * Contributed by Justin Miller |
||||
1169 | * Requires curl to be built into PHP |
||||
1170 | * NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers! |
||||
1171 | * |
||||
1172 | * @param Request $req |
||||
1173 | * @param string $method |
||||
1174 | 66 | * @param string $server |
|||
1175 | * @param int $port |
||||
1176 | 66 | * @param string $path |
|||
1177 | * @param array $opts the keys/values match self::getOptions |
||||
1178 | * @return Response |
||||
1179 | 66 | * |
|||
1180 | 45 | * @todo the $path arg atm is ignored. What to do if it is != $this->path? |
|||
1181 | 45 | */ |
|||
1182 | protected function sendViaCURL($req, $method, $server, $port, $path, $opts) |
||||
1183 | 45 | { |
|||
1184 | if (!function_exists('curl_init')) { |
||||
1185 | $this->errstr = 'CURL unavailable on this install'; |
||||
1186 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['no_curl'], PhpXmlRpc::$xmlrpcstr['no_curl']); |
||||
1187 | } |
||||
1188 | if ($method == 'https' || $method == 'h2') { |
||||
1189 | // q: what about installs where we get back a string, but curl is linked to other ssl libs than openssl? |
||||
1190 | if (($info = curl_version()) && |
||||
1191 | ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))) |
||||
1192 | ) { |
||||
1193 | $this->errstr = 'SSL unavailable on this install'; |
||||
1194 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['no_ssl'], PhpXmlRpc::$xmlrpcstr['no_ssl']); |
||||
1195 | } |
||||
1196 | } |
||||
1197 | if (($method == 'h2' && !defined('CURL_HTTP_VERSION_2_0')) || |
||||
1198 | ($method == 'h2c' && !defined('CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE'))) { |
||||
1199 | $this->errstr = 'HTTP/2 unavailable on this install'; |
||||
1200 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['no_http2'], PhpXmlRpc::$xmlrpcstr['no_http2']); |
||||
1201 | 23 | } |
|||
1202 | |||||
1203 | // BC - we go through prepareCurlHandle in case some subclass reimplemented it |
||||
1204 | 23 | $curl = $this->prepareCurlHandle($req, $server, $port, $opts['timeout'], $opts['username'], $opts['password'], |
|||
0 ignored issues
–
show
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
![]() |
|||||
1205 | 23 | $opts['authtype'], $opts['cert'], $opts['certpass'], $opts['cacert'], $opts['cacertdir'], $opts['proxy'], |
|||
1206 | $opts['proxyport'], $opts['proxy_user'], $opts['proxy_pass'], $opts['proxy_authtype'], $method, |
||||
1207 | $opts['keepalive'], $opts['key'], $opts['keypass'], $opts['sslversion']); |
||||
1208 | |||||
1209 | 23 | if (!$curl) { |
|||
1210 | 23 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['curl_fail'], PhpXmlRpc::$xmlrpcstr['curl_fail'] . |
|||
1211 | ': error during curl initialization. Check php error log for details'); |
||||
1212 | } |
||||
1213 | |||||
1214 | $result = curl_exec($curl); |
||||
1215 | |||||
1216 | if ($opts['debug'] > 1) { |
||||
1217 | $message = "---CURL INFO---\n"; |
||||
1218 | foreach (curl_getinfo($curl) as $name => $val) { |
||||
1219 | if (is_array($val)) { |
||||
1220 | $val = implode("\n", $val); |
||||
1221 | 23 | } |
|||
1222 | $message .= $name . ': ' . $val . "\n"; |
||||
1223 | } |
||||
1224 | $message .= '---END---'; |
||||
1225 | $this->getLogger()->debug($message); |
||||
1226 | } |
||||
1227 | |||||
1228 | if (!$result) { |
||||
1229 | /// @todo we should use a better check here - what if we get back '' or '0'? |
||||
1230 | |||||
1231 | $this->errstr = 'no response'; |
||||
1232 | $resp = new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['curl_fail'], PhpXmlRpc::$xmlrpcstr['curl_fail'] . |
||||
1233 | ': ' . curl_error($curl)); |
||||
1234 | curl_close($curl); |
||||
1235 | 45 | if ($opts['keepalive']) { |
|||
1236 | $this->xmlrpc_curl_handle = null; |
||||
1237 | } |
||||
1238 | 45 | } else { |
|||
1239 | 45 | if (!$opts['keepalive']) { |
|||
1240 | 45 | curl_close($curl); |
|||
1241 | 45 | } |
|||
1242 | 45 | $resp = $req->parseResponse($result, true, $opts['return_type']); |
|||
1243 | 45 | if ($opts['keepalive']) { |
|||
1244 | 45 | /// @todo if we got back a 302 or 308, we should not reuse the curl handle for later calls |
|||
1245 | if ($resp->faultCode() == PhpXmlRpc::$xmlrpcerr['http_error']) { |
||||
1246 | 45 | curl_close($curl); |
|||
1247 | 45 | $this->xmlrpc_curl_handle = null; |
|||
1248 | } |
||||
1249 | 45 | } |
|||
1250 | 45 | } |
|||
1251 | |||||
1252 | return $resp; |
||||
1253 | 45 | } |
|||
1254 | |||||
1255 | 45 | /** |
|||
1256 | * @param Request $req |
||||
1257 | * @param string $method |
||||
1258 | * @param string $server |
||||
1259 | * @param int $port |
||||
1260 | * @param string $path |
||||
1261 | 45 | * @param array $opts the keys/values match self::getOptions |
|||
1262 | * @return \CurlHandle|resource|false |
||||
1263 | 45 | * |
|||
1264 | * @todo allow this method to either throw or return a Response, so that we can pass back to caller more info on errors |
||||
1265 | 45 | */ |
|||
1266 | protected function createCURLHandle($req, $method, $server, $port, $path, $opts) |
||||
1267 | 22 | { |
|||
1268 | 22 | if ($port == 0) { |
|||
1269 | if (in_array($method, array('http', 'http10', 'http11', 'h2c'))) { |
||||
1270 | $port = 80; |
||||
1271 | 22 | } else { |
|||
1272 | 22 | $port = 443; |
|||
1273 | } |
||||
1274 | } |
||||
1275 | |||||
1276 | 22 | // Only create the payload if it was not created previously |
|||
1277 | 22 | $payload = $req->getPayload(); |
|||
1278 | 22 | if (empty($payload)) { |
|||
1279 | 22 | $payload = $req->serialize($opts['request_charset_encoding']); |
|||
1280 | } |
||||
1281 | |||||
1282 | 22 | // Deflate request body and set appropriate request headers |
|||
1283 | 22 | $encodingHdr = ''; |
|||
1284 | 22 | if (($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate')) { |
|||
1285 | if ($opts['request_compression'] == 'gzip' && function_exists('gzencode')) { |
||||
1286 | $a = @gzencode($payload); |
||||
1287 | if ($a) { |
||||
1288 | 22 | $payload = $a; |
|||
1289 | 22 | $encodingHdr = 'Content-Encoding: gzip'; |
|||
1290 | 22 | } else { |
|||
1291 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzencode failure in compressing request'); |
||||
1292 | 22 | } |
|||
1293 | 22 | } else if (function_exists('gzcompress')) { |
|||
1294 | $a = @gzcompress($payload); |
||||
1295 | if ($a) { |
||||
1296 | 22 | $payload = $a; |
|||
1297 | 22 | $encodingHdr = 'Content-Encoding: deflate'; |
|||
1298 | } else { |
||||
1299 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzcompress failure in compressing request'); |
||||
1300 | 22 | } |
|||
1301 | 22 | } else { |
|||
1302 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported by this PHP install'); |
||||
1303 | } |
||||
1304 | } else { |
||||
1305 | if ($opts['request_compression'] != '') { |
||||
1306 | $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported'); |
||||
1307 | 22 | } |
|||
1308 | } |
||||
1309 | |||||
1310 | if (!$opts['keepalive'] || !$this->xmlrpc_curl_handle) { |
||||
1311 | 24 | if ($method == 'http11' || $method == 'http10' || $method == 'h2c') { |
|||
1312 | 24 | $protocol = 'http'; |
|||
1313 | } else { |
||||
1314 | if ($method == 'h2') { |
||||
1315 | 24 | $protocol = 'https'; |
|||
1316 | 24 | } else { |
|||
1317 | // http, https |
||||
1318 | $protocol = $method; |
||||
1319 | if (strpos($protocol, ':') !== false) { |
||||
1320 | 24 | $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ": warning - attempted hacking attempt?. The curl protocol requested for the call is: '$protocol'"); |
|||
1321 | 24 | return false; |
|||
1322 | 24 | } |
|||
1323 | 24 | } |
|||
1324 | 24 | } |
|||
1325 | $curl = curl_init($protocol . '://' . $server . ':' . $port . $path); |
||||
1326 | if (!$curl) { |
||||
1327 | return false; |
||||
1328 | 24 | } |
|||
1329 | 24 | if ($opts['keepalive']) { |
|||
1330 | 22 | $this->xmlrpc_curl_handle = $curl; |
|||
1331 | 22 | } |
|||
1332 | } else { |
||||
1333 | 22 | $curl = $this->xmlrpc_curl_handle; |
|||
1334 | } |
||||
1335 | |||||
1336 | 22 | // results into variable |
|||
1337 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
||||
1338 | 22 | ||||
1339 | if ($opts['debug'] > 1) { |
||||
1340 | curl_setopt($curl, CURLOPT_VERBOSE, true); |
||||
1341 | 22 | /// @todo redirect curlopt_stderr to some stream which can be piped to the logger |
|||
1342 | 22 | } |
|||
1343 | curl_setopt($curl, CURLOPT_USERAGENT, $opts['user_agent']); |
||||
1344 | // required for XMLRPC: post the data |
||||
1345 | curl_setopt($curl, CURLOPT_POST, 1); |
||||
1346 | // the data |
||||
1347 | curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); |
||||
1348 | 24 | ||||
1349 | // return the header too |
||||
1350 | curl_setopt($curl, CURLOPT_HEADER, 1); |
||||
1351 | |||||
1352 | // NB: if we set an empty string, CURL will add http header indicating |
||||
1353 | // ALL methods it is supporting. This is possibly a better option than letting the user tell what curl can / cannot do... |
||||
1354 | if (is_array($opts['accepted_compression']) && count($opts['accepted_compression'])) { |
||||
1355 | //curl_setopt($curl, CURLOPT_ENCODING, implode(',', $opts['accepted_compression'])); |
||||
1356 | // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?) |
||||
1357 | if (count($opts['accepted_compression']) == 1) { |
||||
1358 | curl_setopt($curl, CURLOPT_ENCODING, $opts['accepted_compression'][0]); |
||||
1359 | } else { |
||||
1360 | curl_setopt($curl, CURLOPT_ENCODING, ''); |
||||
1361 | } |
||||
1362 | } |
||||
1363 | // extra headers |
||||
1364 | $headers = array('Content-Type: ' . $req->getContentType(), 'Accept-Charset: ' . implode(',', $opts['accepted_charset_encodings'])); |
||||
1365 | // if no keepalive is wanted, let the server know it in advance |
||||
1366 | if (!$opts['keepalive']) { |
||||
1367 | $headers[] = 'Connection: close'; |
||||
1368 | } |
||||
1369 | // request compression header |
||||
1370 | if ($encodingHdr) { |
||||
1371 | $headers[] = $encodingHdr; |
||||
1372 | } |
||||
1373 | |||||
1374 | if (is_array($this->extra_headers) && $this->extra_headers) { |
||||
1375 | $headers = array_merge($headers, $this->extra_headers); |
||||
1376 | } |
||||
1377 | |||||
1378 | // Fix the HTTP/1.1 417 Expectation Failed Bug (curl by default adds a 'Expect: 100-continue' header when POST |
||||
1379 | // size exceeds 1025 bytes, apparently) |
||||
1380 | $headers[] = 'Expect:'; |
||||
1381 | |||||
1382 | curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); |
||||
1383 | // previous note: "timeout is borked" (on some old php/curl versions? It seems to work on 8.1. Maybe the issue |
||||
1384 | // has to do with dns resolution...) |
||||
1385 | if ($opts['timeout']) { |
||||
1386 | curl_setopt($curl, CURLOPT_TIMEOUT, $opts['timeout']); |
||||
1387 | } |
||||
1388 | |||||
1389 | switch ($method) { |
||||
1390 | case 'http10': |
||||
1391 | curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); |
||||
1392 | break; |
||||
1393 | case 'http11': |
||||
1394 | curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); |
||||
1395 | break; |
||||
1396 | case 'h2c': |
||||
1397 | if (defined('CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE')) { |
||||
1398 | curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); |
||||
1399 | } else { |
||||
1400 | $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. HTTP2 is not supported by the current PHP/curl install'); |
||||
1401 | curl_close($curl); |
||||
1402 | return false; |
||||
1403 | } |
||||
1404 | break; |
||||
1405 | case 'h2': |
||||
1406 | curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); |
||||
1407 | break; |
||||
1408 | } |
||||
1409 | |||||
1410 | if ($opts['username'] && $opts['password']) { |
||||
1411 | curl_setopt($curl, CURLOPT_USERPWD, $opts['username'] . ':' . $opts['password']); |
||||
1412 | if (defined('CURLOPT_HTTPAUTH')) { |
||||
1413 | curl_setopt($curl, CURLOPT_HTTPAUTH, $opts['authtype']); |
||||
1414 | } elseif ($opts['authtype'] != 1) { |
||||
1415 | $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported by the current PHP/curl install'); |
||||
1416 | curl_close($curl); |
||||
1417 | return false; |
||||
1418 | } |
||||
1419 | } |
||||
1420 | |||||
1421 | // note: h2c is http2 without the https. No need to have it in this IF |
||||
1422 | if ($method == 'https' || $method == 'h2') { |
||||
1423 | // set cert file |
||||
1424 | if ($opts['cert']) { |
||||
1425 | curl_setopt($curl, CURLOPT_SSLCERT, $opts['cert']); |
||||
1426 | } |
||||
1427 | // set cert password |
||||
1428 | if ($opts['certpass']) { |
||||
1429 | curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $opts['certpass']); |
||||
1430 | } |
||||
1431 | // whether to verify remote host's cert |
||||
1432 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $opts['verifypeer']); |
||||
1433 | // set ca certificates file/dir |
||||
1434 | if ($opts['cacert']) { |
||||
1435 | curl_setopt($curl, CURLOPT_CAINFO, $opts['cacert']); |
||||
1436 | } |
||||
1437 | if ($opts['cacertdir']) { |
||||
1438 | curl_setopt($curl, CURLOPT_CAPATH, $opts['cacertdir']); |
||||
1439 | } |
||||
1440 | // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?) |
||||
1441 | if ($opts['key']) { |
||||
1442 | curl_setopt($curl, CURLOPT_SSLKEY, $opts['key']); |
||||
1443 | } |
||||
1444 | // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?) |
||||
1445 | if ($opts['keypass']) { |
||||
1446 | curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $opts['keypass']); |
||||
1447 | } |
||||
1448 | // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that |
||||
1449 | // it matches the hostname used |
||||
1450 | curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $opts['verifyhost']); |
||||
1451 | // allow usage of different SSL versions |
||||
1452 | curl_setopt($curl, CURLOPT_SSLVERSION, $opts['sslversion']); |
||||
1453 | } |
||||
1454 | |||||
1455 | // proxy info |
||||
1456 | if ($opts['proxy']) { |
||||
1457 | if ($opts['proxyport'] == 0) { |
||||
1458 | $opts['proxyport'] = 8080; // NB: even for HTTPS, local connection is on port 8080 |
||||
1459 | } |
||||
1460 | curl_setopt($curl, CURLOPT_PROXY, $opts['proxy'] . ':' . $opts['proxyport']); |
||||
1461 | if ($opts['proxy_user']) { |
||||
1462 | curl_setopt($curl, CURLOPT_PROXYUSERPWD, $opts['proxy_user'] . ':' . $opts['proxy_pass']); |
||||
1463 | if (defined('CURLOPT_PROXYAUTH')) { |
||||
1464 | curl_setopt($curl, CURLOPT_PROXYAUTH, $opts['proxy_authtype']); |
||||
1465 | } elseif ($opts['proxy_authtype'] != 1) { |
||||
1466 | $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); |
||||
1467 | curl_close($curl); |
||||
1468 | return false; |
||||
1469 | } |
||||
1470 | } |
||||
1471 | } |
||||
1472 | |||||
1473 | // NB: should we build cookie http headers by hand rather than let CURL do it? |
||||
1474 | // NB: the following code does not honour 'expires', 'path' and 'domain' cookie attributes set to client obj by the user... |
||||
1475 | if (count($opts['cookies'])) { |
||||
1476 | $cookieHeader = ''; |
||||
1477 | foreach ($opts['cookies'] as $name => $cookie) { |
||||
1478 | $cookieHeader .= $name . '=' . $cookie['value'] . '; '; |
||||
1479 | } |
||||
1480 | curl_setopt($curl, CURLOPT_COOKIE, substr($cookieHeader, 0, -2)); |
||||
1481 | } |
||||
1482 | |||||
1483 | foreach ($opts['extracurlopts'] as $opt => $val) { |
||||
1484 | curl_setopt($curl, $opt, $val); |
||||
1485 | } |
||||
1486 | |||||
1487 | if ($opts['debug'] > 1) { |
||||
1488 | $this->getLogger()->debug("---SENDING---\n$payload\n---END---"); |
||||
1489 | } |
||||
1490 | |||||
1491 | return $curl; |
||||
1492 | } |
||||
1493 | |||||
1494 | /** |
||||
1495 | * Send an array of requests and return an array of responses. |
||||
1496 | * |
||||
1497 | * Unless $this->no_multicall has been set to true, it will try first to use one single xml-rpc call to server method |
||||
1498 | * system.multicall, and revert to sending many successive calls in case of failure. |
||||
1499 | * This failure is also stored in $this->no_multicall for subsequent calls. |
||||
1500 | * Unfortunately, there is no server error code universally used to denote the fact that multicall is unsupported, |
||||
1501 | * so there is no way to reliably distinguish between that and a temporary failure. |
||||
1502 | * If you are sure that server supports multicall and do not want to fallback to using many single calls, set the |
||||
1503 | * 2np parameter to FALSE. |
||||
1504 | * |
||||
1505 | * NB: trying to shoehorn extra functionality into existing syntax has resulted |
||||
1506 | * in pretty much convoluted code... |
||||
1507 | * |
||||
1508 | * @param Request[] $reqs an array of Request objects |
||||
1509 | * @param bool $noFallback When true, upon receiving an error during multicall, multiple single calls will not be |
||||
1510 | * attempted. |
||||
1511 | * Deprecated alternative, was: int - "connection timeout (in seconds). See the details in the |
||||
1512 | * docs for the send() method". Please use setOption instead to set a timeout |
||||
1513 | * @param string $method deprecated. Was: "the http protocol variant to be used. See the details in the docs for the send() method." |
||||
1514 | * Please use the constructor to set an http protocol variant. |
||||
1515 | * @param boolean $fallback deprecated. Was: "when true, upon receiving an error during multicall, multiple single |
||||
1516 | * calls will be attempted" |
||||
1517 | * @return Response[] |
||||
1518 | */ |
||||
1519 | public function multicall($reqs, $timeout = 0, $method = '', $fallback = true) |
||||
1520 | { |
||||
1521 | // BC |
||||
1522 | if (is_bool($timeout) && $fallback === true) { |
||||
1523 | $fallback = !$timeout; |
||||
1524 | $timeout = 0; |
||||
1525 | } |
||||
1526 | |||||
1527 | if ($method == '') { |
||||
1528 | $method = $this->method; |
||||
1529 | } |
||||
1530 | |||||
1531 | if (!$this->no_multicall) { |
||||
1532 | $results = $this->_try_multicall($reqs, $timeout, $method); |
||||
1533 | /// @todo how to handle the case of $this->return_type = xml? |
||||
1534 | if (is_array($results)) { |
||||
1535 | // System.multicall succeeded |
||||
1536 | return $results; |
||||
1537 | } else { |
||||
1538 | // either system.multicall is unsupported by server, or the call failed for some other reason. |
||||
1539 | // Feature creep: is there a way to tell apart unsupported multicall from other faults? |
||||
1540 | if ($fallback) { |
||||
1541 | // Don't try it next time... |
||||
1542 | $this->no_multicall = true; |
||||
1543 | } else { |
||||
1544 | $result = $results; |
||||
1545 | } |
||||
1546 | } |
||||
1547 | } else { |
||||
1548 | // override fallback, in case careless user tries to do two |
||||
1549 | // opposite things at the same time |
||||
1550 | $fallback = true; |
||||
1551 | } |
||||
1552 | |||||
1553 | $results = array(); |
||||
1554 | if ($fallback) { |
||||
1555 | // system.multicall is (probably) unsupported by server: emulate multicall via multiple requests |
||||
1556 | /// @todo use curl multi_ functions to make this quicker (see the implementation in the parallel.php demo) |
||||
1557 | foreach ($reqs as $req) { |
||||
1558 | $results[] = $this->send($req, $timeout, $method); |
||||
1559 | } |
||||
1560 | } else { |
||||
1561 | // user does NOT want to fallback on many single calls: since we should always return an array of responses, |
||||
1562 | // we return an array with the same error repeated n times |
||||
1563 | foreach ($reqs as $req) { |
||||
1564 | $results[] = $result; |
||||
1565 | } |
||||
1566 | } |
||||
1567 | |||||
1568 | return $results; |
||||
1569 | } |
||||
1570 | |||||
1571 | /** |
||||
1572 | * Attempt to boxcar $reqs via system.multicall. |
||||
1573 | * |
||||
1574 | * @param Request[] $reqs |
||||
1575 | * @param int $timeout |
||||
1576 | * @param string $method |
||||
1577 | * @return Response[]|Response a single Response when the call returned a fault / does not conform to what we expect |
||||
1578 | * from a multicall response |
||||
1579 | */ |
||||
1580 | private function _try_multicall($reqs, $timeout, $method) |
||||
1581 | { |
||||
1582 | // Construct multicall request |
||||
1583 | $calls = array(); |
||||
1584 | foreach ($reqs as $req) { |
||||
1585 | $call['methodName'] = new Value($req->method(), 'string'); |
||||
1586 | $numParams = $req->getNumParams(); |
||||
1587 | $params = array(); |
||||
1588 | for ($i = 0; $i < $numParams; $i++) { |
||||
1589 | $params[$i] = $req->getParam($i); |
||||
1590 | } |
||||
1591 | $call['params'] = new Value($params, 'array'); |
||||
1592 | $calls[] = new Value($call, 'struct'); |
||||
1593 | } |
||||
1594 | $multiCall = new static::$requestClass('system.multicall'); |
||||
1595 | $multiCall->addParam(new Value($calls, 'array')); |
||||
1596 | |||||
1597 | // Attempt RPC call |
||||
1598 | $result = $this->send($multiCall, $timeout, $method); |
||||
1599 | |||||
1600 | if ($result->faultCode() != 0) { |
||||
1601 | // call to system.multicall failed |
||||
1602 | return $result; |
||||
1603 | } |
||||
1604 | |||||
1605 | // Unpack responses. |
||||
1606 | $rets = $result->value(); |
||||
1607 | $response = array(); |
||||
1608 | |||||
1609 | if ($this->return_type == 'xml') { |
||||
1610 | for ($i = 0; $i < count($reqs); $i++) { |
||||
1611 | $response[] = new static::$responseClass($rets, 0, '', 'xml', $result->httpResponse()); |
||||
1612 | } |
||||
1613 | |||||
1614 | } elseif ($this->return_type == 'phpvals') { |
||||
1615 | if (!is_array($rets)) { |
||||
1616 | // bad return type from system.multicall |
||||
1617 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1618 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ': not an array', 'phpvals', $result->httpResponse()); |
||||
1619 | } |
||||
1620 | $numRets = count($rets); |
||||
1621 | if ($numRets != count($reqs)) { |
||||
1622 | // wrong number of return values. |
||||
1623 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1624 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ': incorrect number of responses', 'phpvals', |
||||
1625 | $result->httpResponse()); |
||||
1626 | } |
||||
1627 | |||||
1628 | for ($i = 0; $i < $numRets; $i++) { |
||||
1629 | $val = $rets[$i]; |
||||
1630 | if (!is_array($val)) { |
||||
1631 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1632 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i is not an array or struct", |
||||
1633 | 'phpvals', $result->httpResponse()); |
||||
1634 | } |
||||
1635 | switch (count($val)) { |
||||
1636 | case 1: |
||||
1637 | if (!isset($val[0])) { |
||||
1638 | // Bad value |
||||
1639 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1640 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has no value", |
||||
1641 | 'phpvals', $result->httpResponse()); |
||||
1642 | } |
||||
1643 | // Normal return value |
||||
1644 | $response[$i] = new static::$responseClass($val[0], 0, '', 'phpvals', $result->httpResponse()); |
||||
1645 | break; |
||||
1646 | case 2: |
||||
1647 | /// @todo remove usage of @: it is apparently quite slow |
||||
1648 | $code = @$val['faultCode']; |
||||
1649 | if (!is_int($code)) { |
||||
1650 | /// @todo should we check that it is != 0? |
||||
1651 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1652 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no faultCode", |
||||
1653 | 'phpvals', $result->httpResponse()); |
||||
1654 | } |
||||
1655 | $str = @$val['faultString']; |
||||
1656 | if (!is_string($str)) { |
||||
1657 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1658 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no FaultString", |
||||
1659 | 'phpvals', $result->httpResponse()); |
||||
1660 | } |
||||
1661 | $response[$i] = new static::$responseClass(0, $code, $str, 'phpvals', $result->httpResponse()); |
||||
1662 | break; |
||||
1663 | default: |
||||
1664 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1665 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has too many items", |
||||
1666 | 'phpvals', $result->httpResponse()); |
||||
1667 | } |
||||
1668 | } |
||||
1669 | |||||
1670 | } else { |
||||
1671 | // return type == 'xmlrpcvals' |
||||
1672 | if ($rets->kindOf() != 'array') { |
||||
1673 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1674 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i is not an array", 'xmlrpcvals', |
||||
1675 | $result->httpResponse()); |
||||
1676 | } |
||||
1677 | $numRets = $rets->count(); |
||||
1678 | if ($numRets != count($reqs)) { |
||||
1679 | // wrong number of return values. |
||||
1680 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1681 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ': incorrect number of responses', 'xmlrpcvals', |
||||
1682 | $result->httpResponse()); |
||||
1683 | } |
||||
1684 | |||||
1685 | foreach ($rets as $i => $val) { |
||||
1686 | switch ($val->kindOf()) { |
||||
1687 | case 'array': |
||||
1688 | if ($val->count() != 1) { |
||||
1689 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1690 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has too many items", |
||||
1691 | 'phpvals', $result->httpResponse()); |
||||
1692 | } |
||||
1693 | // Normal return value |
||||
1694 | $response[] = new static::$responseClass($val[0], 0, '', 'xmlrpcvals', $result->httpResponse()); |
||||
1695 | break; |
||||
1696 | case 'struct': |
||||
1697 | if ($val->count() != 2) { |
||||
1698 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1699 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has too many items", |
||||
1700 | 'phpvals', $result->httpResponse()); |
||||
1701 | } |
||||
1702 | /** @var Value $code */ |
||||
1703 | $code = $val['faultCode']; |
||||
1704 | if ($code->kindOf() != 'scalar' || $code->scalarTyp() != 'int') { |
||||
1705 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1706 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no faultCode", |
||||
1707 | 'xmlrpcvals', $result->httpResponse()); |
||||
1708 | } |
||||
1709 | /** @var Value $str */ |
||||
1710 | $str = $val['faultString']; |
||||
1711 | if ($str->kindOf() != 'scalar' || $str->scalarTyp() != 'string') { |
||||
1712 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1713 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i has invalid or no faultCode", |
||||
1714 | 'xmlrpcvals', $result->httpResponse()); |
||||
1715 | } |
||||
1716 | $response[] = new static::$responseClass(0, $code->scalarVal(), $str->scalarVal(), 'xmlrpcvals', $result->httpResponse()); |
||||
1717 | break; |
||||
1718 | default: |
||||
1719 | return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['multicall_error'], |
||||
1720 | PhpXmlRpc::$xmlrpcstr['multicall_error'] . ": response element $i is not an array or struct", |
||||
1721 | 'xmlrpcvals', $result->httpResponse()); |
||||
1722 | } |
||||
1723 | } |
||||
1724 | } |
||||
1725 | |||||
1726 | return $response; |
||||
1727 | } |
||||
1728 | |||||
1729 | // *** BC layer *** |
||||
1730 | |||||
1731 | /** |
||||
1732 | * @deprecated |
||||
1733 | * |
||||
1734 | * @param Request $req |
||||
1735 | * @param string $server |
||||
1736 | * @param int $port |
||||
1737 | * @param int $timeout |
||||
1738 | * @param string $username |
||||
1739 | * @param string $password |
||||
1740 | * @param int $authType |
||||
1741 | * @param string $proxyHost |
||||
1742 | * @param int $proxyPort |
||||
1743 | * @param string $proxyUsername |
||||
1744 | * @param string $proxyPassword |
||||
1745 | * @param int $proxyAuthType |
||||
1746 | * @param string $method |
||||
1747 | * @return Response |
||||
1748 | */ |
||||
1749 | protected function sendPayloadHTTP10($req, $server, $port, $timeout = 0, $username = '', $password = '', |
||||
1750 | $authType = 1, $proxyHost = '', $proxyPort = 0, $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, |
||||
1751 | $method = 'http') |
||||
1752 | { |
||||
1753 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||||
1754 | |||||
1755 | return $this->sendPayloadSocket($req, $server, $port, $timeout, $username, $password, $authType, null, null, |
||||
0 ignored issues
–
show
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
![]() |
|||||
1756 | null, null, $proxyHost, $proxyPort, $proxyUsername, $proxyPassword, $proxyAuthType, $method); |
||||
1757 | } |
||||
1758 | |||||
1759 | /** |
||||
1760 | * @deprecated |
||||
1761 | * |
||||
1762 | * @param Request $req |
||||
1763 | * @param string $server |
||||
1764 | * @param int $port |
||||
1765 | * @param int $timeout |
||||
1766 | * @param string $username |
||||
1767 | * @param string $password |
||||
1768 | * @param int $authType |
||||
1769 | * @param string $cert |
||||
1770 | * @param string $certPass |
||||
1771 | * @param string $caCert |
||||
1772 | * @param string $caCertDir |
||||
1773 | * @param string $proxyHost |
||||
1774 | * @param int $proxyPort |
||||
1775 | * @param string $proxyUsername |
||||
1776 | * @param string $proxyPassword |
||||
1777 | * @param int $proxyAuthType |
||||
1778 | * @param bool $keepAlive |
||||
1779 | * @param string $key |
||||
1780 | * @param string $keyPass |
||||
1781 | * @param int $sslVersion |
||||
1782 | * @return Response |
||||
1783 | */ |
||||
1784 | protected function sendPayloadHTTPS($req, $server, $port, $timeout = 0, $username = '', $password = '', |
||||
1785 | $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0, |
||||
1786 | $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $keepAlive = false, $key = '', $keyPass = '', |
||||
1787 | $sslVersion = 0) |
||||
1788 | { |
||||
1789 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||||
1790 | |||||
1791 | return $this->sendPayloadCURL($req, $server, $port, $timeout, $username, |
||||
0 ignored issues
–
show
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
![]() |
|||||
1792 | $password, $authType, $cert, $certPass, $caCert, $caCertDir, $proxyHost, $proxyPort, |
||||
1793 | $proxyUsername, $proxyPassword, $proxyAuthType, 'https', $keepAlive, $key, $keyPass, $sslVersion); |
||||
1794 | } |
||||
1795 | |||||
1796 | /** |
||||
1797 | * @deprecated |
||||
1798 | * |
||||
1799 | * @param Request $req |
||||
1800 | * @param string $server |
||||
1801 | * @param int $port |
||||
1802 | * @param int $timeout |
||||
1803 | * @param string $username |
||||
1804 | * @param string $password |
||||
1805 | * @param int $authType only value supported is 1 |
||||
1806 | * @param string $cert |
||||
1807 | * @param string $certPass |
||||
1808 | * @param string $caCert |
||||
1809 | * @param string $caCertDir |
||||
1810 | * @param string $proxyHost |
||||
1811 | * @param int $proxyPort |
||||
1812 | * @param string $proxyUsername |
||||
1813 | * @param string $proxyPassword |
||||
1814 | * @param int $proxyAuthType only value supported is 1 |
||||
1815 | * @param string $method 'http' (synonym for 'http10'), 'http10' or 'https' |
||||
1816 | * @param string $key |
||||
1817 | * @param string $keyPass @todo not implemented yet. |
||||
1818 | * @param int $sslVersion |
||||
1819 | * @return Response |
||||
1820 | */ |
||||
1821 | protected function sendPayloadSocket($req, $server, $port, $timeout = 0, $username = '', $password = '', |
||||
1822 | $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0, |
||||
1823 | $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $method = 'http', $key = '', $keyPass = '', |
||||
1824 | $sslVersion = 0) |
||||
1825 | { |
||||
1826 | $this->logDeprecationUnlessCalledBy('send'); |
||||
1827 | |||||
1828 | return $this->sendViaSocket($req, $method, $server, $port, $this->path, array( |
||||
1829 | 'accepted_charset_encodings' => $this->accepted_charset_encodings, |
||||
1830 | 'accepted_compression' => $this->accepted_compression, |
||||
1831 | 'authtype' => $authType, |
||||
1832 | 'cacert' => $caCert, |
||||
1833 | 'cacertdir' => $caCertDir, |
||||
1834 | 'cert' => $cert, |
||||
1835 | 'certpass' => $certPass, |
||||
1836 | 'cookies' => $this->cookies, |
||||
1837 | 'debug' => $this->debug, |
||||
1838 | 'extracurlopts' => $this->extracurlopts, |
||||
1839 | 'extrasockopts' => $this->extrasockopts, |
||||
1840 | 'keepalive' => $this->keepalive, |
||||
1841 | 'key' => $key, |
||||
1842 | 'keypass' => $keyPass, |
||||
1843 | 'no_multicall' => $this->no_multicall, |
||||
1844 | 'password' => $password, |
||||
1845 | 'proxy' => $proxyHost, |
||||
1846 | 'proxy_authtype' => $proxyAuthType, |
||||
1847 | 'proxy_pass' => $proxyPassword, |
||||
1848 | 'proxyport' => $proxyPort, |
||||
1849 | 'proxy_user' => $proxyUsername, |
||||
1850 | 'request_charset_encoding' => $this->request_charset_encoding, |
||||
1851 | 'request_compression' => $this->request_compression, |
||||
1852 | 'return_type' => $this->return_type, |
||||
1853 | 'sslversion' => $sslVersion, |
||||
1854 | 'timeout' => $timeout, |
||||
1855 | 'username' => $username, |
||||
1856 | 'user_agent' => $this->user_agent, |
||||
1857 | 'use_curl' => $this->use_curl, |
||||
1858 | 'verifyhost' => $this->verifyhost, |
||||
1859 | 'verifypeer' => $this->verifypeer, |
||||
1860 | )); |
||||
1861 | } |
||||
1862 | |||||
1863 | /** |
||||
1864 | * @deprecated |
||||
1865 | * |
||||
1866 | * @param Request $req |
||||
1867 | * @param string $server |
||||
1868 | * @param int $port |
||||
1869 | * @param int $timeout |
||||
1870 | * @param string $username |
||||
1871 | * @param string $password |
||||
1872 | * @param int $authType |
||||
1873 | * @param string $cert |
||||
1874 | * @param string $certPass |
||||
1875 | * @param string $caCert |
||||
1876 | * @param string $caCertDir |
||||
1877 | * @param string $proxyHost |
||||
1878 | * @param int $proxyPort |
||||
1879 | * @param string $proxyUsername |
||||
1880 | * @param string $proxyPassword |
||||
1881 | * @param int $proxyAuthType |
||||
1882 | * @param string $method 'http' (let curl decide), 'http10', 'http11', 'https', 'h2c' or 'h2' |
||||
1883 | * @param bool $keepAlive |
||||
1884 | * @param string $key |
||||
1885 | * @param string $keyPass |
||||
1886 | * @param int $sslVersion |
||||
1887 | * @return Response |
||||
1888 | */ |
||||
1889 | protected function sendPayloadCURL($req, $server, $port, $timeout = 0, $username = '', $password = '', |
||||
1890 | $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0, |
||||
1891 | $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $method = 'https', $keepAlive = false, $key = '', |
||||
1892 | $keyPass = '', $sslVersion = 0) |
||||
1893 | { |
||||
1894 | $this->logDeprecationUnlessCalledBy('send'); |
||||
1895 | |||||
1896 | return $this->sendViaCURL($req, $method, $server, $port, $this->path, array( |
||||
1897 | 'accepted_charset_encodings' => $this->accepted_charset_encodings, |
||||
1898 | 'accepted_compression' => $this->accepted_compression, |
||||
1899 | 'authtype' => $authType, |
||||
1900 | 'cacert' => $caCert, |
||||
1901 | 'cacertdir' => $caCertDir, |
||||
1902 | 'cert' => $cert, |
||||
1903 | 'certpass' => $certPass, |
||||
1904 | 'cookies' => $this->cookies, |
||||
1905 | 'debug' => $this->debug, |
||||
1906 | 'extracurlopts' => $this->extracurlopts, |
||||
1907 | 'extrasockopts' => $this->extrasockopts, |
||||
1908 | 'keepalive' => $keepAlive, |
||||
1909 | 'key' => $key, |
||||
1910 | 'keypass' => $keyPass, |
||||
1911 | 'no_multicall' => $this->no_multicall, |
||||
1912 | 'password' => $password, |
||||
1913 | 'proxy' => $proxyHost, |
||||
1914 | 'proxy_authtype' => $proxyAuthType, |
||||
1915 | 'proxy_pass' => $proxyPassword, |
||||
1916 | 'proxyport' => $proxyPort, |
||||
1917 | 'proxy_user' => $proxyUsername, |
||||
1918 | 'request_charset_encoding' => $this->request_charset_encoding, |
||||
1919 | 'request_compression' => $this->request_compression, |
||||
1920 | 'return_type' => $this->return_type, |
||||
1921 | 'sslversion' => $sslVersion, |
||||
1922 | 'timeout' => $timeout, |
||||
1923 | 'username' => $username, |
||||
1924 | 'user_agent' => $this->user_agent, |
||||
1925 | 'use_curl' => $this->use_curl, |
||||
1926 | 'verifyhost' => $this->verifyhost, |
||||
1927 | 'verifypeer' => $this->verifypeer, |
||||
1928 | )); |
||||
1929 | } |
||||
1930 | |||||
1931 | /** |
||||
1932 | * @deprecated |
||||
1933 | * |
||||
1934 | * @param $req |
||||
1935 | * @param $server |
||||
1936 | * @param $port |
||||
1937 | * @param $timeout |
||||
1938 | * @param $username |
||||
1939 | * @param $password |
||||
1940 | * @param $authType |
||||
1941 | * @param $cert |
||||
1942 | * @param $certPass |
||||
1943 | * @param $caCert |
||||
1944 | * @param $caCertDir |
||||
1945 | * @param $proxyHost |
||||
1946 | * @param $proxyPort |
||||
1947 | * @param $proxyUsername |
||||
1948 | * @param $proxyPassword |
||||
1949 | * @param $proxyAuthType |
||||
1950 | * @param $method |
||||
1951 | * @param $keepAlive |
||||
1952 | * @param $key |
||||
1953 | * @param $keyPass |
||||
1954 | * @param $sslVersion |
||||
1955 | * @return false|\CurlHandle|resource |
||||
1956 | */ |
||||
1957 | protected function prepareCurlHandle($req, $server, $port, $timeout = 0, $username = '', $password = '', |
||||
1958 | $authType = 1, $cert = '', $certPass = '', $caCert = '', $caCertDir = '', $proxyHost = '', $proxyPort = 0, |
||||
1959 | $proxyUsername = '', $proxyPassword = '', $proxyAuthType = 1, $method = 'https', $keepAlive = false, $key = '', |
||||
1960 | $keyPass = '', $sslVersion = 0) |
||||
1961 | { |
||||
1962 | $this->logDeprecationUnlessCalledBy('sendViaCURL'); |
||||
1963 | |||||
1964 | return $this->createCURLHandle($req, $method, $server, $port, $this->path, array( |
||||
1965 | 'accepted_charset_encodings' => $this->accepted_charset_encodings, |
||||
1966 | 'accepted_compression' => $this->accepted_compression, |
||||
1967 | 'authtype' => $authType, |
||||
1968 | 'cacert' => $caCert, |
||||
1969 | 'cacertdir' => $caCertDir, |
||||
1970 | 'cert' => $cert, |
||||
1971 | 'certpass' => $certPass, |
||||
1972 | 'cookies' => $this->cookies, |
||||
1973 | 'debug' => $this->debug, |
||||
1974 | 'extracurlopts' => $this->extracurlopts, |
||||
1975 | 'keepalive' => $keepAlive, |
||||
1976 | 'key' => $key, |
||||
1977 | 'keypass' => $keyPass, |
||||
1978 | 'no_multicall' => $this->no_multicall, |
||||
1979 | 'password' => $password, |
||||
1980 | 'proxy' => $proxyHost, |
||||
1981 | 'proxy_authtype' => $proxyAuthType, |
||||
1982 | 'proxy_pass' => $proxyPassword, |
||||
1983 | 'proxyport' => $proxyPort, |
||||
1984 | 'proxy_user' => $proxyUsername, |
||||
1985 | 'request_charset_encoding' => $this->request_charset_encoding, |
||||
1986 | 'request_compression' => $this->request_compression, |
||||
1987 | 'return_type' => $this->return_type, |
||||
1988 | 'sslversion' => $sslVersion, |
||||
1989 | 'timeout' => $timeout, |
||||
1990 | 'username' => $username, |
||||
1991 | 'user_agent' => $this->user_agent, |
||||
1992 | 'use_curl' => $this->use_curl, |
||||
1993 | 'verifyhost' => $this->verifyhost, |
||||
1994 | 'verifypeer' => $this->verifypeer, |
||||
1995 | )); |
||||
1996 | } |
||||
1997 | |||||
1998 | // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];` |
||||
1999 | public function &__get($name) |
||||
2000 | { |
||||
2001 | if (in_array($name, static::$options)) { |
||||
2002 | $this->logDeprecation('Getting property Client::' . $name . ' is deprecated'); |
||||
2003 | return $this->$name; |
||||
2004 | } |
||||
2005 | |||||
2006 | switch ($name) { |
||||
2007 | case 'errno': |
||||
2008 | case 'errstr': |
||||
2009 | case 'method': |
||||
2010 | case 'server': |
||||
2011 | case 'port': |
||||
2012 | case 'path': |
||||
2013 | $this->logDeprecation('Getting property Client::' . $name . ' is deprecated'); |
||||
2014 | return $this->$name; |
||||
2015 | default: |
||||
2016 | /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... |
||||
2017 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); |
||||
2018 | trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); |
||||
2019 | $result = null; |
||||
2020 | return $result; |
||||
2021 | } |
||||
2022 | } |
||||
2023 | |||||
2024 | public function __set($name, $value) |
||||
2025 | { |
||||
2026 | if (in_array($name, static::$options)) { |
||||
2027 | $this->logDeprecation('Setting property Client::' . $name . ' is deprecated'); |
||||
2028 | $this->$name = $value; |
||||
2029 | return; |
||||
2030 | } |
||||
2031 | |||||
2032 | switch ($name) { |
||||
2033 | case 'errno': |
||||
2034 | case 'errstr': |
||||
2035 | case 'method': |
||||
2036 | case 'server': |
||||
2037 | case 'port': |
||||
2038 | case 'path': |
||||
2039 | $this->logDeprecation('Setting property Client::' . $name . ' is deprecated'); |
||||
2040 | $this->$name = $value; |
||||
2041 | return; |
||||
2042 | default: |
||||
2043 | /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... |
||||
2044 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); |
||||
2045 | trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); |
||||
2046 | } |
||||
2047 | } |
||||
2048 | |||||
2049 | public function __isset($name) |
||||
2050 | { |
||||
2051 | if (in_array($name, static::$options)) { |
||||
2052 | $this->logDeprecation('Checking property Client::' . $name . ' is deprecated'); |
||||
2053 | return isset($this->$name); |
||||
2054 | } |
||||
2055 | |||||
2056 | switch ($name) { |
||||
2057 | case 'errno': |
||||
2058 | case 'errstr': |
||||
2059 | case 'method': |
||||
2060 | case 'server': |
||||
2061 | case 'port': |
||||
2062 | case 'path': |
||||
2063 | $this->logDeprecation('Checking property Client::' . $name . ' is deprecated'); |
||||
2064 | return isset($this->$name); |
||||
2065 | default: |
||||
2066 | return false; |
||||
2067 | } |
||||
2068 | } |
||||
2069 | |||||
2070 | public function __unset($name) |
||||
2071 | { |
||||
2072 | if (in_array($name, static::$options)) { |
||||
2073 | $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated'); |
||||
2074 | unset($this->$name); |
||||
2075 | return; |
||||
2076 | } |
||||
2077 | |||||
2078 | switch ($name) { |
||||
2079 | case 'errno': |
||||
2080 | case 'errstr': |
||||
2081 | case 'method': |
||||
2082 | case 'server': |
||||
2083 | case 'port': |
||||
2084 | case 'path': |
||||
2085 | $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated'); |
||||
2086 | unset($this->$name); |
||||
2087 | return; |
||||
2088 | default: |
||||
2089 | /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... |
||||
2090 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); |
||||
2091 | trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); |
||||
2092 | } |
||||
2093 | } |
||||
2094 | } |
||||
2095 |