From cc97bebe60c0dcbf90056892fd2153a574b23868 Mon Sep 17 00:00:00 2001 From: gggeek Date: Mon, 30 Jan 2023 15:24:22 +0000 Subject: [PATCH] add setOption/getOption and co to Client and Server --- NEWS.md | 4 +- src/Client.php | 385 +++++++++++++++++++++++++++++++++++++++++-------- src/Server.php | 118 +++++++++++++++ 3 files changed, 445 insertions(+), 62 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1107569a..ebcfc695 100644 --- a/NEWS.md +++ b/NEWS.md @@ -68,8 +68,8 @@ * new: method `PhpXmlRpc::useInteropFaults()` can be used to make the library change the error codes it generates to match the spec described at https://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php -* new: added the `Client::setTimeout` method, meant to replace usage of the `$timeout` argument in calls to `send` - and `multicall` +* new: added methods `getOption`, `setOption`, `setOptions` and `getOptions` to both Client and Server, meant to replace + direct access to _all public properties_ as well as the `$timeout` argument in calls to `Client::send` and `Client::multicall` * new: method `Client::getUrl()` diff --git a/src/Client.php b/src/Client.php index 396e0eb9..532c5eef 100644 --- a/src/Client.php +++ b/src/Client.php @@ -3,13 +3,12 @@ namespace PhpXmlRpc; //use PhpXmlRpc\Helper\Charset; +use PhpXmlRpc\Exception\ValueErrorException; use PhpXmlRpc\Helper\XMLParser; use PhpXmlRpc\Traits\LoggerAware; /** * Used to represent a client of an XML-RPC server. - * - * @todo add a setTimeout method, in the vein of other options which can be set to the Client */ class Client { @@ -19,6 +18,37 @@ class Client const USE_CURL_ALWAYS = 1; const USE_CURL_AUTO = 2; + const OPT_ACCEPTED_CHARSET_ENCODINGS = 'accepted_charset_encodings'; + const OPT_ACCEPTED_COMPRESSION = 'accepted_compression'; + const OPT_AUTH_TYPE = 'authtype'; + const OPT_CA_CERT = 'cacert'; + const OPT_CA_CERT_DIR = 'cacertdir'; + const OPT_CERT = 'cert'; + const OPT_CERT_PASS = 'certpass'; + const OPT_COOKIES = 'cookies'; + const OPT_DEBUG = 'debug'; + const OPT_EXTRA_CURL_OPTS = 'extracurlopts'; + const OPT_KEEPALIVE = 'keepalive'; + const OPT_KEY = 'key'; + const OPT_KEY_PASS = 'keypass'; + const OPT_NO_MULTICALL = 'no_multicall'; + const OPT_PASSWORD = 'password'; + const OPT_PROXY = 'proxy'; + const OPT_PROXY_AUTH_TYPE = 'proxy_authtype'; + const OPT_PROXY_PASS = 'proxy_pass'; + const OPT_PROXY_PORT = 'proxyport'; + const OPT_PROXY_USER = 'proxy_user'; + const OPT_REQUEST_CHARSET_ENCODING = 'request_charset_encoding'; + const OPT_REQUEST_COMPRESSION = 'request_compression'; + const OPT_RETURN_TYPE = 'return_type'; + const OPT_SSL_VERSION = 'sslversion'; + const OPT_TIMEOUT = 'timeout'; + const OPT_USERNAME = 'username'; + const OPT_USER_AGENT = 'user_agent'; + const OPT_USE_CURL = 'use_curl'; + const OPT_VERIFY_HOST = 'verifyhost'; + const OPT_VERIFY_PEER = 'verifypeer'; + /** @var string */ protected static $requestClass = '\\PhpXmlRpc\\Request'; /** @var string */ @@ -39,143 +69,135 @@ class Client /** * @var string - * @internal use getUrl + * @internal use getUrl/__construct */ public $method = 'http'; /** * @var string - * @internal use getUrl + * @internal use getUrl/__construct */ public $server; /** * @var int - * @internal use getUrl + * @internal use getUrl/__construct */ public $port = 0; /** * @var string - * @internal use getUrl + * @internal use getUrl/__construct */ public $path; /** * @var int - * @internal use setDebug + * @internal use setOption/getOption */ public $debug = 0; - /** * @var string - * @internal use setCredentials + * @internal use setCredentials/getOption */ public $username = ''; /** * @var string - * @internal use setCredentials + * @internal use setCredentials/getOption */ public $password = ''; /** * @var int - * @internal use setCredentials + * @internal use setCredentials/getOption */ public $authtype = 1; - /** * @var string - * @internal use setCertificate + * @internal use setCertificate/getOption */ public $cert = ''; /** * @var string - * @internal use setCertificate + * @internal use setCertificate/getOption */ public $certpass = ''; /** * @var string - * @internal use setCaCertificate + * @internal use setCaCertificate/getOption */ public $cacert = ''; /** * @var string - * @internal use setCaCertificate + * @internal use setCaCertificate/getOption */ public $cacertdir = ''; /** * @var string - * @internal use setKey + * @internal use setKey/getOption */ public $key = ''; /** * @var string - * @internal use setKey + * @internal use setKey/getOption */ public $keypass = ''; /** * @var bool - * @internal use setSSLVerifyPeer + * @internal use setOption/getOption */ public $verifypeer = true; /** * @var int - * @internal use setSSLVerifyHost + * @internal use setOption/getOption */ public $verifyhost = 2; /** * @var int - * @internal use setSSLVersion + * @internal use setOption/getOption */ public $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT - /** * @var string - * @internal use setProxy + * @internal use setProxy/getOption */ public $proxy = ''; /** * @var int - * @internal use setProxy + * @internal use setProxy/getOption */ public $proxyport = 0; /** * @var string - * @internal use setProxy + * @internal use setProxy/getOption */ public $proxy_user = ''; /** * @var string - * @internal use setProxy + * @internal use setProxy/getOption */ public $proxy_pass = ''; /** * @var int - * @internal use setProxy + * @internal use setProxy/getOption */ public $proxy_authtype = 1; - /** * @var array - * @internal use setCookie + * @internal use setCookie/getOption */ public $cookies = array(); - /** * @var array - * @internal use setCurlOptions + * @internal use setOption/getOption */ public $extracurlopts = array(); - /** * @var int - * @internal use setTimeout + * @internal use setOption/getOption */ public $timeout = 0; - /** * @var int - * @internal use setUseCurl + * @internal use setOption/getOption */ public $use_curl = self::USE_CURL_AUTO; - /** * @var bool * @@ -183,9 +205,10 @@ class Client * to dispatch to the server an array of requests in a single http roundtrip or simply execute many consecutive http * calls. Defaults to FALSE, but it will be enabled automatically on the first failure of execution of * system.multicall. + * + * @internal use setOption/getOption */ public $no_multicall = false; - /** * @var array * @@ -196,34 +219,34 @@ class Client * decide the compression methods it supports. You might check for the presence of 'zlib' in the output of * curl_version() to determine whether compression is supported or not * - * @internal use setAcceptedCompression + * @internal use setAcceptedCompression/getOption */ public $accepted_compression = array(); - /** * @var string|null * * Name of compression scheme to be used for sending requests. * Either null, 'gzip' or 'deflate'. * - * @internal use setRequestCompression + * @internal use setOption/getOption */ public $request_compression = ''; - /** * @var bool * - * Whether to use persistent connections for http 1.1 and https. Value set at constructor time + * Whether to use persistent connections for http 1.1 and https. Value set at constructor time. + * + * @internal use setOption/getOption */ public $keepalive = false; - /** * @var string[] * * Charset encodings that can be decoded without problems by the client. Value set at constructor time + * + * @internal use setOption/getOption */ public $accepted_charset_encodings = array(); - /** * @var string * @@ -233,9 +256,10 @@ class Client * in the transfer, a CR-LF will be preserved as well as a singe LF). * Valid values are 'US-ASCII', 'UTF-8' and 'ISO-8859-1'. * For the fastest mode of operation, set your both your app internal encoding and this to UTF-8. + * + * @internal use setOption/getOption */ public $request_charset_encoding = ''; - /** * @var string * @@ -250,15 +274,16 @@ class Client * Note that the 'phpvals' setting will yield faster execution times, but some of the information from the original * response will be lost. It will be e.g. impossible to tell whether a particular php string value was sent by the * server as an xml-rpc string or base64 value. + * + * @internal use setOption/getOption */ public $return_type = XMLParser::RETURN_XMLRPCVALS; - /** * @var string * * Sent to servers in http headers. Value set at constructor time. * - * @internal use setUserAgent + * @internal use setOption/getOption */ public $user_agent; @@ -268,6 +293,42 @@ class Client */ public $xmlrpc_curl_handle = null; + /** + * @var array + */ + protected $options = array( + self::OPT_ACCEPTED_CHARSET_ENCODINGS, + self::OPT_ACCEPTED_COMPRESSION, + self::OPT_AUTH_TYPE, + self::OPT_CA_CERT, + self::OPT_CA_CERT_DIR, + self::OPT_CERT, + self::OPT_CERT_PASS, + self::OPT_COOKIES, + self::OPT_DEBUG, + self::OPT_EXTRA_CURL_OPTS, + self::OPT_KEEPALIVE, + self::OPT_KEY, + self::OPT_KEY_PASS, + self::OPT_NO_MULTICALL, + self::OPT_PASSWORD, + self::OPT_PROXY, + self::OPT_PROXY_AUTH_TYPE, + self::OPT_PROXY_PASS, + self::OPT_PROXY_USER, + self::OPT_PROXY_PORT, + self::OPT_REQUEST_CHARSET_ENCODING, + self::OPT_REQUEST_COMPRESSION, + self::OPT_RETURN_TYPE, + self::OPT_SSL_VERSION, + self::OPT_TIMEOUT, + self::OPT_USE_CURL, + self::OPT_USER_AGENT, + self::OPT_USERNAME, + self::OPT_VERIFY_HOST, + self::OPT_VERIFY_PEER, + ); + /** * @param string $path either the PATH part of the xml-rpc server URL, or complete server URL (in which case you * should use and empty string for all other parameters) @@ -347,6 +408,212 @@ class Client $this->user_agent = PhpXmlRpc::$xmlrpcName . ' ' . PhpXmlRpc::$xmlrpcVersion; } + /** + * @param string $name + * @param mixed $value + * @return $this + * @throws ValueErrorException on unsupported option + */ + public function setOption($name, $value) + { + switch ($name) { + case self::OPT_ACCEPTED_CHARSET_ENCODINGS: + $this->accepted_charset_encodings = $value; + break; + case self::OPT_ACCEPTED_COMPRESSION: + $this->accepted_compression = $value; + break; + case self::OPT_AUTH_TYPE: + $this->authtype = $value; + break; + case self::OPT_CA_CERT: + $this->cacert = $value; + break; + case self::OPT_CA_CERT_DIR: + $this->cacertdir = $value; + break; + case self::OPT_CERT: + $this->cert = $value; + break; + case self::OPT_CERT_PASS: + $this->certpass = $value; + break; + case self::OPT_COOKIES: + $this->cookies = $value; + break; + case self::OPT_DEBUG: + $this->debug = $value; + break; + case self::OPT_EXTRA_CURL_OPTS: + $this->extracurlopts = $value; + break; + case self::OPT_KEEPALIVE: + $this->keepalive = $value; + break; + case self::OPT_KEY: + $this->key = $value; + break; + case self::OPT_KEY_PASS: + $this->keypass = $value; + break; + case self::OPT_NO_MULTICALL: + $this->no_multicall = $value; + break; + case self::OPT_PASSWORD: + $this->password = $value; + break; + case self::OPT_PROXY: + $this->proxy = $value; + break; + case self::OPT_PROXY_AUTH_TYPE: + $this->proxy_authtype = $value; + break; + case self::OPT_PROXY_PASS: + $this->proxy_pass = $value; + break; + case self::OPT_PROXY_PORT: + $this->proxyport = $value; + break; + case self::OPT_PROXY_USER: + $this->proxy_user = $value; + break; + case self::OPT_REQUEST_CHARSET_ENCODING: + $this->request_charset_encoding = $value; + break; + case self::OPT_REQUEST_COMPRESSION: + $this->request_compression = $value; + break; + case self::OPT_RETURN_TYPE: + $this->return_type = $value; + break; + case self::OPT_SSL_VERSION: + $this->sslversion = $value; + break; + case self::OPT_TIMEOUT: + $this->timeout = $value; + break; + case self::OPT_USERNAME: + $this->username = $value; + break; + case self::OPT_USER_AGENT: + $this->user_agent = $value; + break; + case self::OPT_USE_CURL: + $this->use_curl = $value; + break; + case self::OPT_VERIFY_HOST: + $this->verifyhost = $value; + break; + case self::OPT_VERIFY_PEER: + $this->verifypeer = $value; + break; + default: + throw new ValueErrorException("Unsupported option '$name'"); + } + + return $this; + } + + /** + * @param string $name + * @return mixed + * @throws ValueErrorException on unsupported option + */ + public function getOption($name) + { + switch ($name) { + case self::OPT_ACCEPTED_CHARSET_ENCODINGS: + return $this->accepted_charset_encodings; + case self::OPT_ACCEPTED_COMPRESSION: + return $this->accepted_compression; + case self::OPT_AUTH_TYPE: + return $this->authtype; + case self::OPT_CA_CERT: + return $this->cacert; + case self::OPT_CA_CERT_DIR: + return $this->cacertdir; + case self::OPT_CERT: + return $this->cert; + case self::OPT_CERT_PASS: + return $this->certpass; + case self::OPT_COOKIES: + return $this->cookies; + case self::OPT_DEBUG: + return $this->debug; + case self::OPT_EXTRA_CURL_OPTS: + return $this->extracurlopts; + case self::OPT_KEEPALIVE: + return $this->keepalive; + case self::OPT_KEY: + return $this->key; + case self::OPT_KEY_PASS: + return $this->keypass; + case self::OPT_NO_MULTICALL: + return $this->no_multicall; + case self::OPT_PASSWORD: + return $this->password; + case self::OPT_PROXY: + return $this->proxy; + case self::OPT_PROXY_AUTH_TYPE: + return $this->proxy_authtype; + case self::OPT_PROXY_PASS: + return $this->proxy_pass; + case self::OPT_PROXY_PORT: + return $this->proxyport; + case self::OPT_PROXY_USER: + return $this->proxy_user; + case self::OPT_REQUEST_CHARSET_ENCODING: + return $this->request_charset_encoding; + case self::OPT_REQUEST_COMPRESSION: + return $this->request_compression; + case self::OPT_RETURN_TYPE: + return $this->return_type; + case self::OPT_SSL_VERSION: + return $this->sslversion; + case self::OPT_TIMEOUT: + return $this->timeout; + case self::OPT_USERNAME: + return $this->username; + case self::OPT_USER_AGENT: + return $this->user_agent; + case self::OPT_USE_CURL: + return $this->use_curl; + case self::OPT_VERIFY_HOST: + return $this->verifyhost; + case self::OPT_VERIFY_PEER: + return $this->verifypeer; + default: + throw new ValueErrorException("Unsupported option '$name'"); + } + } + + /** + * Returns the complete list of Client options. + * @return array + */ + public function getOptions() + { + $values = array(); + foreach($this->options as $opt) { + $values[$opt] = $this->getOption($opt); + } + return $values; + } + + /** + * @param array $options + * @return $this + * @throws ValueErrorException on unsupported option + */ + public function setOptions($options) + { + foreach($options as $name => $value) { + $this->setOption($name, $value); + } + + return $this; + } + /** * Enable/disable the echoing to screen of the xml-rpc responses received. The default is not to output anything. * @@ -362,6 +629,7 @@ class Client * * @param integer $level values -1, 0, 1 and 2 are supported * @return $this + * @deprecated use setOption */ public function setDebug($level) { @@ -455,6 +723,7 @@ class Client * * @param bool $i enable/disable verification of peer certificate * @return $this + * @deprecated use setOption */ public function setSSLVerifyPeer($i) { @@ -469,6 +738,7 @@ class Client * * @param int $i Set to 1 to only the existence of a CN, not that it matches * @return $this + * @deprecated use setOption */ public function setSSLVerifyHost($i) { @@ -481,6 +751,7 @@ class Client * * @param int $i * @return $this + * @deprecated use setOption */ public function setSSLVersion($i) { @@ -543,6 +814,7 @@ class Client * * @param string $compMethod either 'gzip', 'deflate' or '' * @return $this + * @deprecated use setOption */ public function setRequestCompression($compMethod) { @@ -591,6 +863,7 @@ class Client * * @param array $options * @return $this + * @deprecated use setOption */ public function setCurlOptions($options) { @@ -601,6 +874,7 @@ class Client /** * @param int $useCurlMode self::USE_CURL_ALWAYS, self::USE_CURL_AUTO or self::USE_CURL_NEVER * @return $this + * @deprecated use setOption */ public function setUseCurl($useCurlMode) { @@ -616,6 +890,7 @@ class Client * * @param string $agentString * @return $this + * @deprecated use setOption */ public function setUserAgent($agentString) { @@ -623,16 +898,6 @@ class Client return $this; } - /** - * @param int $timeout - * @return $this - */ - public function setTimeout($timeout) - { - $this->timeout = $timeout; - return $this; - } - /** * @return string */ @@ -663,7 +928,7 @@ class Client * containing the complete xml representation of the request. It is e.g. useful * when, for maximal speed of execution, the request is serialized into a * string using the native php xml-rpc functions (see http://www.php.net/xmlrpc) - * @param integer $timeout deprecated. Connection timeout, in seconds, If unspecified, the timeout set with setTimeout + * @param integer $timeout deprecated. Connection timeout, in seconds, If unspecified, the timeout set with setOption * will be used. If that is 0, a platform specific timeout will apply. * This timeout value is passed to fsockopen(). It is also used for detecting server * timeouts during communication (i.e. if the server does not send anything to the client @@ -702,7 +967,7 @@ class Client return $r; } elseif (is_string($req)) { - $n = new static::$requestClass(''); + $n = new static::$requestClass(''); $n->payload = $req; $req = $n; } @@ -933,7 +1198,7 @@ class Client $uri = $this->path; } - // Cookie generation, as per rfc2965 (version 1 cookies) or netscape's rules (version 0 cookies) + // Cookie generation, as per rfc2965 $cookieHeader = ''; if (count($this->cookies)) { $version = ''; diff --git a/src/Server.php b/src/Server.php index e10210aa..db590bc5 100644 --- a/src/Server.php +++ b/src/Server.php @@ -3,6 +3,7 @@ namespace PhpXmlRpc; use PhpXmlRpc\Exception\NoSuchMethodException; +use PhpXmlRpc\Exception\ValueErrorException; use PhpXmlRpc\Helper\Http; use PhpXmlRpc\Helper\Interop; use PhpXmlRpc\Helper\Logger; @@ -20,6 +21,15 @@ class Server use LoggerAware; use ParserAware; + const OPT_ACCEPTED_COMPRESSION = 'accepted_compression'; + const OPT_ALLOW_SYSTEM_FUNCS = 'allow_system_funcs'; + const OPT_COMPRESS_RESPONSE = 'compress_response'; + const OPT_DEBUG = 'debug'; + const OPT_EXCEPTION_HANDLING = 'exception_handling'; + const OPT_FUNCTIONS_PARAMETERS_TYPE = 'functions_parameters_type'; + const OPT_PHPVALS_ENCODING_OPTIONS = 'phpvals_encoding_options'; + const OPT_RESPONSE_CHARSET_ENCODING = 'response_charset_encoding'; + /** * @var string * Defines how functions in $dmap will be invoked: either using an xml-rpc Request object or plain php values. @@ -113,6 +123,17 @@ class Server */ protected $dmap = array(); + protected $options = array( + self::OPT_ACCEPTED_COMPRESSION, + self::OPT_ALLOW_SYSTEM_FUNCS, + self::OPT_COMPRESS_RESPONSE, + self::OPT_DEBUG, + self::OPT_EXCEPTION_HANDLING, + self::OPT_FUNCTIONS_PARAMETERS_TYPE, + self::OPT_PHPVALS_ENCODING_OPTIONS, + self::OPT_RESPONSE_CHARSET_ENCODING, + ); + /** * Storage for internal debug info. */ @@ -163,6 +184,102 @@ class Server } } + /** + * @param string $name + * @param mixed $value + * @return $this + * @throws ValueErrorException on unsupported option + */ + public function setOption($name, $value) + { + switch ($name) { + case self::OPT_ACCEPTED_COMPRESSION : + $this->accepted_charset_encodings = $value; + break; + case self::OPT_ALLOW_SYSTEM_FUNCS: + $this->allow_system_funcs = $value; + break; + case self::OPT_COMPRESS_RESPONSE: + $this->compress_response = $value; + break; + case self::OPT_DEBUG: + $this->debug = $value; + break; + case self::OPT_EXCEPTION_HANDLING: + $this->exception_handling = $value; + break; + case self::OPT_FUNCTIONS_PARAMETERS_TYPE: + $this->functions_parameters_type = $value; + break; + case self::OPT_PHPVALS_ENCODING_OPTIONS: + $this->phpvals_encoding_options = $value; + break; + case self::OPT_RESPONSE_CHARSET_ENCODING: + $this->response_charset_encoding = $value; + break; + default: + throw new ValueErrorException("Unsupported option '$name'"); + } + + return $this; + } + + /** + * @param string $name + * @return mixed + * @throws ValueErrorException on unsupported option + */ + public function getOption($name) + { + switch ($name) { + case self::OPT_ACCEPTED_COMPRESSION: + return $this->accepted_compression; + case self::OPT_ALLOW_SYSTEM_FUNCS: + return $this->allow_system_funcs; + case self::OPT_COMPRESS_RESPONSE: + return $this->compress_response; + case self::OPT_DEBUG: + return $this->debug; + case self::OPT_EXCEPTION_HANDLING: + return $this->exception_handling; + case self::OPT_FUNCTIONS_PARAMETERS_TYPE: + return $this->functions_parameters_type; + case self::OPT_PHPVALS_ENCODING_OPTIONS: + return $this->phpvals_encoding_options; + case self::OPT_RESPONSE_CHARSET_ENCODING: + return $this->response_charset_encoding; + default: + throw new ValueErrorException("Unsupported option '$name'"); + } + } + + /** + * Returns the complete list of Client options. + * @return array + */ + public function getOptions() + { + $values = array(); + foreach($this->options as $opt) { + $values[$opt] = $this->getOption($opt); + } + return $values; + } + + /** + * @param array $options + * @return $this + * @throws ValueErrorException on unsupported option + */ + public function setOptions($options) + { + foreach($options as $name => $value) { + $this->setOption($name, $value); + } + + return $this; + } + /** * Set debug level of server. * @@ -177,6 +294,7 @@ class Server * execution anymore, but just end up logged in the xml-rpc response) * Note that info added at level 2 and 3 will be base64 encoded * @return $this + * @deprecated use setOption */ public function setDebug($level) { -- 2.47.0