From 156e42912aa763fdaf0a58b62ecb8e9d2b11d06c Mon Sep 17 00:00:00 2001 From: gggeek Date: Sat, 4 Feb 2023 11:13:41 +0000 Subject: [PATCH] make all (most?) object propeties and add compatibility accessors --- NEWS.md | 26 +-- doc/api_changes_v4.10.md | 194 +++++++++++++++++++ lib/xmlrpcs.inc | 7 +- src/Client.php | 354 +++++++++++++++-------------------- src/Helper/XMLParser.php | 32 +++- src/PhpXmlRpc.php | 28 +-- src/Request.php | 96 +++++++++- src/Response.php | 63 +++++-- src/Server.php | 161 +++++++++++----- src/Traits/PayloadBearer.php | 4 +- src/Value.php | 75 +++++++- 11 files changed, 739 insertions(+), 301 deletions(-) create mode 100644 doc/api_changes_v4.10.md diff --git a/NEWS.md b/NEWS.md index 7dd7bd36..e2efc990 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,12 @@ * changed: dropped support for parsing cookie headers which follow the obsolete Cookie2 specification +* new: it is now possible to make the library generate warning messages whenever a deprecated feature is used, such as + calling deprecated methods, using deprecated method parameters, or reading/writing deprecated object properties. + This is disabled by default, and can be enabled by setting `PhpXmlRpc\PhpXmlRpc::xmlrpc_silence_deprecations = false`. + Note that the deprecation warnings will be by default added to the php error log, and not be displayed on screen. + If you prefer them to be handled in some other way, you should take over the Logger, as described below here + * new: allow to specify other charsets than the canonical three (UTF-8, ISO-8859-1, ASCII), when mbstring is available, both for outgoing and incoming data (issue #42). @@ -54,6 +60,8 @@ a method handler in the dispatch was defined with `'parameters_type' = 'phpvals'`, the handler would be passed a Request object instead of plain php values. +* fixed: made sure all debug output goes through the logger at response parsing time (there was one printf call left) + * fixed: when calling `Client::multicall()` with `$client->return_type = 'xml'`, the code would be always falling back to non-multicall requests @@ -81,12 +89,6 @@ * 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: it is now possible to make the library generate warning messages whenever a deprecated feature is used, such as - calling deprecated methods, using deprecated method parameters, or reading/writing deprecated object properties. - This is disabled by default, and can be enabled by setting `PhpXmlRpc\PhpXmlRpc::xmlrpc_silence_deprecations = false`. - Note that the deprecation warnings will be by default added to the php error log, and not be displayed on screen. - If you prefer them to be handled in some other way, you should take over the Logger, as described just below here - * new: it is now possible to inject a custom logger into helper classes `Charset`, `Http`, `XMLParser`, inching a step closer to supporting DIC patterns (issue #78) @@ -94,8 +96,6 @@ * improved: the `Logger` class now sports methods adhering to Psr\Log\LoggerInterface -* improved: made sure all debug output goes through the logger at response parsing time (there was one printf call left) - * improved: limit the size of incoming data which will be used in error responses and logged error messages, making it slightly harder to carry out DOS attacks against the library @@ -146,9 +146,12 @@ * improved: made sure the test container and gha test runners have at least one locale with comma as decimal separator -* BC notes (besides what can be inferred from the changes listed above): +* BC notes: + + *NB* Given the considerable amount of API changes in this release, a set of tables listing every change has been + added in doc/api_changes_v4.10.md; a textual description follows. - for library users + Besides what can be inferred from the changes listed above, for library users: - the data passed to the application is not encoded anymore in UTF-8 when setting `PhpXmlRpc::$internal_encoding` to a custom character set and the mbstring extension is enabled. It will be encoded instead in the specified character @@ -172,7 +175,7 @@ - the code generated by the debugger when using "Generate stub for method call" will throw on errors instead of returning a Response object - for library extenders + For library extenders: - the `$options` argument passed to `XMLParser::parse` will now contain both options intended to be passed down to the php xml parser, and further options used to tweak the parsing results. If you have subclassed `XMLParser` @@ -196,6 +199,7 @@ - new methods in helper classes: `Charset::knownCharsets`, `Http::parseAcceptHeader`, `XMLParser::truncateValueForLog` - exception `\PhpXmlRpc\Exception\PhpXmlRpcException` is deprecated. Use `\PhpXmlRpc\Exception` instead + ## XML-RPC for PHP version 4.9.5 - 2023/01/11 * improved: revised all demo files. Showcase more features in client demos; isolate better testsuite functions in diff --git a/doc/api_changes_v4.10.md b/doc/api_changes_v4.10.md new file mode 100644 index 00000000..8264e6c7 --- /dev/null +++ b/doc/api_changes_v4.10.md @@ -0,0 +1,194 @@ +API Changes between library versions 4.9 and 4.10 +================================================= + +While 4.10 keeps the usual BC promise with previous 4.x releases, it also paves the way for all the API changes foreseen +to happen in future version 5. + +In particular, API cleanups mean that most public access to object properties has been replaced by dedicated methods. + +New classes, traits, exceptions +------------------------------- + +For the first time, usage of custom exceptions is in place. Traits are also in use for sharing common functionality. + +| Type | Name | Notes | +|-----------|-------------------------------|---------------------------------------------------------------------| +| exception | PhpXmlRpc\Exception | Parent class for all exceptions thrown by the library. | +| | | Its alias PhpXmlRpc\Exception\PhpXmlRpcException is still in place. | +| exception | PhpXmlRpc\Exception\... | See the list in the appendix of the user manual | +| trait | PhpXmlRpc\CharsetEncoderAware | | +| trait | PhpXmlRpc\Server | | +| trait | PhpXmlRpc\DeprecationLogger | | +| trait | PhpXmlRpc\ParserAware | | +| trait | PhpXmlRpc\PayloadBearer | | + +New class methods +----------------- + +In case you had extended the classes of the library and added methods to the subclasses, you might find that your +implementation clashes with the new one if you implemented: + +| Class | Method | Notes | +|-----------|---------------------|-----------| +| * | __get | | +| * | __isset | | +| * | __set | | +| * | __unset | | +| Charset | getLogger | | +| Charset | knownCharsets | | +| Charset | setLogger | static | +| Client | getOption | | +| Client | getOptions | | +| Client | getUrl | | +| Client | setOption | | +| Client | setOptions | | +| Http | getLogger | | +| Http | parseAcceptHeader | | +| Http | setLogger | static | +| Logger | debug | | +| Logger | error | | +| Logger | warning | | +| PhpXmlRpc | setLogger | static | +| PhpXmlRpc | useInteropFaults | static | +| Request | getContentType | | +| Request | getPayload | | +| Response | getContentType | | +| Response | getPayload | | +| Response | valueType | | +| Response | xml_header | | +| Server | getOption | | +| Server | getOptions | | +| Server | setDispatchMap | | +| Server | setOption | | +| Server | setOptions | | +| Wrapper | getHeldObject | | +| Wrapper | holdObject | | +| XMLParser | getLogger | | +| XMLParser | setLogger | static | +| XMLParser | truncateValueForLog | protected | + +New class properties +-------------------- + +| Class | Property | Default value | Notes | +|-----------|----------|---------------|-----------| +| Client | $timeout | 0 | protected | + +New static properties +--------------------- + +| Class | Property | Default value | Notes | +|-----------|-------------------------------|---------------------|-----------| +| Client | $options | see code | protected | +| Client | $requestClass | \PhpXmlRpc\Request | protected | +| Client | $responseClass | \PhpXmlRpc\Response | protected | +| PhpXmlRpc | $xmlrpc_datetime_format | see code | | +| PhpXmlRpc | $xmlrpc_double_format | see code | | +| PhpXmlRpc | $xmlrpc_int_format | see code | | +| PhpXmlRpc | $xmlrpc_methodname_format | see code | | +| PhpXmlRpc | $xmlrpc_reject_invalid_values | false | | +| PhpXmlRpc | $xmlrpc_return_datetimes | false | | +| PhpXmlRpc | $xmlrpc_silence_deprecations | true | | + +New constants +------------- + +| Class | Constant | Notes | +|--------|----------|-----------------------| +| Client | OPT_* | see code for the list | +| Server | OPT_* | see code for the list | + +Changed methods +--------------- + +The following methods acquired new parameters, or accept a wider range of values for existing parameters + +| Class | Method | Notes | +|-----------|----------|-------| +| PhpXmlRpc | $xmlrpc_ | | + +Deprecated methods +--------------------- + +| Class | Method | Replacement | +|---------|-----------------------|----------------------| +| Charset | isValidCharset | - | +| Client | prepareCurlHandle | createCURLHandle | +| Client | sendPayloadCurl | sendViaCURL | +| Client | sendPayloadSocket | sendViaSocket | +| Client | setCurlOptions | setOption | +| Client | setRequestCompression | setOption | +| Client | setSSLVerifyHost | setOption | +| Client | setSSLVerifyPeer | setOption | +| Client | setSSLVersion | setOption | +| Client | setUseCurl | setOption | +| Client | setUserAgent | setOption | +| Server | xml_header | Response::xml_header | +| Value | serializeData | - | + +Deprecated properties +--------------------- + +The following properties have now protected access. Replacement accessor for public use are listed. + +| Class | Property | Read via | Write via | +|----------|----------------------------|------------------------|----------------------------------| +| Client | accepted_charset_encodings | getOption | setOption | +| Client | accepted_compression | getOption | setOption/setAcceptedCompression | +| Client | authtype | getOption | setOption/setCredentials | +| Client | cacert | getOption | setOption/setCaCertificate | +| Client | cacertdir | getOption | setOption/setCaCertificate | +| Client | cert | getOption | setOption/setCertificate | +| Client | certpass | getOption | setOption/setCertificate | +| Client | cookies | getOption | setOption | +| Client | debug | getOption | setOption/setDebug | +| Client | errno | - | - | +| Client | errstr | - | - | +| Client | extracurlopts | getOption | setOption | +| Client | keepalive | getOption | setOption | +| Client | key | getOption | setOption/setKey | +| Client | keypass | getOption | setOption/setKey | +| Client | method | getUrl | __construct | +| Client | no_multicall | getOption | setOption | +| Client | password | getOption | setOption/setCredentials | +| Client | path | getUrl | __construct | +| Client | port | getUrl | __construct | +| Client | proxy | getOption | setOption/setProxy | +| Client | proxy_authtype | getOption | setOption/setProxy | +| Client | proxy_pass | getOption | setOption/setProxy | +| Client | proxy_user | getOption | setOption/setProxy | +| Client | proxyport | getOption | setOption/setProxy | +| Client | request_charset_encoding | getOption | setOption | +| Client | request_compression | getOption | setOption | +| Client | return_type | getOption | setOption | +| Client | server | getUrl | __construct | +| Client | sslversion | getOption | setOption | +| Client | use_curl | getOption | setOption | +| Client | user_agent | getOption | setOption | +| Client | username | getOption | setOption/setCredentials | +| Client | verifyhost | getOption | setOption | +| Client | verifypeer | getOption | setOption | +| Request | content_type | getContentType | setPayload | +| Request | debug | setDebug | - | +| Request | methodname | method | __construct/method | +| Request | params | getParam | __construct/addParam | +| Request | payload | getPayload | setPayload | +| Response | val | value | __construct | +| Response | valtyp | valueType | __construct | +| Response | errno | faultCode | __construct | +| Response | errstr | faultString | __construct | +| Response | content_type | getContentType | setPayload | +| Response | payload | getPayload | setPayload | +| Server | accepted_charset_encodings | - | - | +| Server | accepted_compression | getOption | setOption | +| Server | allow_system_funcs | getOption | setOption | +| Server | compress_response | getOption | setOption | +| Server | debug | getOption | setOption/setDebug | +| Server | exception_handling | getOption | setOption | +| Server | functions_parameters_type | getOption | setOption | +| Server | phpvals_encoding_options | getOption | setOption | +| Server | response_charset_encoding | getOption | setOption | +| Value | _php_class | - | - | +| Value | me | scalarVal/array access | __construct | +| Value | mytype | kindOf | __construct | +| Wrapper | $objectholder | getHeldObject | holdObject | diff --git a/lib/xmlrpcs.inc b/lib/xmlrpcs.inc index 77abb79c..cf5a88bf 100644 --- a/lib/xmlrpcs.inc +++ b/lib/xmlrpcs.inc @@ -69,10 +69,7 @@ class xmlrpc_server extends Server case 'dmap': return $this->dmap; default: - $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . - $trace[0]['line'], E_USER_NOTICE); - return null; + return parent::__get($name); } } @@ -82,7 +79,7 @@ class xmlrpc_server extends Server */ public function __isset($name) { - return $name === 'dmap'; + return $name === 'dmap' ? true : parent::__isset($name); } /// @todo what about __set, __unset? diff --git a/src/Client.php b/src/Client.php index 9fa488e0..076cdceb 100644 --- a/src/Client.php +++ b/src/Client.php @@ -2,17 +2,25 @@ namespace PhpXmlRpc; -//use PhpXmlRpc\Helper\Charset; use PhpXmlRpc\Exception\ValueErrorException; use PhpXmlRpc\Helper\XMLParser; +use PhpXmlRpc\Traits\CharsetEncoderAware; use PhpXmlRpc\Traits\DeprecationLogger; /** * Used to represent a client of an XML-RPC server. + * + * @property int $errno deprecated - public access left in purely for BC. + * @property string $errstr deprecated - public access left in purely for BC. + * @property string $method deprecated - public access left in purely for BC. Access via getUrl()/__construct() + * @property string $server deprecated - public access left in purely for BC. Access via getUrl()/__construct() + * @property int $port deprecated - public access left in purely for BC. Access via getUrl()/__construct() + * @property string $path deprecated - public access left in purely for BC. Access via getUrl()/__construct() */ class Client { use DeprecationLogger; + //use CharsetEncoderAware; const USE_CURL_NEVER = 0; const USE_CURL_ALWAYS = 1; @@ -58,12 +66,12 @@ class Client * @var int * @deprecated will be removed in the future */ - public $errno; + protected $errno; /** * @var string * @deprecated will be removed in the future */ - public $errstr; + protected $errstr; /// @todo: do all the ones below need to be public? @@ -71,133 +79,133 @@ class Client * @var string * @internal use getUrl/__construct */ - public $method = 'http'; + protected $method = 'http'; /** * @var string * @internal use getUrl/__construct */ - public $server; + protected $server; /** * @var int * @internal use getUrl/__construct */ - public $port = 0; + protected $port = 0; /** * @var string * @internal use getUrl/__construct */ - public $path; + protected $path; /** * @var int * @internal use setOption/getOption */ - public $debug = 0; + protected $debug = 0; /** * @var string * @internal use setCredentials/getOption */ - public $username = ''; + protected $username = ''; /** * @var string * @internal use setCredentials/getOption */ - public $password = ''; + protected $password = ''; /** * @var int * @internal use setCredentials/getOption */ - public $authtype = 1; + protected $authtype = 1; /** * @var string * @internal use setCertificate/getOption */ - public $cert = ''; + protected $cert = ''; /** * @var string * @internal use setCertificate/getOption */ - public $certpass = ''; + protected $certpass = ''; /** * @var string * @internal use setCaCertificate/getOption */ - public $cacert = ''; + protected $cacert = ''; /** * @var string * @internal use setCaCertificate/getOption */ - public $cacertdir = ''; + protected $cacertdir = ''; /** * @var string * @internal use setKey/getOption */ - public $key = ''; + protected $key = ''; /** * @var string * @internal use setKey/getOption */ - public $keypass = ''; + protected $keypass = ''; /** * @var bool * @internal use setOption/getOption */ - public $verifypeer = true; + protected $verifypeer = true; /** * @var int * @internal use setOption/getOption */ - public $verifyhost = 2; + protected $verifyhost = 2; /** * @var int * @internal use setOption/getOption */ - public $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT + protected $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT /** * @var string * @internal use setProxy/getOption */ - public $proxy = ''; + protected $proxy = ''; /** * @var int * @internal use setProxy/getOption */ - public $proxyport = 0; + protected $proxyport = 0; /** * @var string * @internal use setProxy/getOption */ - public $proxy_user = ''; + protected $proxy_user = ''; /** * @var string * @internal use setProxy/getOption */ - public $proxy_pass = ''; + protected $proxy_pass = ''; /** * @var int * @internal use setProxy/getOption */ - public $proxy_authtype = 1; + protected $proxy_authtype = 1; /** * @var array * @internal use setCookie/getOption */ - public $cookies = array(); + protected $cookies = array(); /** * @var array * @internal use setOption/getOption */ - public $extracurlopts = array(); + protected $extracurlopts = array(); /** * @var int * @internal use setOption/getOption */ - public $timeout = 0; + protected $timeout = 0; /** * @var int * @internal use setOption/getOption */ - public $use_curl = self::USE_CURL_AUTO; + protected $use_curl = self::USE_CURL_AUTO; /** * @var bool * @@ -208,7 +216,7 @@ class Client * * @internal use setOption/getOption */ - public $no_multicall = false; + protected $no_multicall = false; /** * @var array * @@ -221,7 +229,7 @@ class Client * * @internal use setAcceptedCompression/getOption */ - public $accepted_compression = array(); + protected $accepted_compression = array(); /** * @var string|null * @@ -230,7 +238,7 @@ class Client * * @internal use setOption/getOption */ - public $request_compression = ''; + protected $request_compression = ''; /** * @var bool * @@ -238,7 +246,7 @@ class Client * * @internal use setOption/getOption */ - public $keepalive = false; + protected $keepalive = false; /** * @var string[] * @@ -246,7 +254,7 @@ class Client * * @internal use setOption/getOption */ - public $accepted_charset_encodings = array(); + protected $accepted_charset_encodings = array(); /** * @var string * @@ -259,7 +267,7 @@ class Client * * @internal use setOption/getOption */ - public $request_charset_encoding = ''; + protected $request_charset_encoding = ''; /** * @var string * @@ -277,7 +285,7 @@ class Client * * @internal use setOption/getOption */ - public $return_type = XMLParser::RETURN_XMLRPCVALS; + protected $return_type = XMLParser::RETURN_XMLRPCVALS; /** * @var string * @@ -285,7 +293,7 @@ class Client * * @internal use setOption/getOption */ - public $user_agent; + protected $user_agent; /** * CURL handle: used for keep-alive @@ -296,7 +304,7 @@ class Client /** * @var array */ - protected $options = array( + protected static $options = array( self::OPT_ACCEPTED_CHARSET_ENCODINGS, self::OPT_ACCEPTED_COMPRESSION, self::OPT_AUTH_TYPE, @@ -401,7 +409,7 @@ class Client $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); // NB: this is disabled to avoid making all the requests sent huge... mbstring supports more than 80 charsets! - //$ch = Charset::instance(); + //$ch = $this->getCharsetEncoder(); //$this->accepted_charset_encodings = $ch->knownCharsets(); // initialize user_agent string @@ -416,102 +424,12 @@ class Client */ 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'"); + if (in_array($name, static::$options)) { + $this->$name = $value; + return $this; } - return $this; + throw new ValueErrorException("Unsupported option '$name'"); } /** @@ -521,70 +439,11 @@ class Client */ 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'"); + if (in_array($name, static::$options)) { + return $this->$name; } + + throw new ValueErrorException("Unsupported option '$name'"); } /** @@ -594,7 +453,7 @@ class Client public function getOptions() { $values = array(); - foreach ($this->options as $opt) { + foreach (static::$options as $opt) { $values[$opt] = $this->getOption($opt); } return $values; @@ -1349,7 +1208,7 @@ class Client * @param array $opts the keys/values match self::getOptions * @return \CurlHandle|resource|false */ - protected function createCurlHandle($req, $method, $server, $port, $path, $opts) + protected function createCURLHandle($req, $method, $server, $port, $path, $opts) { if ($port == 0) { if (in_array($method, array('http', 'http10', 'http11', 'h2c'))) { @@ -2018,7 +1877,7 @@ class Client { $this->logDeprecationUnlessCalledBy('sendViaCURL'); - return $this->createCurlHandle($req, $method, $server, $port, $this->path, array( + return $this->createCURLHandle($req, $method, $server, $port, $this->path, array( 'accepted_charset_encodings' => $this->accepted_charset_encodings, 'accepted_compression' => $this->accepted_compression, 'authtype' => $authType, @@ -2051,4 +1910,101 @@ class Client 'verifypeer' => $this->verifypeer, )); } + + // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];` + public function &__get($name) + { + if (in_array($name, static::$options)) { + $this->logDeprecation('Getting property Client::' . $name . ' is deprecated'); + return $this->$name; + } + + switch ($name) { + case 'errno': + case 'errstr': + case 'method': + case 'server': + case 'port': + case 'path': + $this->logDeprecation('Getting property Client::' . $name . ' is deprecated'); + return $this->$name; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + $result = null; + return $result; + } + } + + public function __set($name, $value) + { + if (in_array($name, static::$options)) { + $this->logDeprecation('Setting property Client::' . $name . ' is deprecated'); + $this->$name = $value; + return; + } + + switch ($name) { + case 'errno': + case 'errstr': + case 'method': + case 'server': + case 'port': + case 'path': + $this->logDeprecation('Setting property Client::' . $name . ' is deprecated'); + $this->$name = $value; + return; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } + + public function __isset($name) + { + if (in_array($name, static::$options)) { + $this->logDeprecation('Checking property Client::' . $name . ' is deprecated'); + return isset($this->$name); + } + + switch ($name) { + case 'errno': + case 'errstr': + case 'method': + case 'server': + case 'port': + case 'path': + $this->logDeprecation('Checking property Client::' . $name . ' is deprecated'); + return isset($this->$name); + default: + return false; + } + } + + public function __unset($name) + { + if (in_array($name, static::$options)) { + $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated'); + unset($this->$name); + return; + } + + switch ($name) { + case 'errno': + case 'errstr': + case 'method': + case 'server': + case 'port': + case 'path': + $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated'); + unset($this->$name); + return; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } } diff --git a/src/Helper/XMLParser.php b/src/Helper/XMLParser.php index 39cb8d0b..167a8807 100644 --- a/src/Helper/XMLParser.php +++ b/src/Helper/XMLParser.php @@ -17,6 +17,9 @@ use PhpXmlRpc\Value; * @todo if iconv() or mb_string() are available, we could allow to convert the received xml to a custom charset encoding * while parsing, which is faster than doing it later by going over the rebuilt data structure * @todo rename? This is an xml-rpc parser, not a generic xml parser... + * + * @property array $xmlrpc_valid_parents deprecated - public access left in purely for BC + * @property int $accept deprecated - (protected) access left in purely for BC */ class XMLParser { @@ -72,9 +75,8 @@ class XMLParser /** * @var array[] - * @internal */ - public $xmlrpc_valid_parents = array( + protected $xmlrpc_valid_parents = array( 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), 'BOOLEAN' => array('VALUE'), 'I4' => array('VALUE'), @@ -1015,6 +1017,21 @@ class XMLParser $this->xmlrpc_se($parser, $name, $attrs, true); } + public function &__get($name) + { + switch ($name) { + case 'xmlrpc_valid_parents': + $this->logDeprecation('Getting property XMLParser::' . $name . ' is deprecated'); + return $this->$name; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + $result = null; + return $result; + } + } + public function __set($name, $value) { switch ($name) { @@ -1023,6 +1040,10 @@ class XMLParser $this->logDeprecation('Setting property XMLParser::' . $name . ' is deprecated'); $this->current_parsing_options['accept'] = $value; break; + case 'xmlrpc_valid_parents': + $this->logDeprecation('Setting property XMLParser::' . $name . ' is deprecated'); + $this->$name = $value; + break; default: /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); @@ -1036,6 +1057,9 @@ class XMLParser case 'accept': $this->logDeprecation('Checking property XMLParser::' . $name . ' is deprecated'); return isset($this->current_parsing_options['accept']); + case 'xmlrpc_valid_parents': + $this->logDeprecation('Checking property XMLParser::' . $name . ' is deprecated'); + return isset($this->$name); default: return false; } @@ -1049,6 +1073,10 @@ class XMLParser $this->logDeprecation('Unsetting property XMLParser::' . $name . ' is deprecated'); unset($this->current_parsing_options['accept']); break; + case 'xmlrpc_valid_parents': + $this->logDeprecation('Unsetting property XMLParser::' . $name . ' is deprecated'); + unset($this->$name); + break; default: /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); diff --git a/src/PhpXmlRpc.php b/src/PhpXmlRpc.php index 0a5acf50..9a2757f5 100644 --- a/src/PhpXmlRpc.php +++ b/src/PhpXmlRpc.php @@ -259,7 +259,10 @@ class PhpXmlRpc { $reflection = new \ReflectionClass('PhpXmlRpc\PhpXmlRpc'); foreach ($reflection->getStaticProperties() as $name => $value) { - $GLOBALS[$name] = $value; + if (!in_array($name, array('xmlrpc_return_datetimes', 'xmlrpc_reject_invalid_values', 'xmlrpc_datetime_format', + 'xmlrpc_int_format', 'xmlrpc_double_format', 'xmlrpc_methodname_format', 'xmlrpc_silence_deprecations'))) { + $GLOBALS[$name] = $value; + } } // NB: all the variables exported into the global namespace below here do NOT guarantee 100% compatibility, @@ -272,14 +275,10 @@ class PhpXmlRpc } } + /// @todo mke it possible to inject the XMLParser and Charset, as we do in other classes + $parser = new Helper\XMLParser(); - $reflection = new \ReflectionClass('PhpXmlRpc\Helper\XMLParser'); - foreach ($reflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $name => $value) { - if (in_array($value->getName(), array('xmlrpc_valid_parents'))) - { - $GLOBALS[$value->getName()] = $value->getValue($parser); - } - } + $GLOBALS['xmlrpc_valid_parents'] = $parser->xmlrpc_valid_parents; $charset = Charset::instance(); $GLOBALS['xml_iso88591_Entities'] = $charset->getEntities('iso88591'); @@ -298,14 +297,19 @@ class PhpXmlRpc * @return void * * @deprecated + * + * @todo this function does not import back xmlrpc_valid_parents and xml_iso88591_Entities */ public static function importGlobals() { $reflection = new \ReflectionClass('PhpXmlRpc\PhpXmlRpc'); - $staticProperties = $reflection->getStaticProperties(); - foreach ($staticProperties as $name => $value) { - if (isset($GLOBALS[$name])) { - self::$$name = $GLOBALS[$name]; + foreach ($reflection->getStaticProperties() as $name => $value) { + if (!in_array($name, array('xmlrpc_return_datetimes', 'xmlrpc_reject_invalid_values', 'xmlrpc_datetime_format', + 'xmlrpc_int_format', 'xmlrpc_double_format', 'xmlrpc_methodname_format', 'xmlrpc_silence_deprecations'))) + { + if (isset($GLOBALS[$name])) { + self::$$name = $GLOBALS[$name]; + } } } } diff --git a/src/Request.php b/src/Request.php index 2d9fd1f3..c1248f8a 100644 --- a/src/Request.php +++ b/src/Request.php @@ -15,6 +15,12 @@ use PhpXmlRpc\Traits\PayloadBearer; * A client sends a PhpXmlrpc\Request to a server, and receives back an PhpXmlrpc\Response. * * @todo feature creep - add a protected $httpRequest member, in the same way the Response has one + * + * @property string $methodname deprecated - public access left in purely for BC. Access via method()/__construct() + * @property Value[] $params deprecated - public access left in purely for BC. Access via getParam()/__construct() + * @property int $debug deprecated - public access left in purely for BC. Access via .../setDebug() + * @property string $payload deprecated - public access left in purely for BC. Access via getPayload()/setPayload() + * @property string $content_type deprecated - public access left in purely for BC. Access via getContentType()/setPayload() */ class Request { @@ -23,16 +29,17 @@ class Request use ParserAware; use PayloadBearer; - /// @todo: do these need to be public? - /** @internal */ - public $methodname; - /** @internal */ - public $params = array(); + /** @var string */ + protected $methodname; + /** @var Value[] */ + protected $params = array(); /** @var int */ - public $debug = 0; + protected $debug = 0; - // holds data while parsing the response. NB: Not a full Response object - /** @deprecated will be removed in a future release */ + /** + * holds data while parsing the response. NB: Not a full Response object + * @deprecated will be removed in a future release + */ protected $httpResponse = array(); /** @@ -413,4 +420,77 @@ class Request $this->debug = $level; return $this; } + + // *** BC layer *** + + // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];` + public function &__get($name) + { + switch ($name) { + case 'me': + case 'mytype': + case '_php_class': + case 'payload': + case 'content_type': + $this->logDeprecation('Getting property Request::' . $name . ' is deprecated'); + return $this->$name; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + $result = null; + return $result; + } + } + + public function __set($name, $value) + { + switch ($name) { + case 'methodname': + case 'params': + case 'debug': + case 'payload': + case 'content_type': + $this->logDeprecation('Setting property Request::' . $name . ' is deprecated'); + $this->$name = $value; + break; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } + + public function __isset($name) + { + switch ($name) { + case 'methodname': + case 'params': + case 'debug': + case 'payload': + case 'content_type': + $this->logDeprecation('Checking property Request::' . $name . ' is deprecated'); + return isset($this->$name); + default: + return false; + } + } + + public function __unset($name) + { + switch ($name) { + case 'methodname': + case 'params': + case 'debug': + case 'payload': + case 'content_type': + $this->logDeprecation('Unsetting property Request::' . $name . ' is deprecated'); + unset($this->$name); + break; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } } diff --git a/src/Response.php b/src/Response.php index 64e6373c..d822d3c4 100644 --- a/src/Response.php +++ b/src/Response.php @@ -12,9 +12,15 @@ use PhpXmlRpc\Traits\PayloadBearer; * Server-side, a server method handler will construct a Response and pass it as its return value. * An identical Response object will be returned by the result of an invocation of the send() method of the Client class. * - * @property array $hdrs deprecated, use $httpResponse['headers'] - * @property array _cookies deprecated, use $httpResponse['cookies'] - * @property string $raw_data deprecated, use $httpResponse['raw_data'] + * @property Value|string|mixed $val deprecated - public access left in purely for BC. Access via value()/__construct() + * @property string $valtyp deprecated - public access left in purely for BC. Access via valueType()/__construct() + * @property int $errno deprecated - public access left in purely for BC. Access via faultCode()/__construct() + * @property string $errstr deprecated - public access left in purely for BC. Access faultString()/__construct() + * @property string $payload deprecated - public access left in purely for BC. Access via getPayload()/setPayload() + * @property string $content_type deprecated - public access left in purely for BC. Access via getContentType()/setPayload() + * @property array $hdrs deprecated. Access via httpResponse()['headers'], set via $httpResponse['headers'] + * @property array _cookies deprecated. Access via httpResponse()['cookies'], set via $httpResponse['cookies'] + * @property string $raw_data deprecated. Access via httpResponse()['raw_data'], set via $httpResponse['raw_data'] */ class Response { @@ -22,15 +28,14 @@ class Response use DeprecationLogger; use PayloadBearer; - /// @todo: do these need to be public? - /** @internal */ - public $val = 0; - /** @internal */ - public $valtyp; - /** @internal */ - public $errno = 0; - /** @internal */ - public $errstr = ''; + /** @var Value|string|mixed */ + protected $val = 0; + /** @var string */ + protected $valtyp; + /** @var int */ + protected $errno = 0; + /** @var string */ + protected $errstr = ''; protected $httpResponse = array('headers' => array(), 'cookies' => array(), 'raw_data' => '', 'status_code' => null); @@ -218,6 +223,14 @@ class Response public function &__get($name) { switch ($name) { + case 'val': + case 'valtyp': + case 'errno': + case 'errstr': + case 'payload': + case 'content_type': + $this->logDeprecation('Getting property Response::' . $name . ' is deprecated'); + return $this->$name; case 'hdrs': $this->logDeprecation('Getting property Response::' . $name . ' is deprecated'); return $this->httpResponse['headers']; @@ -239,6 +252,15 @@ class Response public function __set($name, $value) { switch ($name) { + case 'val': + case 'valtyp': + case 'errno': + case 'errstr': + case 'payload': + case 'content_type': + $this->logDeprecation('Setting property Response::' . $name . ' is deprecated'); + $this->$name = $value; + break; case 'hdrs': $this->logDeprecation('Setting property Response::' . $name . ' is deprecated'); $this->httpResponse['headers'] = $value; @@ -261,6 +283,14 @@ class Response public function __isset($name) { switch ($name) { + case 'val': + case 'valtyp': + case 'errno': + case 'errstr': + case 'payload': + case 'content_type': + $this->logDeprecation('Checking property Response::' . $name . ' is deprecated'); + return isset($this->$name); case 'hdrs': $this->logDeprecation('Checking property Response::' . $name . ' is deprecated'); return isset($this->httpResponse['headers']); @@ -278,6 +308,15 @@ class Response public function __unset($name) { switch ($name) { + case 'val': + case 'valtyp': + case 'errno': + case 'errstr': + case 'payload': + case 'content_type': + $this->logDeprecation('Setting property Response::' . $name . ' is deprecated'); + unset($this->$name); + break; case 'hdrs': $this->logDeprecation('Unsetting property Response::' . $name . ' is deprecated'); unset($this->httpResponse['headers']); diff --git a/src/Server.php b/src/Server.php index 0915e452..a41cc366 100644 --- a/src/Server.php +++ b/src/Server.php @@ -14,6 +14,15 @@ use PhpXmlRpc\Traits\ParserAware; /** * Allows effortless implementation of XML-RPC servers + * + * @property string[] $accepted_compression deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property bool $allow_system_funcs deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property bool $compress_response deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property int $debug deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property int $exception_handling deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property string $functions_parameters_type deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property array $phpvals_encoding_options deprecated - public access left in purely for BC. Access via getOption()/setOption() + * @property string $response_charset_encoding deprecated - public access left in purely for BC. Access via getOption()/setOption() */ class Server { @@ -37,7 +46,7 @@ class Server * * @todo create class constants for these */ - public $functions_parameters_type = 'xmlrpcvals'; + protected $functions_parameters_type = 'xmlrpcvals'; /** * @var array @@ -45,7 +54,7 @@ class Server * when the functions_parameters_type member is set to 'phpvals'. * @see Encoder::encode for a list of values */ - public $phpvals_encoding_options = array('auto_dates'); + protected $phpvals_encoding_options = array('auto_dates'); /** * @var int @@ -57,7 +66,7 @@ class Server * 2 = * 3 = */ - public $debug = 1; + protected $debug = 1; /** * @var int @@ -68,7 +77,7 @@ class Server * 2 = allow the exception to float to the upper layers * Can be overridden per-method-handler in the dispatch map */ - public $exception_handling = 0; + protected $exception_handling = 0; /** * @var bool @@ -76,27 +85,27 @@ class Server * for compression in the request. * Automatically set at constructor time. */ - public $compress_response = false; + protected $compress_response = false; /** * @var string[] * List of http compression methods accepted by the server for requests. Automatically set at constructor time. * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib */ - public $accepted_compression = array(); + protected $accepted_compression = array(); /** * @var bool * Shall we serve calls to system.* methods? */ - public $allow_system_funcs = true; + protected $allow_system_funcs = true; /** * List of charset encodings natively accepted for requests. * Set at constructor time. - * UNUSED so far... + * @deprecated UNUSED so far... */ - public $accepted_charset_encodings = array(); + protected $accepted_charset_encodings = array(); /** * @var string @@ -108,7 +117,18 @@ class Server * - 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway). * NB: pretty dangerous if you accept every charset and do not have mbstring enabled) */ - public $response_charset_encoding = ''; + protected $response_charset_encoding = ''; + + protected static $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, + ); /** * @var mixed @@ -123,17 +143,6 @@ 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. */ @@ -194,28 +203,14 @@ class Server { 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; + $this->$name = $value; break; default: throw new ValueErrorException("Unsupported option '$name'"); @@ -233,21 +228,14 @@ class Server { 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; + return $this->$name; default: throw new ValueErrorException("Unsupported option '$name'"); } @@ -260,7 +248,7 @@ class Server public function getOptions() { $values = array(); - foreach($this->options as $opt) { + foreach(static::$options as $opt) { $values[$opt] = $this->getOption($opt); } return $values; @@ -1442,4 +1430,87 @@ class Server return "\n"; } } + + // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];` + public function &__get($name) + { + switch ($name) { + case self::OPT_ACCEPTED_COMPRESSION : + case self::OPT_ALLOW_SYSTEM_FUNCS: + case self::OPT_COMPRESS_RESPONSE: + case self::OPT_DEBUG: + case self::OPT_EXCEPTION_HANDLING: + case self::OPT_FUNCTIONS_PARAMETERS_TYPE: + case self::OPT_PHPVALS_ENCODING_OPTIONS: + case self::OPT_RESPONSE_CHARSET_ENCODING: + $this->logDeprecation('Getting property Request::' . $name . ' is deprecated'); + return $this->$name; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + $result = null; + return $result; + } + } + + public function __set($name, $value) + { + switch ($name) { + case self::OPT_ACCEPTED_COMPRESSION : + case self::OPT_ALLOW_SYSTEM_FUNCS: + case self::OPT_COMPRESS_RESPONSE: + case self::OPT_DEBUG: + case self::OPT_EXCEPTION_HANDLING: + case self::OPT_FUNCTIONS_PARAMETERS_TYPE: + case self::OPT_PHPVALS_ENCODING_OPTIONS: + case self::OPT_RESPONSE_CHARSET_ENCODING: + $this->logDeprecation('Setting property Request::' . $name . ' is deprecated'); + $this->$name = $value; + break; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } + + public function __isset($name) + { + switch ($name) { + case self::OPT_ACCEPTED_COMPRESSION : + case self::OPT_ALLOW_SYSTEM_FUNCS: + case self::OPT_COMPRESS_RESPONSE: + case self::OPT_DEBUG: + case self::OPT_EXCEPTION_HANDLING: + case self::OPT_FUNCTIONS_PARAMETERS_TYPE: + case self::OPT_PHPVALS_ENCODING_OPTIONS: + case self::OPT_RESPONSE_CHARSET_ENCODING: + $this->logDeprecation('Checking property Request::' . $name . ' is deprecated'); + return isset($this->$name); + default: + return false; + } + } + + public function __unset($name) + { + switch ($name) { + case self::OPT_ACCEPTED_COMPRESSION : + case self::OPT_ALLOW_SYSTEM_FUNCS: + case self::OPT_COMPRESS_RESPONSE: + case self::OPT_DEBUG: + case self::OPT_EXCEPTION_HANDLING: + case self::OPT_FUNCTIONS_PARAMETERS_TYPE: + case self::OPT_PHPVALS_ENCODING_OPTIONS: + case self::OPT_RESPONSE_CHARSET_ENCODING: + $this->logDeprecation('Unsetting property Request::' . $name . ' is deprecated'); + unset($this->$name); + break; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } } diff --git a/src/Traits/PayloadBearer.php b/src/Traits/PayloadBearer.php index 877009f8..026130d0 100644 --- a/src/Traits/PayloadBearer.php +++ b/src/Traits/PayloadBearer.php @@ -5,9 +5,9 @@ namespace PhpXmlRpc\Traits; trait PayloadBearer { /** @var string */ - public $payload; + protected $payload; /** @var string */ - public $content_type = 'text/xml'; + protected $content_type = 'text/xml'; /** * @internal diff --git a/src/Value.php b/src/Value.php index 30a9c6b1..64a9dbeb 100644 --- a/src/Value.php +++ b/src/Value.php @@ -10,6 +10,10 @@ use PhpXmlRpc\Traits\DeprecationLogger; /** * This class enables the creation of values for XML-RPC, by encapsulating plain php values. + * + * @property Value[]|mixed $me deprecated - public access left in purely for BC. Access via scalarVal()/__construct() + * @property int $params $mytype - public access left in purely for BC. Access via kindOf()/__construct() + * @property string|null $_php_class deprecated - public access left in purely for BC. */ class Value implements \Countable, \IteratorAggregate, \ArrayAccess { @@ -43,16 +47,14 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess "null" => 1, ); - /// @todo: do these need to be public? /** @var Value[]|mixed */ - public $me = array(); + protected $me = array(); /** * @var int 0 for undef, 1 for scalar, 2 for array, 3 for struct - * @internal */ - public $mytype = 0; + protected $mytype = 0; /** @var string|null */ - public $_php_class = null; + protected $_php_class = null; /** * Build an xml-rpc value. @@ -675,4 +677,67 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess return count($this->me['struct']); } + + // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];` + public function &__get($name) + { + switch ($name) { + case 'me': + case 'mytype': + case '_php_class': + $this->logDeprecation('Getting property Value::' . $name . ' is deprecated'); + return $this->$name; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + $result = null; + return $result; + } + } + + public function __set($name, $value) + { + switch ($name) { + case 'me': + case 'mytype': + case '_php_class': + $this->logDeprecation('Setting property Value::' . $name . ' is deprecated'); + $this->$name = $value; + break; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } + + public function __isset($name) + { + switch ($name) { + case 'me': + case 'mytype': + case '_php_class': + $this->logDeprecation('Checking property Value::' . $name . ' is deprecated'); + return isset($this->$name); + default: + return false; + } + } + + public function __unset($name) + { + switch ($name) { + case 'me': + case 'mytype': + case '_php_class': + $this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated'); + unset($this->$name); + break; + default: + /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); + } + } } -- 2.47.0