From 7f8f24562b596c56d79e46eba9f82780df5725cb Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 16 Sep 2021 15:22:50 +0200 Subject: [PATCH] move IXR XML RPC to composer dependency #1970 This is a monky patched version of kissyfrot/php-ixr until my PR has been accepted upstream. Plugins using the XML RPC client may need adjustments. --- _test/tests/inc/XmlRpcServer.test.php | 6 +- _test/tests/inc/ixr_library_date.test.php | 44 - .../inc/ixr_library_ixr_message.test.php | 134 -- composer.json | 3 +- composer.lock | 51 +- inc/IXR_Library.php | 1135 ----------------- inc/Remote/IXR/Client.php | 88 ++ inc/Remote/XmlRpcServer.php | 23 +- inc/load.php | 4 - vendor/composer/ClassLoader.php | 117 +- vendor/composer/InstalledVersions.php | 667 +++++----- vendor/composer/autoload_psr4.php | 1 + vendor/composer/autoload_static.php | 8 + vendor/composer/installed.json | 50 + vendor/composer/installed.php | 217 ++-- vendor/kissifrot/php-ixr/.editorconfig | 8 + vendor/kissifrot/php-ixr/.gitignore | 6 + vendor/kissifrot/php-ixr/LICENSE.txt | 28 + vendor/kissifrot/php-ixr/README.md | 37 + vendor/kissifrot/php-ixr/composer.json | 27 + .../kissifrot/php-ixr/src/Client/Client.php | 209 +++ .../php-ixr/src/Client/ClientMulticall.php | 36 + .../php-ixr/src/Client/ClientSSL.php | 235 ++++ .../kissifrot/php-ixr/src/DataType/Base64.php | 23 + .../kissifrot/php-ixr/src/DataType/Date.php | 56 + .../kissifrot/php-ixr/src/DataType/Value.php | 121 ++ .../php-ixr/src/Exception/ClientException.php | 9 + .../php-ixr/src/Exception/ServerException.php | 9 + .../kissifrot/php-ixr/src/Message/Error.php | 43 + .../kissifrot/php-ixr/src/Message/Message.php | 210 +++ .../kissifrot/php-ixr/src/Request/Request.php | 48 + .../php-ixr/src/Server/ClassServer.php | 98 ++ .../src/Server/IntrospectionServer.php | 171 +++ .../kissifrot/php-ixr/src/Server/Server.php | 190 +++ 34 files changed, 2316 insertions(+), 1796 deletions(-) delete mode 100644 _test/tests/inc/ixr_library_date.test.php delete mode 100644 _test/tests/inc/ixr_library_ixr_message.test.php delete mode 100644 inc/IXR_Library.php create mode 100644 inc/Remote/IXR/Client.php create mode 100644 vendor/kissifrot/php-ixr/.editorconfig create mode 100644 vendor/kissifrot/php-ixr/.gitignore create mode 100644 vendor/kissifrot/php-ixr/LICENSE.txt create mode 100644 vendor/kissifrot/php-ixr/README.md create mode 100644 vendor/kissifrot/php-ixr/composer.json create mode 100644 vendor/kissifrot/php-ixr/src/Client/Client.php create mode 100644 vendor/kissifrot/php-ixr/src/Client/ClientMulticall.php create mode 100644 vendor/kissifrot/php-ixr/src/Client/ClientSSL.php create mode 100644 vendor/kissifrot/php-ixr/src/DataType/Base64.php create mode 100644 vendor/kissifrot/php-ixr/src/DataType/Date.php create mode 100644 vendor/kissifrot/php-ixr/src/DataType/Value.php create mode 100644 vendor/kissifrot/php-ixr/src/Exception/ClientException.php create mode 100644 vendor/kissifrot/php-ixr/src/Exception/ServerException.php create mode 100644 vendor/kissifrot/php-ixr/src/Message/Error.php create mode 100644 vendor/kissifrot/php-ixr/src/Message/Message.php create mode 100644 vendor/kissifrot/php-ixr/src/Request/Request.php create mode 100644 vendor/kissifrot/php-ixr/src/Server/ClassServer.php create mode 100644 vendor/kissifrot/php-ixr/src/Server/IntrospectionServer.php create mode 100644 vendor/kissifrot/php-ixr/src/Server/Server.php diff --git a/_test/tests/inc/XmlRpcServer.test.php b/_test/tests/inc/XmlRpcServer.test.php index 6d5dffc76..3b50c4de5 100644 --- a/_test/tests/inc/XmlRpcServer.test.php +++ b/_test/tests/inc/XmlRpcServer.test.php @@ -33,13 +33,13 @@ class XmlRpcServerTest extends DokuWikiTest $pageName = ":wiki:dokuwiki"; $file = wikiFN($pageName); $timestamp = filemtime($file); - $ixrModifiedTime = (new DateTime('@' . $timestamp))->format(IXR_Date::XMLRPC_ISO8601); + $ixrModifiedTime = (new DateTime('@' . $timestamp))->format(DateTime::ATOM); $request = << wiki.getPageInfo - + $pageName @@ -64,6 +64,6 @@ EOD; EOD; $this->server->serve($request); - $this->assertEquals(trim($expected), trim($this->server->output)); + $this->assertXmlStringEqualsXmlString(trim($expected), trim($this->server->output)); } } diff --git a/_test/tests/inc/ixr_library_date.test.php b/_test/tests/inc/ixr_library_date.test.php deleted file mode 100644 index 0c81e6741..000000000 --- a/_test/tests/inc/ixr_library_date.test.php +++ /dev/null @@ -1,44 +0,0 @@ -assertEquals($test[1], $dt->getTimeStamp()); - } - } - -} -//Setup VIM: ex: et ts=4 : diff --git a/_test/tests/inc/ixr_library_ixr_message.test.php b/_test/tests/inc/ixr_library_ixr_message.test.php deleted file mode 100644 index b8afd607e..000000000 --- a/_test/tests/inc/ixr_library_ixr_message.test.php +++ /dev/null @@ -1,134 +0,0 @@ -wiki.getBackLinks change '; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.getBackLinks'); - $this->assertEquals($ixrmsg->params,array(' change ')); - } - - function test_untypedvalue2(){ - $xml = ' - - wiki.getBackLinks - - - change - - - '; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.getBackLinks'); - $this->assertEquals($ixrmsg->params,array(' change ')); - } - - function test_stringvalue1(){ - $xml = 'wiki.getBackLinks change '; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.getBackLinks'); - $this->assertEquals($ixrmsg->params,array(' change ')); - } - - function test_stringvalue2(){ - $xml = ' - - wiki.getBackLinks - - - - change - - - - '; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.getBackLinks'); - $this->assertEquals($ixrmsg->params,array(' change ')); - } - - function test_emptyvalue1(){ - $xml = 'wiki.getBackLinks'; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.getBackLinks'); - $this->assertEquals($ixrmsg->params,array('')); - } - - function test_emptyvalue2(){ - $xml = ' - - wiki.getBackLinks - - - - - - - - '; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.getBackLinks'); - $this->assertEquals($ixrmsg->params,array('')); - } - - function test_struct(){ - $xml = ' - - wiki.putPage - - - start - - - test text - - - - - sum - xmlrpc edit - - - minor - 1 - - - - - '; - - $ixrmsg = new IXR_Message($xml); - $ixrmsg->parse(); - - $this->assertEquals($ixrmsg->messageType,'methodCall'); - $this->assertEquals($ixrmsg->methodName,'wiki.putPage'); - $this->assertEquals($ixrmsg->params,array('start','test text',array('sum'=>'xmlrpc edit','minor'=>'1'))); - } - -} -//Setup VIM: ex: et ts=4 : diff --git a/composer.json b/composer.json index 8e0aa40c6..4a46d7768 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "aziraphale/email-address-validator": "^2", "marcusschwarz/lesserphp": "^0.5.1", "splitbrain/php-cli": "^1.1", - "splitbrain/slika": "^1.0" + "splitbrain/slika": "^1.0", + "kissifrot/php-ixr": "^1.8" }, "config": { "platform": { diff --git a/composer.lock b/composer.lock index b7edcabc9..1a446b3e0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cd951937a517d2f058327d0429efe7ff", + "content-hash": "09f5f3726c3993d80980df99ab2a59dc", "packages": [ { "name": "aziraphale/email-address-validator", @@ -98,6 +98,53 @@ }, "time": "2020-06-22T15:46:04+00:00" }, + { + "name": "kissifrot/php-ixr", + "version": "1.8.3", + "source": { + "type": "git", + "url": "https://github.com/kissifrot/php-ixr.git", + "reference": "4477cd1a67416ce5b6a2080f9a79d9eb50a965c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kissifrot/php-ixr/zipball/4477cd1a67416ce5b6a2080f9a79d9eb50a965c1", + "reference": "4477cd1a67416ce5b6a2080f9a79d9eb50a965c1", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "IXR\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Incutio Ltd 2010 - Simon Willison", + "homepage": "http://scripts.incutio.com/xmlrpc/" + } + ], + "description": "Incutio XML-RPC library (IXR)", + "homepage": "http://scripts.incutio.com/xmlrpc/", + "keywords": [ + "remote procedure call", + "rpc", + "xlm-rpc", + "xmlrpc" + ], + "support": { + "issues": "https://github.com/kissifrot/php-ixr/issues", + "source": "https://github.com/kissifrot/php-ixr/tree/master" + }, + "time": "2016-11-17T12:00:18+00:00" + }, { "name": "marcusschwarz/lesserphp", "version": "v0.5.5", @@ -570,5 +617,5 @@ "platform-overrides": { "php": "7.2" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/inc/IXR_Library.php b/inc/IXR_Library.php deleted file mode 100644 index bb1655f10..000000000 --- a/inc/IXR_Library.php +++ /dev/null @@ -1,1135 +0,0 @@ - - */ -class IXR_Value { - - /** @var IXR_Value[]|IXR_Date|IXR_Base64|int|bool|double|string */ - var $data; - /** @var string */ - var $type; - - /** - * @param mixed $data - * @param bool $type - */ - function __construct($data, $type = false) { - $this->data = $data; - if(!$type) { - $type = $this->calculateType(); - } - $this->type = $type; - if($type == 'struct') { - // Turn all the values in the array in to new IXR_Value objects - foreach($this->data as $key => $value) { - $this->data[$key] = new IXR_Value($value); - } - } - if($type == 'array') { - for($i = 0, $j = count($this->data); $i < $j; $i++) { - $this->data[$i] = new IXR_Value($this->data[$i]); - } - } - } - - /** - * @return string - */ - function calculateType() { - if($this->data === true || $this->data === false) { - return 'boolean'; - } - if(is_integer($this->data)) { - return 'int'; - } - if(is_double($this->data)) { - return 'double'; - } - - // Deal with IXR object types base64 and date - if(is_object($this->data) && is_a($this->data, 'IXR_Date')) { - return 'date'; - } - if(is_object($this->data) && is_a($this->data, 'IXR_Base64')) { - return 'base64'; - } - - // If it is a normal PHP object convert it in to a struct - if(is_object($this->data)) { - $this->data = get_object_vars($this->data); - return 'struct'; - } - if(!is_array($this->data)) { - return 'string'; - } - - // We have an array - is it an array or a struct? - if($this->isStruct($this->data)) { - return 'struct'; - } else { - return 'array'; - } - } - - /** - * @return bool|string - */ - function getXml() { - // Return XML for this value - switch($this->type) { - case 'boolean': - return '' . (($this->data) ? '1' : '0') . ''; - break; - case 'int': - return '' . $this->data . ''; - break; - case 'double': - return '' . $this->data . ''; - break; - case 'string': - return '' . htmlspecialchars($this->data) . ''; - break; - case 'array': - $return = '' . "\n"; - foreach($this->data as $item) { - $return .= ' ' . $item->getXml() . "\n"; - } - $return .= ''; - return $return; - break; - case 'struct': - $return = '' . "\n"; - foreach($this->data as $name => $value) { - $return .= " $name"; - $return .= $value->getXml() . "\n"; - } - $return .= ''; - return $return; - break; - case 'date': - case 'base64': - return $this->data->getXml(); - break; - } - return false; - } - - /** - * Checks whether or not the supplied array is a struct or not - * - * @param array $array - * @return boolean - */ - function isStruct($array) { - $expected = 0; - foreach($array as $key => $value) { - if((string) $key != (string) $expected) { - return true; - } - $expected++; - } - return false; - } -} - -/** - * IXR_MESSAGE - * - * @package IXR - * @since 1.5 - * - */ -class IXR_Message { - var $message; - var $messageType; // methodCall / methodResponse / fault - var $faultCode; - var $faultString; - var $methodName; - var $params; - - // Current variable stacks - var $_arraystructs = array(); // The stack used to keep track of the current array/struct - var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array - var $_currentStructName = array(); // A stack as well - var $_param; - var $_value; - var $_currentTag; - var $_currentTagContents; - var $_lastseen; - // The XML parser - var $_parser; - - /** - * @param string $message - */ - function __construct($message) { - $this->message =& $message; - } - - /** - * @return bool - */ - function parse() { - // first remove the XML declaration - // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages - $header = preg_replace('/<\?xml.*?\?' . '>/', '', substr($this->message, 0, 100), 1); - $this->message = substr_replace($this->message, $header, 0, 100); - - // workaround for a bug in PHP/libxml2, see http://bugs.php.net/bug.php?id=45996 - $this->message = str_replace('<', '<', $this->message); - $this->message = str_replace('>', '>', $this->message); - $this->message = str_replace('&', '&', $this->message); - $this->message = str_replace(''', ''', $this->message); - $this->message = str_replace('"', '"', $this->message); - $this->message = str_replace("\x0b", ' ', $this->message); //vertical tab - if(trim($this->message) == '') { - return false; - } - $this->_parser = xml_parser_create(); - // Set XML parser to take the case of tags in to account - xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); - // Set XML parser callback functions - xml_set_object($this->_parser, $this); - xml_set_element_handler($this->_parser, 'tag_open', 'tag_close'); - xml_set_character_data_handler($this->_parser, 'cdata'); - $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages - $final = false; - do { - if(strlen($this->message) <= $chunk_size) { - $final = true; - } - $part = substr($this->message, 0, $chunk_size); - $this->message = substr($this->message, $chunk_size); - if(!xml_parse($this->_parser, $part, $final)) { - return false; - } - if($final) { - break; - } - } while(true); - xml_parser_free($this->_parser); - - // Grab the error messages, if any - if($this->messageType == 'fault') { - $this->faultCode = $this->params[0]['faultCode']; - $this->faultString = $this->params[0]['faultString']; - } - return true; - } - - /** - * @param $parser - * @param string $tag - * @param $attr - */ - function tag_open($parser, $tag, $attr) { - $this->_currentTagContents = ''; - $this->_currentTag = $tag; - - switch($tag) { - case 'methodCall': - case 'methodResponse': - case 'fault': - $this->messageType = $tag; - break; - /* Deal with stacks of arrays and structs */ - case 'data': // data is to all intents and purposes more interesting than array - $this->_arraystructstypes[] = 'array'; - $this->_arraystructs[] = array(); - break; - case 'struct': - $this->_arraystructstypes[] = 'struct'; - $this->_arraystructs[] = array(); - break; - } - $this->_lastseen = $tag; - } - - /** - * @param $parser - * @param string $cdata - */ - function cdata($parser, $cdata) { - $this->_currentTagContents .= $cdata; - } - - /** - * @param $parser - * @param $tag - */ - function tag_close($parser, $tag) { - $value = null; - $valueFlag = false; - switch($tag) { - case 'int': - case 'i4': - $value = (int) trim($this->_currentTagContents); - $valueFlag = true; - break; - case 'double': - $value = (double) trim($this->_currentTagContents); - $valueFlag = true; - break; - case 'string': - $value = (string) $this->_currentTagContents; - $valueFlag = true; - break; - case 'dateTime.iso8601': - $value = new IXR_Date(trim($this->_currentTagContents)); - $valueFlag = true; - break; - case 'value': - // "If no type is indicated, the type is string." - if($this->_lastseen == 'value') { - $value = (string) $this->_currentTagContents; - $valueFlag = true; - } - break; - case 'boolean': - $value = (boolean) trim($this->_currentTagContents); - $valueFlag = true; - break; - case 'base64': - $value = base64_decode($this->_currentTagContents); - $valueFlag = true; - break; - /* Deal with stacks of arrays and structs */ - case 'data': - case 'struct': - $value = array_pop($this->_arraystructs); - array_pop($this->_arraystructstypes); - $valueFlag = true; - break; - case 'member': - array_pop($this->_currentStructName); - break; - case 'name': - $this->_currentStructName[] = trim($this->_currentTagContents); - break; - case 'methodName': - $this->methodName = trim($this->_currentTagContents); - break; - } - - if($valueFlag) { - if(count($this->_arraystructs) > 0) { - // Add value to struct or array - if($this->_arraystructstypes[count($this->_arraystructstypes) - 1] == 'struct') { - // Add to struct - $this->_arraystructs[count($this->_arraystructs) - 1][$this->_currentStructName[count($this->_currentStructName) - 1]] = $value; - } else { - // Add to array - $this->_arraystructs[count($this->_arraystructs) - 1][] = $value; - } - } else { - // Just add as a parameter - $this->params[] = $value; - } - } - $this->_currentTagContents = ''; - $this->_lastseen = $tag; - } -} - -/** - * IXR_Server - * - * @package IXR - * @since 1.5 - */ -class IXR_Server { - var $data; - /** @var array */ - var $callbacks = array(); - var $message; - /** @var array */ - var $capabilities; - - /** - * @param array|bool $callbacks - * @param bool $data - * @param bool $wait - */ - function __construct($callbacks = false, $data = false, $wait = false) { - $this->setCapabilities(); - if($callbacks) { - $this->callbacks = $callbacks; - } - $this->setCallbacks(); - - if(!$wait) { - $this->serve($data); - } - } - - /** - * @param bool|string $data - */ - function serve($data = false) { - if(!$data) { - - $postData = trim(http_get_raw_post_data()); - if(!$postData) { - header('Content-Type: text/plain'); // merged from WP #9093 - die('XML-RPC server accepts POST requests only.'); - } - $data = $postData; - } - $this->message = new IXR_Message($data); - if(!$this->message->parse()) { - $this->error(-32700, 'parse error. not well formed'); - } - if($this->message->messageType != 'methodCall') { - $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall'); - } - $result = $this->call($this->message->methodName, $this->message->params); - - // Is the result an error? - if(is_a($result, 'IXR_Error')) { - $this->error($result); - } - - // Encode the result - $r = new IXR_Value($result); - $resultxml = $r->getXml(); - - // Create the XML - $xml = << - - - - $resultxml - - - - - -EOD; - // Send it - $this->output($xml); - } - - /** - * @param string $methodname - * @param array $args - * @return IXR_Error|mixed - */ - function call($methodname, $args) { - if(!$this->hasMethod($methodname)) { - return new IXR_Error(-32601, 'server error. requested method ' . $methodname . ' does not exist.'); - } - $method = $this->callbacks[$methodname]; - - // Perform the callback and send the response - - # Removed for DokuWiki to have a more consistent interface - # if (count($args) == 1) { - # // If only one parameter just send that instead of the whole array - # $args = $args[0]; - # } - - # Adjusted for DokuWiki to use call_user_func_array - - // args need to be an array - $args = (array) $args; - - // Are we dealing with a function or a method? - if(is_string($method) && substr($method, 0, 5) == 'this:') { - // It's a class method - check it exists - $method = substr($method, 5); - if(!method_exists($this, $method)) { - return new IXR_Error(-32601, 'server error. requested class method "' . $method . '" does not exist.'); - } - // Call the method - #$result = $this->$method($args); - $result = call_user_func_array(array(&$this, $method), $args); - } elseif(substr($method, 0, 7) == 'plugin:') { - list($pluginname, $callback) = explode(':', substr($method, 7), 2); - if(!plugin_isdisabled($pluginname)) { - $plugin = plugin_load('action', $pluginname); - return call_user_func_array(array($plugin, $callback), $args); - } else { - return new IXR_Error(-99999, 'server error'); - } - } else { - // It's a function - does it exist? - if(is_array($method)) { - if(!is_callable(array($method[0], $method[1]))) { - return new IXR_Error(-32601, 'server error. requested object method "' . $method[1] . '" does not exist.'); - } - } else if(!function_exists($method)) { - return new IXR_Error(-32601, 'server error. requested function "' . $method . '" does not exist.'); - } - - // Call the function - $result = call_user_func($method, $args); - } - return $result; - } - - /** - * @param int $error - * @param string|bool $message - */ - function error($error, $message = false) { - // Accepts either an error object or an error code and message - if($message && !is_object($error)) { - $error = new IXR_Error($error, $message); - } - $this->output($error->getXml()); - } - - /** - * @param string $xml - */ - function output($xml) { - header('Content-Type: text/xml; charset=utf-8'); - echo '', "\n", $xml; - exit; - } - - /** - * @param string $method - * @return bool - */ - function hasMethod($method) { - return in_array($method, array_keys($this->callbacks)); - } - - function setCapabilities() { - // Initialises capabilities array - $this->capabilities = array( - 'xmlrpc' => array( - 'specUrl' => 'http://www.xmlrpc.com/spec', - 'specVersion' => 1 - ), - 'faults_interop' => array( - 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', - 'specVersion' => 20010516 - ), - 'system.multicall' => array( - 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', - 'specVersion' => 1 - ), - ); - } - - /** - * @return mixed - */ - function getCapabilities() { - return $this->capabilities; - } - - function setCallbacks() { - $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; - $this->callbacks['system.listMethods'] = 'this:listMethods'; - $this->callbacks['system.multicall'] = 'this:multiCall'; - } - - /** - * @return array - */ - function listMethods() { - // Returns a list of methods - uses array_reverse to ensure user defined - // methods are listed before server defined methods - return array_reverse(array_keys($this->callbacks)); - } - - /** - * @param array $methodcalls - * @return array - */ - function multiCall($methodcalls) { - // See http://www.xmlrpc.com/discuss/msgReader$1208 - $return = array(); - foreach($methodcalls as $call) { - $method = $call['methodName']; - $params = $call['params']; - if($method == 'system.multicall') { - $result = new IXR_Error(-32800, 'Recursive calls to system.multicall are forbidden'); - } else { - $result = $this->call($method, $params); - } - if(is_a($result, 'IXR_Error')) { - $return[] = array( - 'faultCode' => $result->code, - 'faultString' => $result->message - ); - } else { - $return[] = array($result); - } - } - return $return; - } -} - -/** - * IXR_Request - * - * @package IXR - * @since 1.5 - */ -class IXR_Request { - /** @var string */ - var $method; - /** @var array */ - var $args; - /** @var string */ - var $xml; - - /** - * @param string $method - * @param array $args - */ - function __construct($method, $args) { - $this->method = $method; - $this->args = $args; - $this->xml = << - -{$this->method} - - -EOD; - foreach($this->args as $arg) { - $this->xml .= ''; - $v = new IXR_Value($arg); - $this->xml .= $v->getXml(); - $this->xml .= "\n"; - } - $this->xml .= ''; - } - - /** - * @return int - */ - function getLength() { - return strlen($this->xml); - } - - /** - * @return string - */ - function getXml() { - return $this->xml; - } -} - -/** - * IXR_Client - * - * @package IXR - * @since 1.5 - * - * Changed for DokuWiki to use DokuHTTPClient - * - * This should be compatible to the original class, but uses DokuWiki's - * HTTP client library which will respect proxy settings - * - * Because the XMLRPC client is not used in DokuWiki currently this is completely - * untested - */ -class IXR_Client extends DokuHTTPClient { - var $posturl = ''; - /** @var IXR_Message|bool */ - var $message = false; - - // Storage place for an error message - /** @var IXR_Error|bool */ - var $xmlerror = false; - - /** - * @param string $server - * @param string|bool $path - * @param int $port - * @param int $timeout - */ - function __construct($server, $path = false, $port = 80, $timeout = 15) { - parent::__construct(); - if(!$path) { - // Assume we have been given a URL instead - $this->posturl = $server; - } else { - $this->posturl = 'http://' . $server . ':' . $port . $path; - } - $this->timeout = $timeout; - } - - /** - * parameters: method and arguments - * @return bool success or error - */ - function query() { - $args = func_get_args(); - $method = array_shift($args); - $request = new IXR_Request($method, $args); - $xml = $request->getXml(); - - $this->headers['Content-Type'] = 'text/xml'; - if(!$this->sendRequest($this->posturl, $xml, 'POST')) { - $this->xmlerror = new IXR_Error(-32300, 'transport error - ' . $this->error); - return false; - } - - // Check HTTP Response code - if($this->status < 200 || $this->status > 206) { - $this->xmlerror = new IXR_Error(-32300, 'transport error - HTTP status ' . $this->status); - return false; - } - - // Now parse what we've got back - $this->message = new IXR_Message($this->resp_body); - if(!$this->message->parse()) { - // XML error - $this->xmlerror = new IXR_Error(-32700, 'parse error. not well formed'); - return false; - } - - // Is the message a fault? - if($this->message->messageType == 'fault') { - $this->xmlerror = new IXR_Error($this->message->faultCode, $this->message->faultString); - return false; - } - - // Message must be OK - return true; - } - - /** - * @return mixed - */ - function getResponse() { - // methodResponses can only have one param - return that - return $this->message->params[0]; - } - - /** - * @return bool - */ - function isError() { - return (is_object($this->xmlerror)); - } - - /** - * @return int - */ - function getErrorCode() { - return $this->xmlerror->code; - } - - /** - * @return string - */ - function getErrorMessage() { - return $this->xmlerror->message; - } -} - -/** - * IXR_Error - * - * @package IXR - * @since 1.5 - */ -class IXR_Error { - var $code; - var $message; - - /** - * @param int $code - * @param string $message - */ - function __construct($code, $message) { - $this->code = $code; - $this->message = htmlspecialchars($message); - } - - /** - * @return string - */ - function getXml() { - $xml = << - - - - - faultCode - {$this->code} - - - faultString - {$this->message} - - - - - - -EOD; - return $xml; - } -} - -/** - * IXR_Date - * - * @package IXR - * @since 1.5 - */ -class IXR_Date { - - const XMLRPC_ISO8601 = "Ymd\TH:i:sO" ; - /** @var DateTime */ - protected $date; - - /** - * @param int|string $time - */ - public function __construct($time) { - // $time can be a PHP timestamp or an ISO one - if(is_numeric($time)) { - $this->parseTimestamp($time); - } else { - $this->parseIso($time); - } - } - - /** - * Parse unix timestamp - * - * @param int $timestamp - */ - protected function parseTimestamp($timestamp) { - $this->date = new DateTime('@' . $timestamp); - } - - /** - * Parses less or more complete iso dates and much more, if no timezone given assumes UTC - * - * @param string $iso - */ - protected function parseIso($iso) { - $this->date = new DateTime($iso, new DateTimeZone("UTC")); - } - - /** - * Returns date in ISO 8601 format - * - * @return string - */ - public function getIso() { - return $this->date->format(self::XMLRPC_ISO8601); - } - - /** - * Returns date in valid xml - * - * @return string - */ - public function getXml() { - return '' . $this->getIso() . ''; - } - - /** - * Returns Unix timestamp - * - * @return int - */ - function getTimestamp() { - return $this->date->getTimestamp(); - } -} - -/** - * IXR_Base64 - * - * @package IXR - * @since 1.5 - */ -class IXR_Base64 { - var $data; - - /** - * @param string $data - */ - function __construct($data) { - $this->data = $data; - } - - /** - * @return string - */ - function getXml() { - return '' . base64_encode($this->data) . ''; - } -} - -/** - * IXR_IntrospectionServer - * - * @package IXR - * @since 1.5 - */ -class IXR_IntrospectionServer extends IXR_Server { - /** @var array[] */ - var $signatures; - /** @var string[] */ - var $help; - - /** - * Constructor - */ - function __construct() { - $this->setCallbacks(); - $this->setCapabilities(); - $this->capabilities['introspection'] = array( - 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', - 'specVersion' => 1 - ); - $this->addCallback( - 'system.methodSignature', - 'this:methodSignature', - array('array', 'string'), - 'Returns an array describing the return type and required parameters of a method' - ); - $this->addCallback( - 'system.getCapabilities', - 'this:getCapabilities', - array('struct'), - 'Returns a struct describing the XML-RPC specifications supported by this server' - ); - $this->addCallback( - 'system.listMethods', - 'this:listMethods', - array('array'), - 'Returns an array of available methods on this server' - ); - $this->addCallback( - 'system.methodHelp', - 'this:methodHelp', - array('string', 'string'), - 'Returns a documentation string for the specified method' - ); - } - - /** - * @param string $method - * @param string $callback - * @param string[] $args - * @param string $help - */ - function addCallback($method, $callback, $args, $help) { - $this->callbacks[$method] = $callback; - $this->signatures[$method] = $args; - $this->help[$method] = $help; - } - - /** - * @param string $methodname - * @param array $args - * @return IXR_Error|mixed - */ - function call($methodname, $args) { - // Make sure it's in an array - if($args && !is_array($args)) { - $args = array($args); - } - - // Over-rides default call method, adds signature check - if(!$this->hasMethod($methodname)) { - return new IXR_Error(-32601, 'server error. requested method "' . $this->message->methodName . '" not specified.'); - } - $method = $this->callbacks[$methodname]; - $signature = $this->signatures[$methodname]; - $returnType = array_shift($signature); - // Check the number of arguments. Check only, if the minimum count of parameters is specified. More parameters are possible. - // This is a hack to allow optional parameters... - if(count($args) < count($signature)) { - // print 'Num of args: '.count($args).' Num in signature: '.count($signature); - return new IXR_Error(-32602, 'server error. wrong number of method parameters'); - } - - // Check the argument types - $ok = true; - $argsbackup = $args; - for($i = 0, $j = count($args); $i < $j; $i++) { - $arg = array_shift($args); - $type = array_shift($signature); - switch($type) { - case 'int': - case 'i4': - if(is_array($arg) || !is_int($arg)) { - $ok = false; - } - break; - case 'base64': - case 'string': - if(!is_string($arg)) { - $ok = false; - } - break; - case 'boolean': - if($arg !== false && $arg !== true) { - $ok = false; - } - break; - case 'float': - case 'double': - if(!is_float($arg)) { - $ok = false; - } - break; - case 'date': - case 'dateTime.iso8601': - if(!is_a($arg, 'IXR_Date')) { - $ok = false; - } - break; - } - if(!$ok) { - return new IXR_Error(-32602, 'server error. invalid method parameters'); - } - } - // It passed the test - run the "real" method call - return parent::call($methodname, $argsbackup); - } - - /** - * @param string $method - * @return array|IXR_Error - */ - function methodSignature($method) { - if(!$this->hasMethod($method)) { - return new IXR_Error(-32601, 'server error. requested method "' . $method . '" not specified.'); - } - // We should be returning an array of types - $types = $this->signatures[$method]; - $return = array(); - foreach($types as $type) { - switch($type) { - case 'string': - $return[] = 'string'; - break; - case 'int': - case 'i4': - $return[] = 42; - break; - case 'double': - $return[] = 3.1415; - break; - case 'dateTime.iso8601': - $return[] = new IXR_Date(time()); - break; - case 'boolean': - $return[] = true; - break; - case 'base64': - $return[] = new IXR_Base64('base64'); - break; - case 'array': - $return[] = array('array'); - break; - case 'struct': - $return[] = array('struct' => 'struct'); - break; - } - } - return $return; - } - - /** - * @param string $method - * @return mixed - */ - function methodHelp($method) { - return $this->help[$method]; - } -} - -/** - * IXR_ClientMulticall - * - * @package IXR - * @since 1.5 - */ -class IXR_ClientMulticall extends IXR_Client { - - /** @var array[] */ - var $calls = array(); - - /** - * @param string $server - * @param string|bool $path - * @param int $port - */ - function __construct($server, $path = false, $port = 80) { - parent::__construct($server, $path, $port); - //$this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)'; - } - - /** - * Add a call - */ - function addCall() { - $args = func_get_args(); - $methodName = array_shift($args); - $struct = array( - 'methodName' => $methodName, - 'params' => $args - ); - $this->calls[] = $struct; - } - - /** - * @return bool - */ - function query() { - // Prepare multicall, then call the parent::query() method - return parent::query('system.multicall', $this->calls); - } -} - diff --git a/inc/Remote/IXR/Client.php b/inc/Remote/IXR/Client.php new file mode 100644 index 000000000..6c34df5d0 --- /dev/null +++ b/inc/Remote/IXR/Client.php @@ -0,0 +1,88 @@ +posturl = $server; + } else { + $this->posturl = 'http://' . $server . ':' . $port . $path; + } + + $this->httpClient = new HTTPClient(); + $this->httpClient->timeout = $timeout; + } + + /** @inheritdoc */ + public function query() + { + $args = func_get_args(); + $method = array_shift($args); + $request = new Request($method, $args); + $length = $request->getLength(); + $xml = $request->getXml(); + + $this->headers['Content-Type'] = 'text/xml'; + $this->headers['Content-Length'] = $length; + $this->httpClient->headers = array_merge($this->httpClient->headers, $this->headers); + + if (!$this->httpClient->sendRequest($this->posturl, $xml, 'POST')) { + $this->handleError(-32300, 'transport error - ' . $this->httpClient->error); + return false; + } + + // Check HTTP Response code + if ($this->httpClient->status < 200 || $this->httpClient->status > 206) { + $this->handleError(-32300, 'transport error - HTTP status ' . $this->httpClient->status); + return false; + } + + // Now parse what we've got back + $this->message = new Message($this->httpClient->resp_body); + if (!$this->message->parse()) { + // XML error + return $this->handleError(-32700, 'Parse error. Message not well formed'); + } + + // Is the message a fault? + if ($this->message->messageType == 'fault') { + return $this->handleError($this->message->faultCode, $this->message->faultString); + } + + // Message must be OK + return true; + } + + /** + * Direct access to the underlying HTTP client if needed + * + * @return HTTPClient + */ + public function getHTTPClient() + { + return $this->httpClient; + } +} diff --git a/inc/Remote/XmlRpcServer.php b/inc/Remote/XmlRpcServer.php index 0a16af1cc..bd70b51b8 100644 --- a/inc/Remote/XmlRpcServer.php +++ b/inc/Remote/XmlRpcServer.php @@ -2,10 +2,15 @@ namespace dokuwiki\Remote; +use IXR\DataType\Base64; +use IXR\DataType\Date; +use IXR\Exception\ServerException; +use IXR\Server\Server; + /** * Contains needed wrapper functions and registers all available XMLRPC functions. */ -class XmlRpcServer extends \IXR_Server +class XmlRpcServer extends Server { protected $remote; @@ -28,34 +33,34 @@ class XmlRpcServer extends \IXR_Server try { $result = $this->remote->call($methodname, $args); return $result; - } /** @noinspection PhpRedundantCatchClauseInspection */ catch (AccessDeniedException $e) { + } catch (AccessDeniedException $e) { if (!isset($_SERVER['REMOTE_USER'])) { http_status(401); - return new \IXR_Error(-32603, "server error. not authorized to call method $methodname"); + return new ServerException("server error. not authorized to call method $methodname", -32603); } else { http_status(403); - return new \IXR_Error(-32604, "server error. forbidden to call the method $methodname"); + return new ServerException("server error. forbidden to call the method $methodname", -32604); } } catch (RemoteException $e) { - return new \IXR_Error($e->getCode(), $e->getMessage()); + return new ServerException($e->getMessage(), $e->getCode()); } } /** * @param string|int $data iso date(yyyy[-]mm[-]dd[ hh:mm[:ss]]) or timestamp - * @return \IXR_Date + * @return Date */ public function toDate($data) { - return new \IXR_Date($data); + return new Date($data); } /** * @param string $data - * @return \IXR_Base64 + * @return Base64 */ public function toFile($data) { - return new \IXR_Base64($data); + return new Base64($data); } } diff --git a/inc/load.php b/inc/load.php index 791f743d7..022ac014f 100644 --- a/inc/load.php +++ b/inc/load.php @@ -65,10 +65,6 @@ function load_autoload($name){ 'JpegMeta' => DOKU_INC.'inc/JpegMeta.php', 'SimplePie' => DOKU_INC.'inc/SimplePie.php', 'FeedParser' => DOKU_INC.'inc/FeedParser.php', - 'IXR_Server' => DOKU_INC.'inc/IXR_Library.php', - 'IXR_Client' => DOKU_INC.'inc/IXR_Library.php', - 'IXR_Error' => DOKU_INC.'inc/IXR_Library.php', - 'IXR_IntrospectionServer' => DOKU_INC.'inc/IXR_Library.php', 'SafeFN' => DOKU_INC.'inc/SafeFN.class.php', 'Sitemapper' => DOKU_INC.'inc/Sitemapper.php', 'Mailer' => DOKU_INC.'inc/Mailer.class.php', diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index 247294d66..0cd6055d1 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -42,30 +42,75 @@ namespace Composer\Autoload; */ class ClassLoader { + /** @var ?string */ private $vendorDir; // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr4 = array(); // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr0 = array(); + /** @var bool */ private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ private $classMap = array(); + + /** @var bool */ private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ private $missingClasses = array(); + + /** @var ?string */ private $apcuPrefix; + /** + * @var self[] + */ private static $registeredLoaders = array(); + /** + * @param ?string $vendorDir + */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; } + /** + * @return string[] + */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { @@ -75,28 +120,47 @@ class ClassLoader return array(); } + /** + * @return array[] + * @psalm-return array> + */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } + /** + * @return string[] Array of classname => path + * @psalm-var array + */ public function getClassMap() { return $this->classMap; } /** - * @param array $classMap Class to filename map + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void */ public function addClassMap(array $classMap) { @@ -111,9 +175,11 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void */ public function add($prefix, $paths, $prepend = false) { @@ -156,11 +222,13 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException + * + * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -204,8 +272,10 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void */ public function set($prefix, $paths) { @@ -220,10 +290,12 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException + * + * @return void */ public function setPsr4($prefix, $paths) { @@ -243,6 +315,8 @@ class ClassLoader * Turns on searching the include path for class files. * * @param bool $useIncludePath + * + * @return void */ public function setUseIncludePath($useIncludePath) { @@ -265,6 +339,8 @@ class ClassLoader * that have not been registered with the class map. * * @param bool $classMapAuthoritative + * + * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -285,6 +361,8 @@ class ClassLoader * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix + * + * @return void */ public function setApcuPrefix($apcuPrefix) { @@ -305,6 +383,8 @@ class ClassLoader * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void */ public function register($prepend = false) { @@ -324,6 +404,8 @@ class ClassLoader /** * Unregisters this instance as an autoloader. + * + * @return void */ public function unregister() { @@ -338,7 +420,7 @@ class ClassLoader * Loads the given class or interface. * * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { @@ -347,6 +429,8 @@ class ClassLoader return true; } + + return null; } /** @@ -401,6 +485,11 @@ class ClassLoader return self::$registeredLoaders; } + /** + * @param string $class + * @param string $ext + * @return string|false + */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -472,6 +561,10 @@ class ClassLoader * Scope isolated include. * * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private */ function includeFile($file) { diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 4910e1b21..7c5502ca4 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -1,366 +1,337 @@ + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Composer; use Composer\Autoload\ClassLoader; use Composer\Semver\VersionParser; - - - - - +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + */ class InstalledVersions { -private static $installed = array ( - 'root' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - ), - 'reference' => '4ee6ddae660f9ec72c1f6e2ddb72d6b29d6d8900', - 'name' => 'splitbrain/dokuwiki', - ), - 'versions' => - array ( - 'aziraphale/email-address-validator' => - array ( - 'pretty_version' => '2.0.1', - 'version' => '2.0.1.0', - 'aliases' => - array ( - ), - 'reference' => 'fa25bc22c1c0b6491657c91473fae3e40719a650', - ), - 'geshi/geshi' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - 0 => '1.0.x-dev', - 1 => '9999999-dev', - ), - 'reference' => '3c12a7931d509c5e3557c5ed44c9a32e9c917c7d', - ), - 'marcusschwarz/lesserphp' => - array ( - 'pretty_version' => 'v0.5.5', - 'version' => '0.5.5.0', - 'aliases' => - array ( - ), - 'reference' => '77ba82b5218ff228267d3b0e5ec8697be75e86a7', - ), - 'openpsa/universalfeedcreator' => - array ( - 'pretty_version' => 'v1.8.4', - 'version' => '1.8.4.0', - 'aliases' => - array ( - ), - 'reference' => '099817dc9efef33ca2382b04daf9e191b77fed13', - ), - 'phpseclib/phpseclib' => - array ( - 'pretty_version' => '2.0.31', - 'version' => '2.0.31.0', - 'aliases' => - array ( - ), - 'reference' => '233a920cb38636a43b18d428f9a8db1f0a1a08f4', - ), - 'simplepie/simplepie' => - array ( - 'pretty_version' => '1.5.6', - 'version' => '1.5.6.0', - 'aliases' => - array ( - ), - 'reference' => '1c68e14ca3ac84346b6e6fe3c5eedf725d0f92c6', - ), - 'splitbrain/dokuwiki' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - ), - 'reference' => '4ee6ddae660f9ec72c1f6e2ddb72d6b29d6d8900', - ), - 'splitbrain/php-archive' => - array ( - 'pretty_version' => '1.2.1', - 'version' => '1.2.1.0', - 'aliases' => - array ( - ), - 'reference' => '211a2198b73b233d7d2b6159462e11cd9a91348a', - ), - 'splitbrain/php-cli' => - array ( - 'pretty_version' => '1.1.8', - 'version' => '1.1.8.0', - 'aliases' => - array ( - ), - 'reference' => '8c2c001b1b55d194402cf18aad2757049ac6d575', - ), - 'splitbrain/slika' => - array ( - 'pretty_version' => '1.0.4', - 'version' => '1.0.4.0', - 'aliases' => - array ( - ), - 'reference' => 'fda87e816eb150f3608282da962788b4ad509c11', - ), - ), -); -private static $canGetVendors; -private static $installedByVendor = array(); + private static $installed; + private static $canGetVendors; + private static $installedByVendor = array(); + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + if (1 === \count($packages)) { + return $packages[0]; + } + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + return $packagesByType; + } -public static function getInstalledPackages() -{ -$packages = array(); -foreach (self::getInstalled() as $installed) { -$packages[] = array_keys($installed['versions']); -} - - -if (1 === \count($packages)) { -return $packages[0]; -} - -return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); -} - - - - - - - - - -public static function isInstalled($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (isset($installed['versions'][$packageName])) { -return true; -} -} - -return false; -} - - - - - - - - - - - - - - -public static function satisfies(VersionParser $parser, $packageName, $constraint) -{ -$constraint = $parser->parseConstraints($constraint); -$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); - -return $provided->matches($constraint); -} - - - - - - - - - - -public static function getVersionRanges($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -$ranges = array(); -if (isset($installed['versions'][$packageName]['pretty_version'])) { -$ranges[] = $installed['versions'][$packageName]['pretty_version']; -} -if (array_key_exists('aliases', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); -} -if (array_key_exists('replaced', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); -} -if (array_key_exists('provided', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); -} - -return implode(' || ', $ranges); -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getVersion($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['version'])) { -return null; -} - -return $installed['versions'][$packageName]['version']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getPrettyVersion($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['pretty_version'])) { -return null; -} - -return $installed['versions'][$packageName]['pretty_version']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getReference($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['reference'])) { -return null; -} - -return $installed['versions'][$packageName]['reference']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getRootPackage() -{ -$installed = self::getInstalled(); - -return $installed[0]['root']; -} - - - - - - - -public static function getRawData() -{ -return self::$installed; -} - - - - - - - - - - - - - - - - - - - -public static function reload($data) -{ -self::$installed = $data; -self::$installedByVendor = array(); -} - - - - -private static function getInstalled() -{ -if (null === self::$canGetVendors) { -self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); -} - -$installed = array(); - -if (self::$canGetVendors) { -foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { -if (isset(self::$installedByVendor[$vendorDir])) { -$installed[] = self::$installedByVendor[$vendorDir]; -} elseif (is_file($vendorDir.'/composer/installed.php')) { -$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; -} -} -} - -$installed[] = self::$installed; - -return $installed; -} + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } } diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 855f95f23..a8c2bcb90 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -11,4 +11,5 @@ return array( 'splitbrain\\phpcli\\' => array($vendorDir . '/splitbrain/php-cli/src'), 'splitbrain\\PHPArchive\\' => array($vendorDir . '/splitbrain/php-archive/src'), 'phpseclib\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'), + 'IXR\\' => array($vendorDir . '/kissifrot/php-ixr/src'), ); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 4618df6b3..80a0ea3c7 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -23,6 +23,10 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b array ( 'phpseclib\\' => 10, ), + 'I' => + array ( + 'IXR\\' => 4, + ), ); public static $prefixDirsPsr4 = array ( @@ -46,6 +50,10 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b array ( 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', ), + 'IXR\\' => + array ( + 0 => __DIR__ . '/..' . '/kissifrot/php-ixr/src', + ), ); public static $prefixesPsr0 = array ( diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 86a2915cd..4d635f233 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -87,6 +87,56 @@ "homepage": "http://qbnz.com/highlighter/", "install-path": "../geshi/geshi" }, + { + "name": "kissifrot/php-ixr", + "version": "1.8.3", + "version_normalized": "1.8.3.0", + "source": { + "type": "git", + "url": "https://github.com/kissifrot/php-ixr.git", + "reference": "4477cd1a67416ce5b6a2080f9a79d9eb50a965c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kissifrot/php-ixr/zipball/4477cd1a67416ce5b6a2080f9a79d9eb50a965c1", + "reference": "4477cd1a67416ce5b6a2080f9a79d9eb50a965c1", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "time": "2016-11-17T12:00:18+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "IXR\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Incutio Ltd 2010 - Simon Willison", + "homepage": "http://scripts.incutio.com/xmlrpc/" + } + ], + "description": "Incutio XML-RPC library (IXR)", + "homepage": "http://scripts.incutio.com/xmlrpc/", + "keywords": [ + "remote procedure call", + "rpc", + "xlm-rpc", + "xmlrpc" + ], + "support": { + "issues": "https://github.com/kissifrot/php-ixr/issues", + "source": "https://github.com/kissifrot/php-ixr/tree/master" + }, + "install-path": "../kissifrot/php-ixr" + }, { "name": "marcusschwarz/lesserphp", "version": "v0.5.5", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 57d493fd1..bb130d8d8 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,107 +1,116 @@ - - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( + array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => 'dc2ffedf4d1aa49db448d4fc9029d50705d0c3c6', + 'name' => 'splitbrain/dokuwiki', + 'dev' => true, ), - 'reference' => '4ee6ddae660f9ec72c1f6e2ddb72d6b29d6d8900', - 'name' => 'splitbrain/dokuwiki', - ), - 'versions' => - array ( - 'aziraphale/email-address-validator' => - array ( - 'pretty_version' => '2.0.1', - 'version' => '2.0.1.0', - 'aliases' => - array ( - ), - 'reference' => 'fa25bc22c1c0b6491657c91473fae3e40719a650', + 'versions' => array( + 'aziraphale/email-address-validator' => array( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../aziraphale/email-address-validator', + 'aliases' => array(), + 'reference' => 'fa25bc22c1c0b6491657c91473fae3e40719a650', + 'dev_requirement' => false, + ), + 'geshi/geshi' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'type' => 'library', + 'install_path' => __DIR__ . '/../geshi/geshi', + 'aliases' => array( + 0 => '1.0.x-dev', + 1 => '9999999-dev', + ), + 'reference' => '3c12a7931d509c5e3557c5ed44c9a32e9c917c7d', + 'dev_requirement' => false, + ), + 'kissifrot/php-ixr' => array( + 'pretty_version' => '1.8.3', + 'version' => '1.8.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../kissifrot/php-ixr', + 'aliases' => array(), + 'reference' => '4477cd1a67416ce5b6a2080f9a79d9eb50a965c1', + 'dev_requirement' => false, + ), + 'marcusschwarz/lesserphp' => array( + 'pretty_version' => 'v0.5.5', + 'version' => '0.5.5.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../marcusschwarz/lesserphp', + 'aliases' => array(), + 'reference' => '77ba82b5218ff228267d3b0e5ec8697be75e86a7', + 'dev_requirement' => false, + ), + 'openpsa/universalfeedcreator' => array( + 'pretty_version' => 'v1.8.4', + 'version' => '1.8.4.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../openpsa/universalfeedcreator', + 'aliases' => array(), + 'reference' => '099817dc9efef33ca2382b04daf9e191b77fed13', + 'dev_requirement' => false, + ), + 'phpseclib/phpseclib' => array( + 'pretty_version' => '2.0.31', + 'version' => '2.0.31.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpseclib/phpseclib', + 'aliases' => array(), + 'reference' => '233a920cb38636a43b18d428f9a8db1f0a1a08f4', + 'dev_requirement' => false, + ), + 'simplepie/simplepie' => array( + 'pretty_version' => '1.5.6', + 'version' => '1.5.6.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../simplepie/simplepie', + 'aliases' => array(), + 'reference' => '1c68e14ca3ac84346b6e6fe3c5eedf725d0f92c6', + 'dev_requirement' => false, + ), + 'splitbrain/dokuwiki' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => 'dc2ffedf4d1aa49db448d4fc9029d50705d0c3c6', + 'dev_requirement' => false, + ), + 'splitbrain/php-archive' => array( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../splitbrain/php-archive', + 'aliases' => array(), + 'reference' => '211a2198b73b233d7d2b6159462e11cd9a91348a', + 'dev_requirement' => false, + ), + 'splitbrain/php-cli' => array( + 'pretty_version' => '1.1.8', + 'version' => '1.1.8.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../splitbrain/php-cli', + 'aliases' => array(), + 'reference' => '8c2c001b1b55d194402cf18aad2757049ac6d575', + 'dev_requirement' => false, + ), + 'splitbrain/slika' => array( + 'pretty_version' => '1.0.4', + 'version' => '1.0.4.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../splitbrain/slika', + 'aliases' => array(), + 'reference' => 'fda87e816eb150f3608282da962788b4ad509c11', + 'dev_requirement' => false, + ), ), - 'geshi/geshi' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - 0 => '1.0.x-dev', - 1 => '9999999-dev', - ), - 'reference' => '3c12a7931d509c5e3557c5ed44c9a32e9c917c7d', - ), - 'marcusschwarz/lesserphp' => - array ( - 'pretty_version' => 'v0.5.5', - 'version' => '0.5.5.0', - 'aliases' => - array ( - ), - 'reference' => '77ba82b5218ff228267d3b0e5ec8697be75e86a7', - ), - 'openpsa/universalfeedcreator' => - array ( - 'pretty_version' => 'v1.8.4', - 'version' => '1.8.4.0', - 'aliases' => - array ( - ), - 'reference' => '099817dc9efef33ca2382b04daf9e191b77fed13', - ), - 'phpseclib/phpseclib' => - array ( - 'pretty_version' => '2.0.31', - 'version' => '2.0.31.0', - 'aliases' => - array ( - ), - 'reference' => '233a920cb38636a43b18d428f9a8db1f0a1a08f4', - ), - 'simplepie/simplepie' => - array ( - 'pretty_version' => '1.5.6', - 'version' => '1.5.6.0', - 'aliases' => - array ( - ), - 'reference' => '1c68e14ca3ac84346b6e6fe3c5eedf725d0f92c6', - ), - 'splitbrain/dokuwiki' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - ), - 'reference' => '4ee6ddae660f9ec72c1f6e2ddb72d6b29d6d8900', - ), - 'splitbrain/php-archive' => - array ( - 'pretty_version' => '1.2.1', - 'version' => '1.2.1.0', - 'aliases' => - array ( - ), - 'reference' => '211a2198b73b233d7d2b6159462e11cd9a91348a', - ), - 'splitbrain/php-cli' => - array ( - 'pretty_version' => '1.1.8', - 'version' => '1.1.8.0', - 'aliases' => - array ( - ), - 'reference' => '8c2c001b1b55d194402cf18aad2757049ac6d575', - ), - 'splitbrain/slika' => - array ( - 'pretty_version' => '1.0.4', - 'version' => '1.0.4.0', - 'aliases' => - array ( - ), - 'reference' => 'fda87e816eb150f3608282da962788b4ad509c11', - ), - ), ); diff --git a/vendor/kissifrot/php-ixr/.editorconfig b/vendor/kissifrot/php-ixr/.editorconfig new file mode 100644 index 000000000..427884b20 --- /dev/null +++ b/vendor/kissifrot/php-ixr/.editorconfig @@ -0,0 +1,8 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true diff --git a/vendor/kissifrot/php-ixr/.gitignore b/vendor/kissifrot/php-ixr/.gitignore new file mode 100644 index 000000000..af08cb0d2 --- /dev/null +++ b/vendor/kissifrot/php-ixr/.gitignore @@ -0,0 +1,6 @@ +.project +.idea +.vscode +.phpunit.result.cache +composer.lock +vendor diff --git a/vendor/kissifrot/php-ixr/LICENSE.txt b/vendor/kissifrot/php-ixr/LICENSE.txt new file mode 100644 index 000000000..066028156 --- /dev/null +++ b/vendor/kissifrot/php-ixr/LICENSE.txt @@ -0,0 +1,28 @@ +IXR - The Incutio XML-RPC Library + +Copyright (c) 2010, Incutio Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of Incutio Ltd. nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/kissifrot/php-ixr/README.md b/vendor/kissifrot/php-ixr/README.md new file mode 100644 index 000000000..55165d601 --- /dev/null +++ b/vendor/kissifrot/php-ixr/README.md @@ -0,0 +1,37 @@ +#Incutio XML-RPC library (IXR) + +**Note**: _This is a fork of the original Incutio XML-RPC library (IXR) SVN repo hosted on _ + +All credits go to Incutio. + +**Docs and Homepage:** + +#Introduction + +The Incutio XML-RPC library (IXR) is designed primarily for ease of use. It incorporates both client and server classes, and is designed to hide as much of the workings of XML-RPC from the user as possible. A key feature of the library is automatic type conversion from PHP types to XML-RPC types and vice versa. This should enable developers to write web services with very little knowledge of the underlying XML-RPC standard. + +Don't however be fooled by it's simple surface. The library includes a wide variety of additional XML-RPC specifications and has all of the features required for serious web service implementations. + +#Background / History + +The original XML-RPC library was developed back in 2002 and updated through 2010 by Incutio for a number of projects the company was working on at the time. It has become fairly dated but is still used extensively by a wide range of commercial and open-source projects. +This fork makes it usable on more recent systems (PHP 5.4+ ones) + +#Composer + +A [Composer](http://getcomposer.org/) file has been added to this repository. + +This package is published to [Packagist](https://packagist.org/), but if you don't want to use it simply add + + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/kissifrot/php-ixr" + } + ], + + "require": { + "kissifrot/php-ixr": "1.8.*" + } + +To your composer.json file diff --git a/vendor/kissifrot/php-ixr/composer.json b/vendor/kissifrot/php-ixr/composer.json new file mode 100644 index 000000000..9e8985d09 --- /dev/null +++ b/vendor/kissifrot/php-ixr/composer.json @@ -0,0 +1,27 @@ +{ + "name": "kissifrot/php-ixr", + "type": "library", + "description": "Incutio XML-RPC library (IXR)", + "keywords": ["xmlrpc","xlm-rpc", "remote procedure call", "rpc"], + "homepage": "http://scripts.incutio.com/xmlrpc/", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Incutio Ltd 2010 - Simon Willison", + "homepage": "http://scripts.incutio.com/xmlrpc/" + } + ], + "require": { + "php": ">=5.4.0", + "ext-xml": "*" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "autoload": { + "psr-4": { + "IXR\\tests\\": "tests/", + "IXR\\": "src/" + } + } +} diff --git a/vendor/kissifrot/php-ixr/src/Client/Client.php b/vendor/kissifrot/php-ixr/src/Client/Client.php new file mode 100644 index 000000000..9d13fbe9e --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Client/Client.php @@ -0,0 +1,209 @@ +server = $bits['host']; + $this->port = isset($bits['port']) ? $bits['port'] : 80; + $this->path = isset($bits['path']) ? $bits['path'] : '/'; + + // Make absolutely sure we have a path + if (!$this->path) { + $this->path = '/'; + } + + if (!empty($bits['query'])) { + $this->path .= '?' . $bits['query']; + } + } else { + $this->server = $server; + $this->path = $path; + $this->port = $port; + } + $this->useragent = 'The Incutio XML-RPC PHP Library'; + $this->timeout = $timeout; + $this->timeout_io = $timeout_io; + } + + public function query() + { + $args = func_get_args(); + $method = array_shift($args); + $request = new Request($method, $args); + $length = $request->getLength(); + $xml = $request->getXml(); + $r = "\r\n"; + $request = "POST {$this->path} HTTP/1.0$r"; + + // Merged from WP #8145 - allow custom headers + $this->headers['Host'] = $this->server; + $this->headers['Content-Type'] = 'text/xml'; + $this->headers['User-Agent'] = $this->useragent; + $this->headers['Content-Length'] = $length; + + foreach ($this->headers as $header => $value) { + $request .= "{$header}: {$value}{$r}"; + } + $request .= $r; + + $request .= $xml; + + // Now send the request + if ($this->debug) { + echo '
' . htmlspecialchars($request) . "\n
\n\n"; + } + + if ($this->timeout) { + try { + $fp = fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout); + } catch (\Exception $e) { + $fp = false; + } + } else { + try { + $fp = fsockopen($this->server, $this->port, $errno, $errstr); + } catch (\Exception $e) { + $fp = false; + } + } + if (!$fp) { + return $this->handleError(-32300, 'transport error - could not open socket'); + } + if (null !== $this->timeout_io) { + stream_set_timeout($fp, $this->timeout_io); + } + fputs($fp, $request); + $contents = ''; + $debugContents = ''; + $gotFirstLine = false; + $gettingHeaders = true; + while (!feof($fp)) { + $line = fgets($fp, 4096); + if (!$gotFirstLine) { + // Check line for '200' + if (strstr($line, '200') === false) { + return $this->handleError(-32300, 'transport error - HTTP status code was not 200'); + } + $gotFirstLine = true; + } + if (trim($line) == '') { + $gettingHeaders = false; + } + if (!$gettingHeaders) { + // merged from WP #12559 - remove trim + $contents .= $line; + } + if ($this->debug) { + $debugContents .= $line; + } + } + if ($this->debug) { + echo '
' . htmlspecialchars($debugContents) . "\n
\n\n"; + } + + // Now parse what we've got back + $this->message = new Message($contents); + if (!$this->message->parse()) { + // XML error + return $this->handleError(-32700, 'Parse error. Message not well formed'); + } + + // Is the message a fault? + if ($this->message->messageType == 'fault') { + return $this->handleError($this->message->faultCode, $this->message->faultString); + } + + // Message must be OK + return true; + } + + public function getResponse() + { + // methodResponses can only have one param - return that + return $this->message->params[0]; + } + + public function isError() + { + return (is_object($this->error)); + } + + protected function handleError($errorCode, $errorMessage) + { + $this->error = new Error($errorCode, $errorMessage); + + return false; + } + + public function getError() + { + return $this->error; + } + + public function getErrorCode() + { + return $this->error->code; + } + + public function getErrorMessage() + { + return $this->error->message; + } + + + /** + * Gets the current timeout set for data transfer + * @return int|null + */ + public function getTimeoutIo() + { + return $this->timeout_io; + } + + /** + * Sets the timeout for data transfer + * @param int $timeout_io + * @return $this + */ + public function setTimeoutIo($timeout_io) + { + $this->timeout_io = $timeout_io; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Client/ClientMulticall.php b/vendor/kissifrot/php-ixr/src/Client/ClientMulticall.php new file mode 100644 index 000000000..b54a179bb --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Client/ClientMulticall.php @@ -0,0 +1,36 @@ +useragent = 'The Incutio XML-RPC PHP Library (multicall client)'; + } + + public function addCall() + { + $args = func_get_args(); + $methodName = array_shift($args); + $struct = [ + 'methodName' => $methodName, + 'params' => $args + ]; + $this->calls[] = $struct; + } + + public function query() + { + // Prepare multicall, then call the parent::query() method + return parent::query('system.multicall', $this->calls); + } +} diff --git a/vendor/kissifrot/php-ixr/src/Client/ClientSSL.php b/vendor/kissifrot/php-ixr/src/Client/ClientSSL.php new file mode 100644 index 000000000..7bbd5a551 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Client/ClientSSL.php @@ -0,0 +1,235 @@ + (@link http://blog.griffin.homelinux.org/projects/xmlrpc/) + * @version 0.2.0 26May2005 08:34 +0800 + * @copyright (c) 2004-2005 Jason Stirk + * @package IXR + */ +class ClientSSL extends Client +{ + /** + * Filename of the SSL Client Certificate + * @access private + * @since 0.1.0 + * @var string + */ + private $_certFile; + + /** + * Filename of the SSL CA Certificate + * @access private + * @since 0.1.0 + * @var string + */ + private $_caFile; + + /** + * Filename of the SSL Client Private Key + * @access private + * @since 0.1.0 + * @var string + */ + private $_keyFile; + + /** + * Passphrase to unlock the private key + * @access private + * @since 0.1.0 + * @var string + */ + private $_passphrase; + + /** + * Constructor + * @param string $server URL of the Server to connect to + * @since 0.1.0 + */ + public function __construct($server, $path = false, $port = 443, $timeout = false, $timeout_io = null) + { + parent::__construct($server, $path, $port, $timeout, $timeout_io); + $this->useragent = 'The Incutio XML-RPC PHP Library for SSL'; + + // Set class fields + $this->_certFile = false; + $this->_caFile = false; + $this->_keyFile = false; + $this->_passphrase = ''; + } + + /** + * Set the client side certificates to communicate with the server. + * + * @since 0.1.0 + * @param string $certificateFile Filename of the client side certificate to use + * @param string $keyFile Filename of the client side certificate's private key + * @param string $keyPhrase Passphrase to unlock the private key + * @throws ClientException + */ + public function setCertificate($certificateFile, $keyFile, $keyPhrase = '') + { + // Check the files all exist + if (is_file($certificateFile)) { + $this->_certFile = $certificateFile; + } else { + throw new ClientException('Could not open certificate: ' . $certificateFile); + } + + if (is_file($keyFile)) { + $this->_keyFile = $keyFile; + } else { + throw new ClientException('Could not open private key: ' . $keyFile); + } + + $this->_passphrase = (string)$keyPhrase; + } + + public function setCACertificate($caFile) + { + if (is_file($caFile)) { + $this->_caFile = $caFile; + } else { + throw new ClientException('Could not open CA certificate: ' . $caFile); + } + } + + /** + * Sets the connection timeout (in seconds) + * @param int $newTimeOut Timeout in seconds + * @returns void + * @since 0.1.2 + */ + public function setTimeOut($newTimeOut) + { + $this->timeout = (int)$newTimeOut; + } + + /** + * Returns the connection timeout (in seconds) + * @returns int + * @since 0.1.2 + */ + public function getTimeOut() + { + return $this->timeout; + } + + /** + * Set the query to send to the XML-RPC Server + * @since 0.1.0 + */ + public function query() + { + $args = func_get_args(); + $method = array_shift($args); + $request = new Request($method, $args); + $length = $request->getLength(); + $xml = $request->getXml(); + + $this->debugOutput('
' . htmlspecialchars($xml) . PHP_EOL . '
'); + + //This is where we deviate from the normal query() + //Rather than open a normal sock, we will actually use the cURL + //extensions to make the calls, and handle the SSL stuff. + + $curl = curl_init('https://' . $this->server . $this->path); + + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + + //Since 23Jun2004 (0.1.2) - Made timeout a class field + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $this->timeout); + if (null !== $this->timeout_io) { + curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeout_io); + } + + if ($this->debug) { + curl_setopt($curl, CURLOPT_VERBOSE, 1); + } + + curl_setopt($curl, CURLOPT_HEADER, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $xml); + if($this->port !== 443) { + curl_setopt($curl, CURLOPT_PORT, $this->port); + } + curl_setopt($curl, CURLOPT_HTTPHEADER, [ + "Content-Type: text/xml", + "Content-length: {$length}" + ]); + + // Process the SSL certificates, etc. to use + if (!($this->_certFile === false)) { + // We have a certificate file set, so add these to the cURL handler + curl_setopt($curl, CURLOPT_SSLCERT, $this->_certFile); + curl_setopt($curl, CURLOPT_SSLKEY, $this->_keyFile); + + if ($this->debug) { + $this->debugOutput('SSL Cert at : ' . $this->_certFile); + $this->debugOutput('SSL Key at : ' . $this->_keyFile); + } + + // See if we need to give a passphrase + if (!($this->_passphrase === '')) { + curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $this->_passphrase); + } + + if ($this->_caFile === false) { + // Don't verify their certificate, as we don't have a CA to verify against + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); + } else { + // Verify against a CA + curl_setopt($curl, CURLOPT_CAINFO, $this->_caFile); + } + } + + // Call cURL to do it's stuff and return us the content + $contents = curl_exec($curl); + curl_close($curl); + + // Check for 200 Code in $contents + if (!strstr($contents, '200 OK')) { + //There was no "200 OK" returned - we failed + return $this->handleError(-32300, 'transport error - HTTP status code was not 200'); + } + + if ($this->debug) { + $this->debugOutput('
' . htmlspecialchars($contents) . PHP_EOL . '
'); + } + // Now parse what we've got back + // Since 20Jun2004 (0.1.1) - We need to remove the headers first + // Why I have only just found this, I will never know... + // So, remove everything before the first < + $contents = substr($contents, strpos($contents, '<')); + + $this->message = new Message($contents); + if (!$this->message->parse()) { + // XML error + return $this->handleError(-32700, 'parse error. not well formed'); + } + // Is the message a fault? + if ($this->message->messageType == 'fault') { + return $this->handleError($this->message->faultCode, $this->message->faultString); + } + + // Message must be OK + return true; + } + + /** + * Debug output, if debug is enabled + * @param $message + */ + private function debugOutput($message) + { + if ($this->debug) { + echo $message . PHP_EOL; + } + } +} diff --git a/vendor/kissifrot/php-ixr/src/DataType/Base64.php b/vendor/kissifrot/php-ixr/src/DataType/Base64.php new file mode 100644 index 000000000..647a8193e --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/DataType/Base64.php @@ -0,0 +1,23 @@ +data = $data; + } + + public function getXml() + { + return '' . base64_encode($this->data) . ''; + } +} diff --git a/vendor/kissifrot/php-ixr/src/DataType/Date.php b/vendor/kissifrot/php-ixr/src/DataType/Date.php new file mode 100644 index 000000000..f448b4a48 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/DataType/Date.php @@ -0,0 +1,56 @@ +parseTimestamp($time); + } else { + $this->parseIso($time); + } + } + + private function parseTimestamp($timestamp) + { + $date = new \DateTime(); + $this->dateTime = $date->setTimestamp($timestamp); + } + + /** + * Parses more or less complete iso dates and much more, if no timezone given assumes UTC + * + * @param string $iso + * @throws \Exception when no valid date is given + */ + protected function parseIso($iso) { + $this->dateTime = new \DateTime($iso, new \DateTimeZone('UTC')); + } + + public function getIso() + { + return $this->dateTime->format(\DateTime::ATOM); + } + + public function getXml() + { + return '' . $this->getIso() . ''; + } + + public function getTimestamp() + { + return (int)$this->dateTime->format('U'); + } +} diff --git a/vendor/kissifrot/php-ixr/src/DataType/Value.php b/vendor/kissifrot/php-ixr/src/DataType/Value.php new file mode 100644 index 000000000..f8cbef6b0 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/DataType/Value.php @@ -0,0 +1,121 @@ +data = $data; + if (!$type) { + $type = $this->calculateType(); + } + $this->type = $type; + if ($type === 'struct') { + // Turn all the values in the array in to new IXR_Value objects + foreach ($this->data as $key => $value) { + $this->data[$key] = new Value($value); + } + } + if ($type === 'array') { + for ($i = 0, $j = count($this->data); $i < $j; $i++) { + $this->data[$i] = new Value($this->data[$i]); + } + } + } + + public function calculateType() + { + if ($this->data === true || $this->data === false) { + return 'boolean'; + } + if (is_integer($this->data)) { + return 'int'; + } + if (is_double($this->data)) { + return 'double'; + } + + // Deal with IXR object types base64 and date + if (is_object($this->data) && $this->data instanceof Date) { + return 'date'; + } + if (is_object($this->data) && $this->data instanceof Base64) { + return 'base64'; + } + + // If it is a normal PHP object convert it in to a struct + if (is_object($this->data)) { + $this->data = get_object_vars($this->data); + return 'struct'; + } + if (!is_array($this->data)) { + return 'string'; + } + + // We have an array - is it an array or a struct? + if ($this->isStruct($this->data)) { + return 'struct'; + } else { + return 'array'; + } + } + + public function getXml() + { + // Return XML for this value + switch ($this->type) { + case 'boolean': + return '' . (((bool)$this->data) ? '1' : '0') . ''; + case 'int': + return '' . $this->data . ''; + case 'double': + return '' . $this->data . ''; + case 'string': + return '' . htmlspecialchars($this->data) . ''; + case 'array': + $return = '' . "\n"; + foreach ($this->data as $item) { + $return .= ' ' . $item->getXml() . "\n"; + } + $return .= ''; + return $return; + break; + case 'struct': + $return = '' . "\n"; + foreach ($this->data as $name => $value) { + $name = htmlspecialchars($name); + $return .= " $name"; + $return .= $value->getXml() . "\n"; + } + $return .= ''; + return $return; + case 'date': + case 'base64': + return $this->data->getXml(); + default: + return false; + } + } + + /** + * Checks whether or not the supplied array is a struct or not + * + * @param array $array + * @return boolean + */ + public function isStruct($array) + { + $expected = 0; + foreach ($array as $key => $value) { + if ((string)$key != (string)$expected) { + return true; + } + $expected++; + } + return false; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Exception/ClientException.php b/vendor/kissifrot/php-ixr/src/Exception/ClientException.php new file mode 100644 index 000000000..5fa91a9ae --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Exception/ClientException.php @@ -0,0 +1,9 @@ +code = $code; + $this->message = htmlspecialchars($message); + } + + public function getXml() + { + $xml = << + + + + + faultCode + {$this->code} + + + faultString + {$this->message} + + + + + +EOD; + return $xml; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Message/Message.php b/vendor/kissifrot/php-ixr/src/Message/Message.php new file mode 100644 index 000000000..e8a1d922a --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Message/Message.php @@ -0,0 +1,210 @@ +message =& $message; + } + + public function parse() + { + // first remove the XML declaration + // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages + $header = preg_replace('/<\?xml.*?\?' . '>/s', '', substr($this->message, 0, 100), 1); + $this->message = trim(substr_replace($this->message, $header, 0, 100)); + if ('' == $this->message) { + return false; + } + + // Then remove the DOCTYPE + $header = preg_replace('/^]*+>/i', '', substr($this->message, 0, 200), 1); + $this->message = trim(substr_replace($this->message, $header, 0, 200)); + if ('' == $this->message) { + return false; + } + + // Check that the root tag is valid + $root_tag = substr($this->message, 0, strcspn(substr($this->message, 0, 20), "> \t\r\n")); + if ('message, '<')) { + return false; + } + + $this->_parser = xml_parser_create(); + // Set XML parser to take the case of tags in to account + xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); + // Set XML parser callback functions + xml_set_object($this->_parser, $this); + xml_set_element_handler($this->_parser, 'tagOpen', 'tagClose'); + xml_set_character_data_handler($this->_parser, 'cdata'); + $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages + $final = false; + do { + if (strlen($this->message) <= $chunk_size) { + $final = true; + } + $part = substr($this->message, 0, $chunk_size); + $this->message = substr($this->message, $chunk_size); + if (!xml_parse($this->_parser, $part, $final)) { + return false; + } + if ($final) { + break; + } + } while (true); + xml_parser_free($this->_parser); + + // Grab the error messages, if any + if ($this->messageType === 'fault') { + $this->faultCode = $this->params[0]['faultCode']; + $this->faultString = $this->params[0]['faultString']; + } + return true; + } + + /** + * Opening tag handler + * @param $parser + * @param $tag + * @param $attr + */ + public function tagOpen($parser, $tag, $attr) + { + $this->_currentTagContents = ''; + $this->currentTag = $tag; + switch ($tag) { + case 'methodCall': + case 'methodResponse': + case 'fault': + $this->messageType = $tag; + break; + /* Deal with stacks of arrays and structs */ + case 'data': // data is to all intents and puposes more interesting than array + $this->_arraystructstypes[] = 'array'; + $this->_arraystructs[] = []; + break; + case 'struct': + $this->_arraystructstypes[] = 'struct'; + $this->_arraystructs[] = []; + break; + } + } + + /** + * Character Data handler + * @param $parser + * @param $cdata + */ + public function cdata($parser, $cdata) + { + $this->_currentTagContents .= $cdata; + } + + /** + * Closing tag handler + * @param $parser + * @param $tag + */ + public function tagClose($parser, $tag) + { + $valueFlag = false; + switch ($tag) { + case 'int': + case 'i4': + $value = (int)trim($this->_currentTagContents); + $valueFlag = true; + break; + case 'double': + $value = (double)trim($this->_currentTagContents); + $valueFlag = true; + break; + case 'string': + $value = (string)($this->_currentTagContents); + $valueFlag = true; + break; + case 'dateTime.iso8601': + $value = new Date(trim($this->_currentTagContents)); + $valueFlag = true; + break; + case 'value': + // "If no type is indicated, the type is string." + if (trim($this->_currentTagContents) != '') { + $value = (string)$this->_currentTagContents; + $valueFlag = true; + } + break; + case 'boolean': + $value = (boolean)trim($this->_currentTagContents); + $valueFlag = true; + break; + case 'base64': + $value = base64_decode($this->_currentTagContents); + $valueFlag = true; + break; + /* Deal with stacks of arrays and structs */ + case 'data': + case 'struct': + $value = array_pop($this->_arraystructs); + array_pop($this->_arraystructstypes); + $valueFlag = true; + break; + case 'member': + array_pop($this->_currentStructName); + break; + case 'name': + $this->_currentStructName[] = trim($this->_currentTagContents); + break; + case 'methodName': + $this->methodName = trim($this->_currentTagContents); + break; + } + + if ($valueFlag) { + if (count($this->_arraystructs) > 0) { + // Add value to struct or array + if ($this->_arraystructstypes[count($this->_arraystructstypes) - 1] === 'struct') { + // Add to struct + $this->_arraystructs[count($this->_arraystructs) - 1][$this->_currentStructName[count($this->_currentStructName) - 1]] = $value; + } else { + // Add to array + $this->_arraystructs[count($this->_arraystructs) - 1][] = $value; + } + } else { + // Just add as a paramater + $this->params[] = $value; + } + } + $this->_currentTagContents = ''; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Request/Request.php b/vendor/kissifrot/php-ixr/src/Request/Request.php new file mode 100644 index 000000000..2664fb7a8 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Request/Request.php @@ -0,0 +1,48 @@ +method = $method; + $this->args = $args; + $this->xml = << + +{$this->method} + + +EOD; + foreach ($this->args as $arg) { + $this->xml .= ''; + $v = new Value($arg); + $this->xml .= $v->getXml(); + $this->xml .= "\n"; + } + $this->xml .= ''; + } + + public function getLength() + { + return strlen($this->xml); + } + + public function getXml() + { + return $this->xml; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Server/ClassServer.php b/vendor/kissifrot/php-ixr/src/Server/ClassServer.php new file mode 100644 index 000000000..1b0816429 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Server/ClassServer.php @@ -0,0 +1,98 @@ + + * @version 1.0.1 19Apr2005 17:40 +0800 + * @copyright Copyright (c) 2005 Jason Stirk + * @package IXR + */ +class ClassServer extends Server +{ + + private $_objects; + private $_delim; + + public function __construct($delim = '.', $wait = false) + { + parent::__construct([], false, $wait); + $this->_delim = $delim; + $this->_objects = []; + } + + public function addMethod($rpcName, $functionName) + { + $this->callbacks[$rpcName] = $functionName; + } + + public function registerObject($object, $methods, $prefix = null) + { + if (is_null($prefix)) { + $prefix = get_class($object); + } + $this->_objects[$prefix] = $object; + + // Add to our callbacks array + foreach ($methods as $method) { + if (is_array($method)) { + $targetMethod = $method[0]; + $method = $method[1]; + } else { + $targetMethod = $method; + } + $this->callbacks[$prefix . $this->_delim . $method] = [$prefix, $targetMethod]; + } + } + + public function call($methodname, $args) + { + if (!$this->hasMethod($methodname)) { + return new Error(-32601, 'server error. requested method ' . $methodname . ' does not exist.'); + } + $method = $this->callbacks[$methodname]; + + // Perform the callback and send the response + if (count($args) == 1) { + // If only one paramater just send that instead of the whole array + $args = $args[0]; + } + + // See if this method comes from one of our objects or maybe self + if (is_array($method) || (substr($method, 0, 5) == 'this:')) { + if (is_array($method)) { + $object = $this->_objects[$method[0]]; + $method = $method[1]; + } else { + $object = $this; + $method = substr($method, 5); + } + + // It's a class method - check it exists + if (!method_exists($object, $method)) { + return new Error(-32601, 'server error. requested class method "' . $method . '" does not exist.'); + } + + // Call the method + $result = $object->$method($args); + } else { + // It's a function - does it exist? + if (!function_exists($method)) { + return new Error(-32601, 'server error. requested function "' . $method . '" does not exist.'); + } + + // Call the function + $result = $method($args); + } + return $result; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Server/IntrospectionServer.php b/vendor/kissifrot/php-ixr/src/Server/IntrospectionServer.php new file mode 100644 index 000000000..8557e1fe1 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Server/IntrospectionServer.php @@ -0,0 +1,171 @@ +setCallbacks(); + $this->setCapabilities(); + $this->capabilities['introspection'] = [ + 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', + 'specVersion' => 1 + ]; + $this->addCallback( + 'system.methodSignature', + 'this:methodSignature', + ['array', 'string'], + 'Returns an array describing the return type and required parameters of a method' + ); + $this->addCallback( + 'system.getCapabilities', + 'this:getCapabilities', + ['struct'], + 'Returns a struct describing the XML-RPC specifications supported by this server' + ); + $this->addCallback( + 'system.listMethods', + 'this:listMethods', + ['array'], + 'Returns an array of available methods on this server' + ); + $this->addCallback( + 'system.methodHelp', + 'this:methodHelp', + ['string', 'string'], + 'Returns a documentation string for the specified method' + ); + } + + public function addCallback($method, $callback, $args, $help) + { + $this->callbacks[$method] = $callback; + $this->signatures[$method] = $args; + $this->help[$method] = $help; + } + + public function call($methodname, $args) + { + // Make sure it's in an array + if ($args && !is_array($args)) { + $args = [$args]; + } + + // Over-rides default call method, adds signature check + if (!$this->hasMethod($methodname)) { + return new Error(-32601, + 'server error. requested method "' . $this->message->methodName . '" not specified.'); + } + $method = $this->callbacks[$methodname]; + $signature = $this->signatures[$methodname]; + array_shift($signature); + + // Check the number of arguments + if (count($args) != count($signature)) { + return new Error(-32602, 'server error. wrong number of method parameters'); + } + + // Check the argument types + $ok = true; + $argsbackup = $args; + for ($i = 0, $j = count($args); $i < $j; $i++) { + $arg = array_shift($args); + $type = array_shift($signature); + switch ($type) { + case 'int': + case 'i4': + if (is_array($arg) || !is_int($arg)) { + $ok = false; + } + break; + case 'base64': + case 'string': + if (!is_string($arg)) { + $ok = false; + } + break; + case 'boolean': + if ($arg !== false && $arg !== true) { + $ok = false; + } + break; + case 'float': + case 'double': + if (!is_float($arg)) { + $ok = false; + } + break; + case 'date': + case 'dateTime.iso8601': + if (!($arg instanceof Date)) { + $ok = false; + } + break; + } + if (!$ok) { + return new Error(-32602, 'server error. invalid method parameters'); + } + } + // It passed the test - run the "real" method call + return parent::call($methodname, $argsbackup); + } + + public function methodSignature($method) + { + if (!$this->hasMethod($method)) { + return new Error(-32601, 'server error. requested method "' . $method . '" not specified.'); + } + // We should be returning an array of types + $types = $this->signatures[$method]; + $return = []; + foreach ($types as $type) { + switch ($type) { + case 'string': + $return[] = 'string'; + break; + case 'int': + case 'i4': + $return[] = 42; + break; + case 'double': + $return[] = 3.1415; + break; + case 'dateTime.iso8601': + $return[] = new Date(time()); + break; + case 'boolean': + $return[] = true; + break; + case 'base64': + $return[] = new Base64('base64'); + break; + case 'array': + $return[] = ['array']; + break; + case 'struct': + $return[] = ['struct' => 'struct']; + break; + } + } + return $return; + } + + public function methodHelp($method) + { + return $this->help[$method]; + } +} diff --git a/vendor/kissifrot/php-ixr/src/Server/Server.php b/vendor/kissifrot/php-ixr/src/Server/Server.php new file mode 100644 index 000000000..694c48a39 --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Server/Server.php @@ -0,0 +1,190 @@ +setCapabilities(); + if ($callbacks) { + $this->callbacks = $callbacks; + } + $this->setCallbacks(); + if (!$wait) { + $this->serve($data); + } + } + + public function serve($data = false) + { + if (!$data) { + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Content-Type: text/plain'); // merged from WP #9093 + throw new ServerException('XML-RPC server accepts POST requests only.'); + } + + $data = file_get_contents('php://input'); + } + $this->message = new Message($data); + if (!$this->message->parse()) { + $this->error(-32700, 'parse error. not well formed'); + } + if ($this->message->messageType != 'methodCall') { + $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall'); + } + $result = $this->call($this->message->methodName, $this->message->params); + + // Is the result an error? + if ($result instanceof Error) { + $this->error($result); + } + + // Encode the result + $r = new Value($result); + $resultxml = $r->getXml(); + + // Create the XML + $xml = << + + + + $resultxml + + + + + +EOD; + // Send it + $this->output($xml); + } + + protected function call($methodname, $args) + { + if (!$this->hasMethod($methodname)) { + return new Error(-32601, 'server error. requested method ' . $methodname . ' does not exist.'); + } + $method = $this->callbacks[$methodname]; + // Perform the callback and send the response + + if (is_array($args) && count($args) == 1) { + // If only one parameter just send that instead of the whole array + $args = $args[0]; + } + + try { + // Are we dealing with a function or a method? + if (is_string($method) && substr($method, 0, 5) === 'this:') { + // It's a class method - check it exists + $method = substr($method, 5); + + return $this->$method($args); + } + + return call_user_func($method, $args); + } catch (\BadFunctionCallException $exception) { + return new Error(-32601, "server error. requested callable '{$method}' does not exist."); + } + + } + + public function error($error, $message = false) + { + // Accepts either an error object or an error code and message + if ($message && !is_object($error)) { + $error = new Error($error, $message); + } + $this->output($error->getXml()); + } + + public function output($xml) + { + $xml = '' . "\n" . $xml; + $length = strlen($xml); + header('Connection: close'); + header('Content-Length: ' . $length); + header('Content-Type: text/xml'); + header('Date: ' . date('r')); + echo $xml; + exit; + } + + protected function hasMethod($method) + { + return in_array($method, array_keys($this->callbacks)); + } + + protected function setCapabilities() + { + // Initialises capabilities array + $this->capabilities = [ + 'xmlrpc' => [ + 'specUrl' => 'http://www.xmlrpc.com/spec', + 'specVersion' => 1 + ], + 'faults_interop' => [ + 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', + 'specVersion' => 20010516 + ], + 'system.multicall' => [ + 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', + 'specVersion' => 1 + ], + ]; + } + + public function getCapabilities($args) + { + return $this->capabilities; + } + + public function setCallbacks() + { + $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; + $this->callbacks['system.listMethods'] = 'this:listMethods'; + $this->callbacks['system.multicall'] = 'this:multiCall'; + } + + public function listMethods($args) + { + // Returns a list of methods - uses array_reverse to ensure user defined + // methods are listed before server defined methods + return array_reverse(array_keys($this->callbacks)); + } + + public function multiCall($methodcalls) + { + // See http://www.xmlrpc.com/discuss/msgReader$1208 + $return = []; + foreach ($methodcalls as $call) { + $method = $call['methodName']; + $params = $call['params']; + if ($method == 'system.multicall') { + $result = new Error(-32600, 'Recursive calls to system.multicall are forbidden'); + } else { + $result = $this->call($method, $params); + } + if ($result instanceof Error) { + $return[] = [ + 'faultCode' => $result->code, + 'faultString' => $result->message + ]; + } else { + $return[] = [$result]; + } + } + return $return; + } +}