class-IXR-server.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * IXR_Server
  4. *
  5. * @package IXR
  6. * @since 1.5.0
  7. */
  8. class IXR_Server
  9. {
  10. var $data;
  11. var $callbacks = array();
  12. var $message;
  13. var $capabilities;
  14. /**
  15. * PHP5 constructor.
  16. */
  17. function __construct( $callbacks = false, $data = false, $wait = false )
  18. {
  19. $this->setCapabilities();
  20. if ($callbacks) {
  21. $this->callbacks = $callbacks;
  22. }
  23. $this->setCallbacks();
  24. if (!$wait) {
  25. $this->serve($data);
  26. }
  27. }
  28. /**
  29. * PHP4 constructor.
  30. */
  31. public function IXR_Server( $callbacks = false, $data = false, $wait = false ) {
  32. self::__construct( $callbacks, $data, $wait );
  33. }
  34. function serve($data = false)
  35. {
  36. if (!$data) {
  37. if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
  38. if ( function_exists( 'status_header' ) ) {
  39. status_header( 405 ); // WP #20986
  40. header( 'Allow: POST' );
  41. }
  42. header('Content-Type: text/plain'); // merged from WP #9093
  43. die('XML-RPC server accepts POST requests only.');
  44. }
  45. $data = file_get_contents('php://input');
  46. }
  47. $this->message = new IXR_Message($data);
  48. if (!$this->message->parse()) {
  49. $this->error(-32700, 'parse error. not well formed');
  50. }
  51. if ($this->message->messageType != 'methodCall') {
  52. $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
  53. }
  54. $result = $this->call($this->message->methodName, $this->message->params);
  55. // Is the result an error?
  56. if (is_a($result, 'IXR_Error')) {
  57. $this->error($result);
  58. }
  59. // Encode the result
  60. $r = new IXR_Value($result);
  61. $resultxml = $r->getXml();
  62. // Create the XML
  63. $xml = <<<EOD
  64. <methodResponse>
  65. <params>
  66. <param>
  67. <value>
  68. $resultxml
  69. </value>
  70. </param>
  71. </params>
  72. </methodResponse>
  73. EOD;
  74. // Send it
  75. $this->output($xml);
  76. }
  77. function call($methodname, $args)
  78. {
  79. if (!$this->hasMethod($methodname)) {
  80. return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
  81. }
  82. $method = $this->callbacks[$methodname];
  83. // Perform the callback and send the response
  84. if (count($args) == 1) {
  85. // If only one parameter just send that instead of the whole array
  86. $args = $args[0];
  87. }
  88. // Are we dealing with a function or a method?
  89. if (is_string($method) && substr($method, 0, 5) == 'this:') {
  90. // It's a class method - check it exists
  91. $method = substr($method, 5);
  92. if (!method_exists($this, $method)) {
  93. return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
  94. }
  95. //Call the method
  96. $result = $this->$method($args);
  97. } else {
  98. // It's a function - does it exist?
  99. if (is_array($method)) {
  100. if (!is_callable(array($method[0], $method[1]))) {
  101. return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.');
  102. }
  103. } else if (!function_exists($method)) {
  104. return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
  105. }
  106. // Call the function
  107. $result = call_user_func($method, $args);
  108. }
  109. return $result;
  110. }
  111. function error($error, $message = false)
  112. {
  113. // Accepts either an error object or an error code and message
  114. if ($message && !is_object($error)) {
  115. $error = new IXR_Error($error, $message);
  116. }
  117. $this->output($error->getXml());
  118. }
  119. function output($xml)
  120. {
  121. $charset = function_exists('get_option') ? get_option('blog_charset') : '';
  122. if ($charset)
  123. $xml = '<?xml version="1.0" encoding="'.$charset.'"?>'."\n".$xml;
  124. else
  125. $xml = '<?xml version="1.0"?>'."\n".$xml;
  126. $length = strlen($xml);
  127. header('Connection: close');
  128. if ($charset)
  129. header('Content-Type: text/xml; charset='.$charset);
  130. else
  131. header('Content-Type: text/xml');
  132. header('Date: '.gmdate('r'));
  133. echo $xml;
  134. exit;
  135. }
  136. function hasMethod($method)
  137. {
  138. return in_array($method, array_keys($this->callbacks));
  139. }
  140. function setCapabilities()
  141. {
  142. // Initialises capabilities array
  143. $this->capabilities = array(
  144. 'xmlrpc' => array(
  145. 'specUrl' => 'http://www.xmlrpc.com/spec',
  146. 'specVersion' => 1
  147. ),
  148. 'faults_interop' => array(
  149. 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
  150. 'specVersion' => 20010516
  151. ),
  152. 'system.multicall' => array(
  153. 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
  154. 'specVersion' => 1
  155. ),
  156. );
  157. }
  158. function getCapabilities($args)
  159. {
  160. return $this->capabilities;
  161. }
  162. function setCallbacks()
  163. {
  164. $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
  165. $this->callbacks['system.listMethods'] = 'this:listMethods';
  166. $this->callbacks['system.multicall'] = 'this:multiCall';
  167. }
  168. function listMethods($args)
  169. {
  170. // Returns a list of methods - uses array_reverse to ensure user defined
  171. // methods are listed before server defined methods
  172. return array_reverse(array_keys($this->callbacks));
  173. }
  174. function multiCall($methodcalls)
  175. {
  176. // See http://www.xmlrpc.com/discuss/msgReader$1208
  177. $return = array();
  178. foreach ($methodcalls as $call) {
  179. $method = $call['methodName'];
  180. $params = $call['params'];
  181. if ($method == 'system.multicall') {
  182. $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
  183. } else {
  184. $result = $this->call($method, $params);
  185. }
  186. if (is_a($result, 'IXR_Error')) {
  187. $return[] = array(
  188. 'faultCode' => $result->code,
  189. 'faultString' => $result->message
  190. );
  191. } else {
  192. $return[] = array($result);
  193. }
  194. }
  195. return $return;
  196. }
  197. }