aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/vendor/kissifrot/php-ixr/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/kissifrot/php-ixr/src')
-rw-r--r--vendor/kissifrot/php-ixr/src/Client/Client.php209
-rw-r--r--vendor/kissifrot/php-ixr/src/Client/ClientMulticall.php36
-rw-r--r--vendor/kissifrot/php-ixr/src/Client/ClientSSL.php235
-rw-r--r--vendor/kissifrot/php-ixr/src/DataType/Base64.php23
-rw-r--r--vendor/kissifrot/php-ixr/src/DataType/Date.php56
-rw-r--r--vendor/kissifrot/php-ixr/src/DataType/Value.php121
-rw-r--r--vendor/kissifrot/php-ixr/src/Exception/ClientException.php9
-rw-r--r--vendor/kissifrot/php-ixr/src/Exception/ServerException.php9
-rw-r--r--vendor/kissifrot/php-ixr/src/Message/Error.php43
-rw-r--r--vendor/kissifrot/php-ixr/src/Message/Message.php210
-rw-r--r--vendor/kissifrot/php-ixr/src/Request/Request.php48
-rw-r--r--vendor/kissifrot/php-ixr/src/Server/ClassServer.php98
-rw-r--r--vendor/kissifrot/php-ixr/src/Server/IntrospectionServer.php171
-rw-r--r--vendor/kissifrot/php-ixr/src/Server/Server.php190
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;
+ }
+}