From b337d292eb5b5656d27a2fc9ab6796be300c59a3 Mon Sep 17 00:00:00 2001 From: gggeek Date: Wed, 13 Jan 2021 00:15:14 +0000 Subject: [PATCH] adopt CI-like patterns --- NEWS | 13 +++++++ src/Client.php | 38 +++++++++++++++------ src/Encoder.php | 42 ++++++++++++++++++++--- src/Helper/Charset.php | 4 +++ src/Helper/XMLParser.php | 6 +++- src/Request.php | 59 +++++++++++++++++++++++++++----- src/Response.php | 15 ++++++++ src/Server.php | 74 ++++++++++++++++++++++++++++++++++------ src/Value.php | 45 +++++++++++++++++++----- src/Wrapper.php | 45 ++++++++++++++++-------- 10 files changed, 284 insertions(+), 57 deletions(-) diff --git a/NEWS b/NEWS index 3ddc9ee..f10f1ef 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,19 @@ XML-RPC for PHP version 4.6.0 - unreleased * improved: when encoding utf8 text into us-ascii xml, use character entity references for characters number 0-31 (ascii non printable characters), as we were already doing when encoding iso-8859-1 text into us-ascii xml +* new: method `Server::getDispatchMap()`. Useful for non-child classes which want to f.e. introspect the server + +* new: increase flexibility in class composition by adopting a Dependency Injection (...ish) pattern: + it is now possible to swap out the Logger, XMLParser and Charset classes with similar ones of your own making. + Example code: + // 1. create an instance of a custom character encoder + // $myCharsetEncoder = ... + // 2. then use it while serializing a Request: + Request::setCharsetEncoder($myCharsetEncoder); + $request->serialize($funkyCharset); + +* new: method `XMLParser::parse()` acquired a 4th argument + XML-RPC for PHP version 4.5.2 - 2021/1/11 diff --git a/src/Client.php b/src/Client.php index fe4eb5d..4e03d3e 100644 --- a/src/Client.php +++ b/src/Client.php @@ -13,6 +13,8 @@ class Client const USE_CURL_ALWAYS = 1; const USE_CURL_AUTO = 2; + protected static $logger; + /// @todo: do these need to be public? public $method = 'http'; public $server; @@ -88,10 +90,11 @@ class Client /** * The charset encoding that will be used for serializing request sent by the client. - * It defaults to NULL, which means using US-ASCII and encoding all characters outside of the ASCII range using - * their xml character entity representation (this has the benefit that line end characters will not be mangled 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' + * It defaults to NULL, which means using US-ASCII and encoding all characters outside of the ASCII printable range + * using their xml character entity representation (this has the benefit that line end characters will not be mangled + * 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 as well as this to UTF-8. */ public $request_charset_encoding = ''; @@ -115,6 +118,19 @@ class Client */ public $user_agent; + public function getLogger() + { + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + return self::$logger; + } + + public static function setLogger($logger) + { + self::$logger = $logger; + } + /** * @param string $path either the PATH part of the xmlrpc server URL, or complete server URL (in which case you * should use and empty string for all other parameters) @@ -670,7 +686,7 @@ class Client if ($username != '') { $credentials = 'Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; if ($authType != 1) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported with HTTP 1.0'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported with HTTP 1.0'); } } @@ -690,7 +706,7 @@ class Client $uri = 'http://' . $server . ':' . $port . $this->path; if ($proxyUsername != '') { if ($proxyAuthType != 1) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported with HTTP 1.0'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported with HTTP 1.0'); } $proxyCredentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyUsername . ':' . $proxyPassword) . "\r\n"; } @@ -746,7 +762,7 @@ class Client $payload; if ($this->debug > 1) { - Logger::instance()->debugMessage("---SENDING---\n$op\n---END---"); + $this->getLogger()->debugMessage("---SENDING---\n$op\n---END---"); } $contextOptions = array(); @@ -900,7 +916,7 @@ class Client } if ($this->debug > 1) { - Logger::instance()->debugMessage("---SENDING---\n$payload\n---END---"); + $this->getLogger()->debugMessage("---SENDING---\n$payload\n---END---"); } if (!$keepAlive || !$this->xmlrpc_curl_handle) { @@ -976,7 +992,7 @@ class Client if (defined('CURLOPT_HTTPAUTH')) { curl_setopt($curl, CURLOPT_HTTPAUTH, $authType); } elseif ($authType != 1) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported by the current PHP/curl install'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported by the current PHP/curl install'); } } @@ -1024,7 +1040,7 @@ class Client if (defined('CURLOPT_PROXYAUTH')) { curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyAuthType); } elseif ($proxyAuthType != 1) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); } } } @@ -1054,7 +1070,7 @@ class Client $message .= $name . ': ' . $val . "\n"; } $message .= '---END---'; - Logger::instance()->debugMessage($message); + $this->getLogger()->debugMessage($message); } if (!$result) { diff --git a/src/Encoder.php b/src/Encoder.php index ecb64bd..7ad2adb 100644 --- a/src/Encoder.php +++ b/src/Encoder.php @@ -12,6 +12,35 @@ use PhpXmlRpc\Helper\XMLParser; */ class Encoder { + protected static $logger; + protected static $parser; + + public function getLogger() + { + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + return self::$logger; + } + + public static function setLogger($logger) + { + self::$logger = $logger; + } + + public function getParser() + { + if (self::$parser === null) { + self::$parser = new XMLParser(); + } + return self::$parser; + } + + public static function setParser($parser) + { + self::$parser = $parser; + } + /** * Takes an xmlrpc value in object format and translates it into native PHP types. * @@ -280,7 +309,7 @@ class Encoder if (extension_loaded('mbstring')) { $xmlVal = mb_convert_encoding($xmlVal, 'UTF-8', $valEncoding); } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of xml text: ' . $valEncoding); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of xml text: ' . $valEncoding); } } } @@ -294,13 +323,18 @@ class Encoder $parserOptions = array(XML_OPTION_TARGET_ENCODING => PhpXmlRpc::$xmlrpc_internalencoding); } - $xmlRpcParser = new XMLParser($parserOptions); - $xmlRpcParser->parse($xmlVal, XMLParser::RETURN_XMLRPCVALS, XMLParser::ACCEPT_REQUEST | XMLParser::ACCEPT_RESPONSE | XMLParser::ACCEPT_VALUE | XMLParser::ACCEPT_FAULT); + $xmlRpcParser = $this->getParser(); + $xmlRpcParser->parse( + $xmlVal, + XMLParser::RETURN_XMLRPCVALS, + XMLParser::ACCEPT_REQUEST | XMLParser::ACCEPT_RESPONSE | XMLParser::ACCEPT_VALUE | XMLParser::ACCEPT_FAULT, + $parserOptions + ); if ($xmlRpcParser->_xh['isf'] > 1) { // test that $xmlrpc->_xh['value'] is an obj, too??? - Logger::instance()->errorLog($xmlRpcParser->_xh['isf_reason']); + $this->getLogger()->errorLog($xmlRpcParser->_xh['isf_reason']); return false; } diff --git a/src/Helper/Charset.php b/src/Helper/Charset.php index 78bc813..5fa5422 100644 --- a/src/Helper/Charset.php +++ b/src/Helper/Charset.php @@ -51,6 +51,8 @@ class Charset * @param string $tableName * @throws \Exception for unsupported $tableName * @todo add support for cp1252 as well as latin-2 .. latin-10 + * Optimization creep: instead of building all those tables on load, keep them ready-made php files + * which are not even included until needed * @todo should we add to the latin-1 table the characters from cp_1252 range, i.e. 128 to 159 ? * Those will NOT be present in true ISO-8859-1, but will save the unwary windows user from sending junk * (though no luck when receiving them...) @@ -125,6 +127,7 @@ class Charset * but then take those into account as well in other methods, ie.isValidCharset) * @todo when converting to ASCII, allow to choose whether to escape the range 0-31,127 (non-print chars) or not * @todo allow picking different strategies to deal w. invalid chars? eg. source in latin-1 and chars 128-159 + * @todo add support for escaping using CDATA sections? (add cdata start and end tokens, replace only ']]>' with ']]]]>') * * @param string $data * @param string $srcEncoding @@ -176,6 +179,7 @@ class Charset } else if ($ii < 128) { /// @todo shall we replace this with a (supposedly) faster str_replace? + /// @todo to be 'print safe', should we encode as well character 127 (DEL) ? switch ($ii) { case 34: $escapedData .= '"'; diff --git a/src/Helper/XMLParser.php b/src/Helper/XMLParser.php index 59eec67..f6e79a9 100644 --- a/src/Helper/XMLParser.php +++ b/src/Helper/XMLParser.php @@ -97,8 +97,9 @@ class XMLParser * @param string $data * @param string $returnType * @param int $accept a bit-combination of self::ACCEPT_REQUEST, self::ACCEPT_RESPONSE, self::ACCEPT_VALUE + * @param array $options */ - public function parse($data, $returnType = self::RETURN_XMLRPCVALS, $accept = 3) + public function parse($data, $returnType = self::RETURN_XMLRPCVALS, $accept = 3, $options = array()) { $this->_xh = array( 'ac' => '', @@ -127,6 +128,9 @@ class XMLParser foreach ($this->parsing_options as $key => $val) { xml_parser_set_option($parser, $key, $val); } + foreach ($options as $key => $val) { + xml_parser_set_option($parser, $key, $val); + } // always set this, in case someone tries to disable it via options... xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 1); diff --git a/src/Request.php b/src/Request.php index 66cc788..01fc9d6 100644 --- a/src/Request.php +++ b/src/Request.php @@ -13,6 +13,10 @@ use PhpXmlRpc\Helper\XMLParser; */ class Request { + protected static $logger; + protected static $parser; + protected static $charsetEncoder; + /// @todo: do these need to be public? public $payload; /** @internal */ @@ -25,6 +29,45 @@ class Request // holds data while parsing the response. NB: Not a full Response object protected $httpResponse = array(); + public function getLogger() + { + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + return self::$logger; + } + + public static function setLogger($logger) + { + self::$logger = $logger; + } + + public function getParser() + { + if (self::$parser === null) { + self::$parser = new XMLParser(); + } + return self::$parser; + } + + public static function setParser($parser) + { + self::$parser = $parser; + } + + public function getCharsetEncoder() + { + if (self::$charsetEncoder === null) { + self::$charsetEncoder = Charset::instance(); + } + return self::$charsetEncoder; + } + + public function setCharsetEncoder($charsetEncoder) + { + self::$charsetEncoder = $charsetEncoder; + } + /** * @param string $methodName the name of the method to invoke * @param Value[] $params array of parameters to be passed to the method (NB: Value objects, not plain php values) @@ -72,7 +115,7 @@ class Request $this->content_type = 'text/xml'; } $this->payload = $this->xml_header($charsetEncoding); - $this->payload .= '' . Charset::instance()->encodeEntities( + $this->payload .= '' . $this->getCharsetEncoder()->encodeEntities( $this->methodname, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "\n"; $this->payload .= "\n"; foreach ($this->params as $p) { @@ -197,13 +240,13 @@ class Request public function parseResponse($data = '', $headersProcessed = false, $returnType = 'xmlrpcvals') { if ($this->debug) { - Logger::instance()->debugMessage("---GOT---\n$data\n---END---"); + $this->getLogger()->debugMessage("---GOT---\n$data\n---END---"); } $this->httpResponse = array('raw_data' => $data, 'headers' => array(), 'cookies' => array()); if ($data == '') { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': no response received from server.'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': no response received from server.'); return new Response(0, PhpXmlRpc::$xmlrpcerr['no_data'], PhpXmlRpc::$xmlrpcstr['no_data']); } @@ -243,7 +286,7 @@ class Request $start += strlen('', $start); $comments = substr($data, $start, $end - $start); - Logger::instance()->debugMessage("---SERVER DEBUG INFO (DECODED) ---\n\t" . + $this->getLogger()->debugMessage("---SERVER DEBUG INFO (DECODED) ---\n\t" . str_replace("\n", "\n\t", base64_decode($comments)) . "\n---END---", $respEncoding); } } @@ -272,7 +315,7 @@ class Request if (extension_loaded('mbstring')) { $data = mb_convert_encoding($data, 'UTF-8', $respEncoding); } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of received response: ' . $respEncoding); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of received response: ' . $respEncoding); } } } @@ -289,8 +332,8 @@ class Request $options = array(XML_OPTION_TARGET_ENCODING => PhpXmlRpc::$xmlrpc_internalencoding); } - $xmlRpcParser = new XMLParser($options); - $xmlRpcParser->parse($data, $returnType, XMLParser::ACCEPT_RESPONSE); + $xmlRpcParser = $this->getParser(); + $xmlRpcParser->parse($data, $returnType, XMLParser::ACCEPT_RESPONSE, $options); // first error check: xml not well formed if ($xmlRpcParser->_xh['isf'] > 2) { @@ -323,7 +366,7 @@ class Request PhpXmlRpc::$xmlrpcstr['invalid_return']); } else { if ($this->debug > 1) { - Logger::instance()->debugMessage( + $this->getLogger()->debugMessage( "---PARSED---\n".var_export($xmlRpcParser->_xh['value'], true)."\n---END---" ); } diff --git a/src/Response.php b/src/Response.php index cc33ebf..e634ce5 100644 --- a/src/Response.php +++ b/src/Response.php @@ -11,6 +11,8 @@ use PhpXmlRpc\Helper\Charset; */ class Response { + protected static $charsetEncoder; + /// @todo: do these need to be public? /** @internal */ public $val = 0; @@ -26,6 +28,19 @@ class Response public $_cookies = array(); public $raw_data = ''; + public function getCharsetEncoder() + { + if (self::$charsetEncoder === null) { + self::$charsetEncoder = Charset::instance(); + } + return self::$charsetEncoder; + } + + public function setCharsetEncoder($charsetEncoder) + { + self::$charsetEncoder = $charsetEncoder; + } + /** * @param Value|string|mixed $val either a Value object, a php value or the xml serialization of an xmlrpc value (a string) * @param integer $fCode set it to anything but 0 to create an error response. In that case, $val is discarded diff --git a/src/Server.php b/src/Server.php index 199a7a6..e859c7b 100644 --- a/src/Server.php +++ b/src/Server.php @@ -11,6 +11,10 @@ use PhpXmlRpc\Helper\XMLParser; */ class Server { + protected static $logger; + protected static $parser; + protected static $charsetEncoder; + /** * Defines how functions in dmap will be invoked: either using an xmlrpc request object * or plain php values. @@ -95,6 +99,45 @@ class Server protected static $_xmlrpcs_occurred_errors = ''; protected static $_xmlrpcs_prev_ehandler = ''; + public function getLogger() + { + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + return self::$logger; + } + + public static function setLogger($logger) + { + self::$logger = $logger; + } + + public function getParser() + { + if (self::$parser === null) { + self::$parser = new XMLParser(); + } + return self::$parser; + } + + public static function setParser($parser) + { + self::$parser = $parser; + } + + public function getCharsetEncoder() + { + if (self::$charsetEncoder === null) { + self::$charsetEncoder = Charset::instance(); + } + return self::$charsetEncoder; + } + + public function setCharsetEncoder($charsetEncoder) + { + self::$charsetEncoder = $charsetEncoder; + } + /** * @param array[] $dispatchMap the dispatch map with definition of exposed services * Array keys are the names of the method names. @@ -194,7 +237,7 @@ class Server $out .= "\n"; } if (static::$_xmlrpc_debuginfo != '') { - $out .= "\n"; + $out .= "\n"; // NB: a better solution MIGHT be to use CDATA, but we need to insert it // into return payload AFTER the beginning tag //$out .= "', ']_]_>', static::$_xmlrpc_debuginfo) . "\n]]>\n"; @@ -292,7 +335,7 @@ class Server header('Content-Length: ' . (int)strlen($payload)); } } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': http headers already sent before response is fully generated. Check for php warning or error messages'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': http headers already sent before response is fully generated. Check for php warning or error messages'); } print $payload; @@ -392,7 +435,7 @@ class Server // check if $_SERVER is populated: it might have been disabled via ini file // (this is true even when in CLI mode) if (count($_SERVER) == 0) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': cannot parse request headers as $_SERVER is not populated'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': cannot parse request headers as $_SERVER is not populated'); } if ($this->debug > 1) { @@ -513,7 +556,7 @@ class Server if (extension_loaded('mbstring')) { $data = mb_convert_encoding($data, 'UTF-8', $reqEncoding); } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of received request: ' . $reqEncoding); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of received request: ' . $reqEncoding); } } } @@ -530,8 +573,8 @@ class Server $options = array(XML_OPTION_TARGET_ENCODING => PhpXmlRpc::$xmlrpc_internalencoding); } - $xmlRpcParser = new XMLParser($options); - $xmlRpcParser->parse($data, $this->functions_parameters_type, XMLParser::ACCEPT_REQUEST); + $xmlRpcParser = $this->getParser(); + $xmlRpcParser->parse($data, $this->functions_parameters_type, XMLParser::ACCEPT_REQUEST, $options); if ($xmlRpcParser->_xh['isf'] > 2) { // (BC) we return XML error as a faultCode preg_match('/^XML error ([0-9]+)/', $xmlRpcParser->_xh['isf_reason'], $matches); @@ -643,7 +686,7 @@ class Server // verify that function to be invoked is in fact callable if (!is_callable($func)) { - Logger::instance()->errorLog("XML-RPC: " . __METHOD__ . ": function '$funcName' registered as method handler is not callable"); + $this->getLogger()->errorLog("XML-RPC: " . __METHOD__ . ": function '$funcName' registered as method handler is not callable"); return new Response( 0, PhpXmlRpc::$xmlrpcerr['server_error'], @@ -666,7 +709,7 @@ class Server $r = call_user_func($func, $req); } if (!is_a($r, 'PhpXmlRpc\Response')) { - Logger::instance()->errorLog("XML-RPC: " . __METHOD__ . ": function '$funcName' registered as method handler does not return an xmlrpc response object but a " . gettype($r)); + $this->getLogger()->errorLog("XML-RPC: " . __METHOD__ . ": function '$funcName' registered as method handler does not return an xmlrpc response object but a " . gettype($r)); if (is_a($r, 'PhpXmlRpc\Value')) { $r = new Response($r); } else { @@ -773,7 +816,13 @@ class Server return (strpos($methName, "system.") === 0); } - /* Functions that implement system.XXX methods of xmlrpc servers */ + /** + * @return array[] + */ + public function getDispatchMap() + { + return $this->dmap; + } /** * @return array[] @@ -820,6 +869,8 @@ class Server ); } + /* Functions that implement system.XXX methods of xmlrpc servers */ + /** * @return array[] */ @@ -1119,7 +1170,10 @@ class Server // The previous error handler was the default: all we should do is log error // to the default error log (if level high enough) if (ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errCode)) { - Logger::instance()->errorLog($errString); + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + self::$logger->errorLog($errString); } } else { // Pass control on to previous error handler, trying to avoid loops... diff --git a/src/Value.php b/src/Value.php index e3db3a1..1e7e288 100644 --- a/src/Value.php +++ b/src/Value.php @@ -37,6 +37,9 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess "null" => 1, ); + protected static $logger; + protected static $charsetEncoder; + /// @todo: do these need to be public? /** @var Value[]|mixed */ public $me = array(); @@ -48,6 +51,32 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess /** @var string|null $_php_class */ public $_php_class = null; + public function getLogger() + { + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + return self::$logger; + } + + public static function setLogger($logger) + { + self::$logger = $logger; + } + + public function getCharsetEncoder() + { + if (self::$charsetEncoder === null) { + self::$charsetEncoder = Charset::instance(); + } + return self::$charsetEncoder; + } + + public function setCharsetEncoder($charsetEncoder) + { + self::$charsetEncoder = $charsetEncoder; + } + /** * Build an xmlrpc value. * @@ -90,7 +119,7 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess $this->me['struct'] = $val; break; default: - Logger::instance()->errorLog("XML-RPC: " . __METHOD__ . ": not a known type ($type)"); + $this->getLogger()->errorLog("XML-RPC: " . __METHOD__ . ": not a known type ($type)"); } } } @@ -115,7 +144,7 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess } if ($typeOf !== 1) { - Logger::instance()->errorLog("XML-RPC: " . __METHOD__ . ": not a scalar type ($type)"); + $this->getLogger()->errorLog("XML-RPC: " . __METHOD__ . ": not a scalar type ($type)"); return 0; } @@ -132,10 +161,10 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess switch ($this->mytype) { case 1: - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': scalar xmlrpc value can have only one value'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': scalar xmlrpc value can have only one value'); return 0; case 3: - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': cannot add anonymous scalar to struct xmlrpc value'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': cannot add anonymous scalar to struct xmlrpc value'); return 0; case 2: // we're adding a scalar value to an array here @@ -177,7 +206,7 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess return 1; } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']'); return 0; } } @@ -208,7 +237,7 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess return 1; } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']'); return 0; } } @@ -257,7 +286,7 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess break; case static::$xmlrpcString: // Do NOT use htmlentities, since it will produce named html entities, which are invalid xml - $rs .= "<${typ}>" . Charset::instance()->encodeEntities($val, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . ""; + $rs .= "<${typ}>" . $this->getCharsetEncoder()->encodeEntities($val, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . ""; break; case static::$xmlrpcInt: case static::$xmlrpcI4: @@ -304,7 +333,7 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess } else { $rs .= "\n"; } - $charsetEncoder = Charset::instance(); + $charsetEncoder = $this->getCharsetEncoder(); /** @var Value $val2 */ foreach ($val as $key2 => $val2) { $rs .= '' . $charsetEncoder->encodeEntities($key2, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "\n"; diff --git a/src/Wrapper.php b/src/Wrapper.php index 2751ec2..15f84ce 100644 --- a/src/Wrapper.php +++ b/src/Wrapper.php @@ -24,6 +24,21 @@ class Wrapper /// used to hold a reference to object instances whose methods get wrapped by wrapPhpFunction(), in 'create source' mode public static $objHolder = array(); + protected static $logger; + + public function getLogger() + { + if (self::$logger === null) { + self::$logger = Logger::instance(); + } + return self::$logger; + } + + public static function setLogger($logger) + { + self::$logger = $logger; + } + /** * Given a string defining a php type or phpxmlrpc type (loosely defined: strings * accepted come from javadoc blocks), return corresponding phpxmlrpc type. @@ -168,7 +183,7 @@ class Wrapper } if (is_array($callable)) { if (count($callable) < 2 || (!is_string($callable[0]) && !is_object($callable[0]))) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': syntax for function to be wrapped is wrong'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': syntax for function to be wrapped is wrong'); return false; } if (is_string($callable[0])) { @@ -180,7 +195,7 @@ class Wrapper } else if ($callable instanceof \Closure) { // we do not support creating code which wraps closures, as php does not allow to serialize them if (!$buildIt) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': a closure can not be wrapped in generated source code'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': a closure can not be wrapped in generated source code'); return false; } @@ -192,7 +207,7 @@ class Wrapper } if (!$exists) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': function to be wrapped is not defined: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': function to be wrapped is not defined: ' . $plainFuncName); return false; } @@ -236,23 +251,23 @@ class Wrapper if (is_array($callable)) { $func = new \ReflectionMethod($callable[0], $callable[1]); if ($func->isPrivate()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is private: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is private: ' . $plainFuncName); return false; } if ($func->isProtected()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is protected: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is protected: ' . $plainFuncName); return false; } if ($func->isConstructor()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the constructor: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the constructor: ' . $plainFuncName); return false; } if ($func->isDestructor()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the destructor: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the destructor: ' . $plainFuncName); return false; } if ($func->isAbstract()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is abstract: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': method to be wrapped is abstract: ' . $plainFuncName); return false; } /// @todo add more checks for static vs. nonstatic? @@ -262,7 +277,7 @@ class Wrapper if ($func->isInternal()) { // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs // instead of getparameters to fully reflect internal php functions ? - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': function to be wrapped is internal: ' . $plainFuncName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': function to be wrapped is internal: ' . $plainFuncName); return false; } @@ -745,7 +760,7 @@ class Wrapper $client->setDebug($debug); $response = $client->send($req, $timeout, $protocol); if ($response->faultCode()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve method signature from remote server for method ' . $methodName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve method signature from remote server for method ' . $methodName); return false; } @@ -756,7 +771,7 @@ class Wrapper } if (!is_array($mSig) || count($mSig) <= $sigNum) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve method signature nr.' . $sigNum . ' from remote server for method ' . $methodName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve method signature nr.' . $sigNum . ' from remote server for method ' . $methodName); return false; } @@ -1021,7 +1036,7 @@ class Wrapper $req = new $reqClass('system.listMethods'); $response = $client->send($req, $timeout, $protocol); if ($response->faultCode()) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve method list from remote server'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve method list from remote server'); return false; } else { @@ -1031,7 +1046,7 @@ class Wrapper $mList = $decoder->decode($mList); } if (!is_array($mList) || !count($mList)) { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve meaningful method list from remote server'); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': could not retrieve meaningful method list from remote server'); return false; } else { @@ -1073,7 +1088,7 @@ class Wrapper } $source .= $methodWrap['source'] . "\n"; } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': will not create class method to wrap remote method ' . $mName); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': will not create class method to wrap remote method ' . $mName); } } } @@ -1084,7 +1099,7 @@ class Wrapper if ($allOK) { return $xmlrpcClassName; } else { - Logger::instance()->errorLog('XML-RPC: ' . __METHOD__ . ': could not create class ' . $xmlrpcClassName . ' to wrap remote server ' . $client->server); + $this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': could not create class ' . $xmlrpcClassName . ' to wrap remote server ' . $client->server); return false; } } else { -- 2.43.0