diff options
Diffstat (limited to 'vendor/kissifrot/php-ixr/src')
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Client/Client.php | 209 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Client/ClientMulticall.php | 36 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Client/ClientSSL.php | 235 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/DataType/Base64.php | 23 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/DataType/Date.php | 56 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/DataType/Value.php | 121 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Exception/ClientException.php | 9 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Exception/ServerException.php | 9 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Message/Error.php | 43 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Message/Message.php | 210 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Request/Request.php | 48 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Server/ClassServer.php | 98 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Server/IntrospectionServer.php | 171 | ||||
-rw-r--r-- | vendor/kissifrot/php-ixr/src/Server/Server.php | 190 |
14 files changed, 1458 insertions, 0 deletions
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 @@ +<?php +namespace IXR\Client; + +use IXR\Message\Error; +use IXR\Message\Message; +use IXR\Request\Request; + +/** + * IXR_Client + * + * @package IXR + * @since 1.5.0 + * + */ +class Client +{ + protected $server; + protected $port; + protected $path; + protected $useragent; + protected $response; + /** @var bool|Message */ + protected $message = false; + protected $debug = false; + /** @var int Connection timeout in seconds */ + protected $timeout; + /** @var null|int Timeout for actual data transfer; in seconds */ + protected $timeout_io = null; + protected $headers = []; + + /** + * @var null|Error + * + * Storage place for an error message + */ + private $error = null; + + public function __construct($server, $path = false, $port = 80, $timeout = 15, $timeout_io = null) + { + if (!$path) { + // Assume we have been given a URL instead + $bits = parse_url($server); + $this->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 '<pre class="ixr_request">' . htmlspecialchars($request) . "\n</pre>\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 '<pre class="ixr_response">' . htmlspecialchars($debugContents) . "\n</pre>\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 @@ +<?php +namespace IXR\Client; + +/** + * IXR_ClientMulticall + * + * @package IXR + * @since 1.5.0 + */ +class ClientMulticall extends Client +{ + private $calls = []; + + public function __construct($server, $path = false, $port = 80) + { + parent::__construct($server, $path, $port); + $this->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 @@ +<?php +namespace IXR\Client; + +use IXR\Exception\ClientException; +use IXR\Message\Message; +use IXR\Request\Request; + +/** + * Client for communicating with a XML-RPC Server over HTTPS. + * + * @author Jason Stirk <jstirk@gmm.com.au> (@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('<pre>' . htmlspecialchars($xml) . PHP_EOL . '</pre>'); + + //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('<pre>' . htmlspecialchars($contents) . PHP_EOL . '</pre>'); + } + // 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 @@ +<?php +namespace IXR\DataType; + +/** + * IXR_Base64 + * + * @package IXR + * @since 1.5.0 + */ +class Base64 +{ + private $data; + + public function __construct($data) + { + $this->data = $data; + } + + public function getXml() + { + return '<base64>' . base64_encode($this->data) . '</base64>'; + } +} 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 @@ +<?php + +namespace IXR\DataType; + +/** + * IXR_Date + * + * @package IXR + * @since 1.5.0 + */ +class Date +{ + /** @var \DateTime */ + private $dateTime; + + 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); + } + } + + 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 '<dateTime.iso8601>' . $this->getIso() . '</dateTime.iso8601>'; + } + + 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 @@ +<?php +namespace IXR\DataType; + + +class Value +{ + private $data; + private $type; + + public function __construct($data, $type = null) + { + $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 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 '<boolean>' . (((bool)$this->data) ? '1' : '0') . '</boolean>'; + case 'int': + return '<int>' . $this->data . '</int>'; + case 'double': + return '<double>' . $this->data . '</double>'; + case 'string': + return '<string>' . htmlspecialchars($this->data) . '</string>'; + case 'array': + $return = '<array><data>' . "\n"; + foreach ($this->data as $item) { + $return .= ' <value>' . $item->getXml() . "</value>\n"; + } + $return .= '</data></array>'; + return $return; + break; + case 'struct': + $return = '<struct>' . "\n"; + foreach ($this->data as $name => $value) { + $name = htmlspecialchars($name); + $return .= " <member><name>$name</name><value>"; + $return .= $value->getXml() . "</value></member>\n"; + } + $return .= '</struct>'; + 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 @@ +<?php + +namespace IXR\Exception; + + +class ClientException extends \Exception +{ + +} diff --git a/vendor/kissifrot/php-ixr/src/Exception/ServerException.php b/vendor/kissifrot/php-ixr/src/Exception/ServerException.php new file mode 100644 index 000000000..a6b69538e --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Exception/ServerException.php @@ -0,0 +1,9 @@ +<?php + +namespace IXR\Exception; + + +class ServerException extends \Exception +{ + +} diff --git a/vendor/kissifrot/php-ixr/src/Message/Error.php b/vendor/kissifrot/php-ixr/src/Message/Error.php new file mode 100644 index 000000000..6dbb46c5c --- /dev/null +++ b/vendor/kissifrot/php-ixr/src/Message/Error.php @@ -0,0 +1,43 @@ +<?php +namespace IXR\Message; + +/** + * IXR_Error + * + * @package IXR + * @since 1.5.0 + */ +class Error +{ + public $code; + public $message; + + public function __construct($code, $message) + { + $this->code = $code; + $this->message = htmlspecialchars($message); + } + + public function getXml() + { + $xml = <<<EOD +<methodResponse> + <fault> + <value> + <struct> + <member> + <name>faultCode</name> + <value><int>{$this->code}</int></value> + </member> + <member> + <name>faultString</name> + <value><string>{$this->message}</string></value> + </member> + </struct> + </value> + </fault> +</methodResponse> +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 @@ +<?php +namespace IXR\Message; + + +use IXR\DataType\Date; + +class Message +{ + public $message; + public $messageType; // methodCall / methodResponse / fault + public $faultCode; + public $faultString; + public $methodName; + public $params; + + // Current variable stacks + private $_arraystructs = []; // The stack used to keep track of the current array/struct + private $_arraystructstypes = []; // Stack keeping track of if things are structs or array + private $_currentStructName = []; // A stack as well + private $_param; + private $_value; + private $_currentTag; + private $_currentTagContents; + // The XML parser + private $_parser; + + public function __construct($message) + { + $this->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('/^<!DOCTYPE[^>]*+>/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 ('<!DOCTYPE' === strtoupper($root_tag)) { + return false; + } + if (!in_array($root_tag, ['<methodCall', '<methodResponse', '<fault'])) { + return false; + } + + // Bail if there are too many elements to parse + $element_limit = 30000; + if ($element_limit && 2 * $element_limit < substr_count($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, '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 @@ +<?php + +namespace IXR\Request; + +use IXR\DataType\Value; + +/** + * IXR_Request + * + * @package IXR + * @since 1.5.0 + */ +class Request +{ + private $method; + private $args; + private $xml; + + public function __construct($method, $args) + { + $this->method = $method; + $this->args = $args; + $this->xml = <<<EOD +<?xml version="1.0"?> +<methodCall> +<methodName>{$this->method}</methodName> +<params> + +EOD; + foreach ($this->args as $arg) { + $this->xml .= '<param><value>'; + $v = new Value($arg); + $this->xml .= $v->getXml(); + $this->xml .= "</value></param>\n"; + } + $this->xml .= '</params></methodCall>'; + } + + 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 @@ +<?php +namespace IXR\Server; + +use IXR\Message\Error; + +/** + * Extension of the {@link Server} class to easily wrap objects. + * + * Class is designed to extend the existing XML-RPC server to allow the + * presentation of methods from a variety of different objects via an + * XML-RPC server. + * It is intended to assist in organization of your XML-RPC methods by allowing + * you to "write once" in your existing model classes and present them. + * + * @author Jason Stirk <jstirk@gmm.com.au> + * @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 @@ +<?php +namespace IXR\Server; + +use IXR\DataType\Base64; +use IXR\DataType\Date; +use IXR\Message\Error; + +/** + * IXR_IntrospectionServer + * + * @package IXR + * @since 1.5.0 + */ +class IntrospectionServer extends Server +{ + + private $signatures; + private $help; + + public function __construct() + { + $this->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 @@ +<?php + +namespace IXR\Server; + + +use IXR\DataType\Value; +use IXR\Exception\ServerException; +use IXR\Message\Error; +use IXR\Message\Message; + +class Server +{ + protected $callbacks = []; + protected $message; + protected $capabilities; + + public function __construct($callbacks = false, $data = false, $wait = false) + { + $this->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 = <<<EOD +<methodResponse> + <params> + <param> + <value> + $resultxml + </value> + </param> + </params> +</methodResponse> + +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 = '<?xml version="1.0"?>' . "\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; + } +} |