2016-08-26 18:08:33 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IXR_Server
|
|
|
|
*
|
|
|
|
* @package IXR
|
|
|
|
* @since 1.5.0
|
|
|
|
*/
|
|
|
|
class IXR_Server
|
|
|
|
{
|
|
|
|
var $data;
|
|
|
|
var $callbacks = array();
|
|
|
|
var $message;
|
|
|
|
var $capabilities;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* PHP5 constructor.
|
|
|
|
*/
|
|
|
|
function __construct( $callbacks = false, $data = false, $wait = false )
|
|
|
|
{
|
|
|
|
$this->setCapabilities();
|
|
|
|
if ($callbacks) {
|
|
|
|
$this->callbacks = $callbacks;
|
|
|
|
}
|
|
|
|
$this->setCallbacks();
|
|
|
|
if (!$wait) {
|
|
|
|
$this->serve($data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* PHP4 constructor.
|
|
|
|
*/
|
|
|
|
public function IXR_Server( $callbacks = false, $data = false, $wait = false ) {
|
|
|
|
self::__construct( $callbacks, $data, $wait );
|
|
|
|
}
|
|
|
|
|
|
|
|
function serve($data = false)
|
|
|
|
{
|
|
|
|
if (!$data) {
|
|
|
|
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
|
|
if ( function_exists( 'status_header' ) ) {
|
|
|
|
status_header( 405 ); // WP #20986
|
|
|
|
header( 'Allow: POST' );
|
|
|
|
}
|
|
|
|
header('Content-Type: text/plain'); // merged from WP #9093
|
|
|
|
die('XML-RPC server accepts POST requests only.');
|
|
|
|
}
|
|
|
|
|
2020-06-08 15:55:10 -04:00
|
|
|
$data = file_get_contents('php://input');
|
2016-08-26 18:08:33 -04:00
|
|
|
}
|
|
|
|
$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 = <<<EOD
|
|
|
|
<methodResponse>
|
|
|
|
<params>
|
|
|
|
<param>
|
|
|
|
<value>
|
|
|
|
$resultxml
|
|
|
|
</value>
|
|
|
|
</param>
|
|
|
|
</params>
|
|
|
|
</methodResponse>
|
|
|
|
|
|
|
|
EOD;
|
|
|
|
// Send it
|
|
|
|
$this->output($xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
if (count($args) == 1) {
|
|
|
|
// If only one parameter just send that instead of the whole array
|
|
|
|
$args = $args[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2020-12-21 15:23:02 -05:00
|
|
|
|
|
|
|
if ( function_exists( 'status_header' ) ) {
|
|
|
|
status_header( $error->code );
|
|
|
|
}
|
|
|
|
|
2016-08-26 18:08:33 -04:00
|
|
|
$this->output($error->getXml());
|
|
|
|
}
|
|
|
|
|
|
|
|
function output($xml)
|
|
|
|
{
|
|
|
|
$charset = function_exists('get_option') ? get_option('blog_charset') : '';
|
|
|
|
if ($charset)
|
|
|
|
$xml = '<?xml version="1.0" encoding="'.$charset.'"?>'."\n".$xml;
|
|
|
|
else
|
|
|
|
$xml = '<?xml version="1.0"?>'."\n".$xml;
|
|
|
|
$length = strlen($xml);
|
|
|
|
header('Connection: close');
|
|
|
|
if ($charset)
|
|
|
|
header('Content-Type: text/xml; charset='.$charset);
|
|
|
|
else
|
|
|
|
header('Content-Type: text/xml');
|
2019-05-25 20:12:54 -04:00
|
|
|
header('Date: '.gmdate('r'));
|
2016-08-26 18:08:33 -04:00
|
|
|
echo $xml;
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCapabilities($args)
|
|
|
|
{
|
|
|
|
return $this->capabilities;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setCallbacks()
|
|
|
|
{
|
|
|
|
$this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
|
|
|
|
$this->callbacks['system.listMethods'] = 'this:listMethods';
|
|
|
|
$this->callbacks['system.multicall'] = 'this:multiCall';
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
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(-32600, '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;
|
|
|
|
}
|
|
|
|
}
|