raw
mp-wp_genesis           1 <?php
mp-wp_genesis 2 /**
mp-wp_genesis 3 * IXR - The Inutio XML-RPC Library
mp-wp_genesis 4 *
mp-wp_genesis 5 * @package IXR
mp-wp_genesis 6 * @since 1.5
mp-wp_genesis 7 *
mp-wp_genesis 8 * @copyright Incutio Ltd 2002-2005
mp-wp_genesis 9 * @version 1.7 (beta) 23rd May 2005
mp-wp_genesis 10 * @author Simon Willison
mp-wp_genesis 11 * @link http://scripts.incutio.com/xmlrpc/ Site
mp-wp_genesis 12 * @link http://scripts.incutio.com/xmlrpc/manual.php Manual
mp-wp_genesis 13 * @license BSD License http://www.opensource.org/licenses/bsd-license.php
mp-wp_genesis 14 */
mp-wp_genesis 15
mp-wp_genesis 16 /**
mp-wp_genesis 17 * IXR_Value
mp-wp_genesis 18 *
mp-wp_genesis 19 * @package IXR
mp-wp_genesis 20 * @since 1.5
mp-wp_genesis 21 */
mp-wp_genesis 22 class IXR_Value {
mp-wp_genesis 23 var $data;
mp-wp_genesis 24 var $type;
mp-wp_genesis 25
mp-wp_genesis 26 function IXR_Value ($data, $type = false) {
mp-wp_genesis 27 $this->data = $data;
mp-wp_genesis 28 if (!$type) {
mp-wp_genesis 29 $type = $this->calculateType();
mp-wp_genesis 30 }
mp-wp_genesis 31 $this->type = $type;
mp-wp_genesis 32 if ($type == 'struct') {
mp-wp_genesis 33 /* Turn all the values in the array in to new IXR_Value objects */
mp-wp_genesis 34 foreach ($this->data as $key => $value) {
mp-wp_genesis 35 $this->data[$key] = new IXR_Value($value);
mp-wp_genesis 36 }
mp-wp_genesis 37 }
mp-wp_genesis 38 if ($type == 'array') {
mp-wp_genesis 39 for ($i = 0, $j = count($this->data); $i < $j; $i++) {
mp-wp_genesis 40 $this->data[$i] = new IXR_Value($this->data[$i]);
mp-wp_genesis 41 }
mp-wp_genesis 42 }
mp-wp_genesis 43 }
mp-wp_genesis 44
mp-wp_genesis 45 function calculateType() {
mp-wp_genesis 46 if ($this->data === true || $this->data === false) {
mp-wp_genesis 47 return 'boolean';
mp-wp_genesis 48 }
mp-wp_genesis 49 if (is_integer($this->data)) {
mp-wp_genesis 50 return 'int';
mp-wp_genesis 51 }
mp-wp_genesis 52 if (is_double($this->data)) {
mp-wp_genesis 53 return 'double';
mp-wp_genesis 54 }
mp-wp_genesis 55 // Deal with IXR object types base64 and date
mp-wp_genesis 56 if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
mp-wp_genesis 57 return 'date';
mp-wp_genesis 58 }
mp-wp_genesis 59 if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
mp-wp_genesis 60 return 'base64';
mp-wp_genesis 61 }
mp-wp_genesis 62 // If it is a normal PHP object convert it in to a struct
mp-wp_genesis 63 if (is_object($this->data)) {
mp-wp_genesis 64
mp-wp_genesis 65 $this->data = get_object_vars($this->data);
mp-wp_genesis 66 return 'struct';
mp-wp_genesis 67 }
mp-wp_genesis 68 if (!is_array($this->data)) {
mp-wp_genesis 69 return 'string';
mp-wp_genesis 70 }
mp-wp_genesis 71 /* We have an array - is it an array or a struct ? */
mp-wp_genesis 72 if ($this->isStruct($this->data)) {
mp-wp_genesis 73 return 'struct';
mp-wp_genesis 74 } else {
mp-wp_genesis 75 return 'array';
mp-wp_genesis 76 }
mp-wp_genesis 77 }
mp-wp_genesis 78
mp-wp_genesis 79 function getXml() {
mp-wp_genesis 80 /* Return XML for this value */
mp-wp_genesis 81 switch ($this->type) {
mp-wp_genesis 82 case 'boolean':
mp-wp_genesis 83 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
mp-wp_genesis 84 break;
mp-wp_genesis 85 case 'int':
mp-wp_genesis 86 return '<int>'.$this->data.'</int>';
mp-wp_genesis 87 break;
mp-wp_genesis 88 case 'double':
mp-wp_genesis 89 return '<double>'.$this->data.'</double>';
mp-wp_genesis 90 break;
mp-wp_genesis 91 case 'string':
mp-wp_genesis 92 return '<string>'.htmlspecialchars($this->data).'</string>';
mp-wp_genesis 93 break;
mp-wp_genesis 94 case 'array':
mp-wp_genesis 95 $return = '<array><data>'."\n";
mp-wp_genesis 96 foreach ($this->data as $item) {
mp-wp_genesis 97 $return .= ' <value>'.$item->getXml()."</value>\n";
mp-wp_genesis 98 }
mp-wp_genesis 99 $return .= '</data></array>';
mp-wp_genesis 100 return $return;
mp-wp_genesis 101 break;
mp-wp_genesis 102 case 'struct':
mp-wp_genesis 103 $return = '<struct>'."\n";
mp-wp_genesis 104 foreach ($this->data as $name => $value) {
mp-wp_genesis 105 $name = htmlspecialchars($name);
mp-wp_genesis 106 $return .= " <member><name>$name</name><value>";
mp-wp_genesis 107 $return .= $value->getXml()."</value></member>\n";
mp-wp_genesis 108 }
mp-wp_genesis 109 $return .= '</struct>';
mp-wp_genesis 110 return $return;
mp-wp_genesis 111 break;
mp-wp_genesis 112 case 'date':
mp-wp_genesis 113 case 'base64':
mp-wp_genesis 114 return $this->data->getXml();
mp-wp_genesis 115 break;
mp-wp_genesis 116 }
mp-wp_genesis 117 return false;
mp-wp_genesis 118 }
mp-wp_genesis 119
mp-wp_genesis 120 function isStruct($array) {
mp-wp_genesis 121 /* Nasty function to check if an array is a struct or not */
mp-wp_genesis 122 $expected = 0;
mp-wp_genesis 123 foreach ($array as $key => $value) {
mp-wp_genesis 124 if ((string)$key != (string)$expected) {
mp-wp_genesis 125 return true;
mp-wp_genesis 126 }
mp-wp_genesis 127 $expected++;
mp-wp_genesis 128 }
mp-wp_genesis 129 return false;
mp-wp_genesis 130 }
mp-wp_genesis 131 }
mp-wp_genesis 132
mp-wp_genesis 133 /**
mp-wp_genesis 134 * IXR_Message
mp-wp_genesis 135 *
mp-wp_genesis 136 * @package IXR
mp-wp_genesis 137 * @since 1.5
mp-wp_genesis 138 */
mp-wp_genesis 139 class IXR_Message {
mp-wp_genesis 140 var $message;
mp-wp_genesis 141 var $messageType; // methodCall / methodResponse / fault
mp-wp_genesis 142 var $faultCode;
mp-wp_genesis 143 var $faultString;
mp-wp_genesis 144 var $methodName;
mp-wp_genesis 145 var $params;
mp-wp_genesis 146 // Current variable stacks
mp-wp_genesis 147 var $_arraystructs = array(); // The stack used to keep track of the current array/struct
mp-wp_genesis 148 var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
mp-wp_genesis 149 var $_currentStructName = array(); // A stack as well
mp-wp_genesis 150 var $_param;
mp-wp_genesis 151 var $_value;
mp-wp_genesis 152 var $_currentTag;
mp-wp_genesis 153 var $_currentTagContents;
mp-wp_genesis 154 // The XML parser
mp-wp_genesis 155 var $_parser;
mp-wp_genesis 156 function IXR_Message ($message) {
mp-wp_genesis 157 $this->message = $message;
mp-wp_genesis 158 }
mp-wp_genesis 159 function parse() {
mp-wp_genesis 160 // first remove the XML declaration
mp-wp_genesis 161 $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
mp-wp_genesis 162 if (trim($this->message) == '') {
mp-wp_genesis 163 return false;
mp-wp_genesis 164 }
mp-wp_genesis 165 $this->_parser = xml_parser_create();
mp-wp_genesis 166 // Set XML parser to take the case of tags in to account
mp-wp_genesis 167 xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
mp-wp_genesis 168 // Set XML parser callback functions
mp-wp_genesis 169 xml_set_object($this->_parser, $this);
mp-wp_genesis 170 xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
mp-wp_genesis 171 xml_set_character_data_handler($this->_parser, 'cdata');
mp-wp_genesis 172 if (!xml_parse($this->_parser, $this->message)) {
mp-wp_genesis 173 /* die(sprintf('XML error: %s at line %d',
mp-wp_genesis 174 xml_error_string(xml_get_error_code($this->_parser)),
mp-wp_genesis 175 xml_get_current_line_number($this->_parser))); */
mp-wp_genesis 176 return false;
mp-wp_genesis 177 }
mp-wp_genesis 178 xml_parser_free($this->_parser);
mp-wp_genesis 179 // Grab the error messages, if any
mp-wp_genesis 180 if ($this->messageType == 'fault') {
mp-wp_genesis 181 $this->faultCode = $this->params[0]['faultCode'];
mp-wp_genesis 182 $this->faultString = $this->params[0]['faultString'];
mp-wp_genesis 183 }
mp-wp_genesis 184 return true;
mp-wp_genesis 185 }
mp-wp_genesis 186 function tag_open($parser, $tag, $attr) {
mp-wp_genesis 187 $this->_currentTagContents = '';
mp-wp_genesis 188 $this->currentTag = $tag;
mp-wp_genesis 189 switch($tag) {
mp-wp_genesis 190 case 'methodCall':
mp-wp_genesis 191 case 'methodResponse':
mp-wp_genesis 192 case 'fault':
mp-wp_genesis 193 $this->messageType = $tag;
mp-wp_genesis 194 break;
mp-wp_genesis 195 /* Deal with stacks of arrays and structs */
mp-wp_genesis 196 case 'data': // data is to all intents and puposes more interesting than array
mp-wp_genesis 197 $this->_arraystructstypes[] = 'array';
mp-wp_genesis 198 $this->_arraystructs[] = array();
mp-wp_genesis 199 break;
mp-wp_genesis 200 case 'struct':
mp-wp_genesis 201 $this->_arraystructstypes[] = 'struct';
mp-wp_genesis 202 $this->_arraystructs[] = array();
mp-wp_genesis 203 break;
mp-wp_genesis 204 }
mp-wp_genesis 205 }
mp-wp_genesis 206 function cdata($parser, $cdata) {
mp-wp_genesis 207 $this->_currentTagContents .= $cdata;
mp-wp_genesis 208 }
mp-wp_genesis 209 function tag_close($parser, $tag) {
mp-wp_genesis 210 $valueFlag = false;
mp-wp_genesis 211 switch($tag) {
mp-wp_genesis 212 case 'int':
mp-wp_genesis 213 case 'i4':
mp-wp_genesis 214 $value = (int) trim($this->_currentTagContents);
mp-wp_genesis 215 $valueFlag = true;
mp-wp_genesis 216 break;
mp-wp_genesis 217 case 'double':
mp-wp_genesis 218 $value = (double) trim($this->_currentTagContents);
mp-wp_genesis 219 $valueFlag = true;
mp-wp_genesis 220 break;
mp-wp_genesis 221 case 'string':
mp-wp_genesis 222 $value = $this->_currentTagContents;
mp-wp_genesis 223 $valueFlag = true;
mp-wp_genesis 224 break;
mp-wp_genesis 225 case 'dateTime.iso8601':
mp-wp_genesis 226 $value = new IXR_Date(trim($this->_currentTagContents));
mp-wp_genesis 227 // $value = $iso->getTimestamp();
mp-wp_genesis 228 $valueFlag = true;
mp-wp_genesis 229 break;
mp-wp_genesis 230 case 'value':
mp-wp_genesis 231 // "If no type is indicated, the type is string."
mp-wp_genesis 232 if (trim($this->_currentTagContents) != '') {
mp-wp_genesis 233 $value = (string)$this->_currentTagContents;
mp-wp_genesis 234 $valueFlag = true;
mp-wp_genesis 235 }
mp-wp_genesis 236 break;
mp-wp_genesis 237 case 'boolean':
mp-wp_genesis 238 $value = (boolean) trim($this->_currentTagContents);
mp-wp_genesis 239 $valueFlag = true;
mp-wp_genesis 240 break;
mp-wp_genesis 241 case 'base64':
mp-wp_genesis 242 $value = base64_decode( trim( $this->_currentTagContents ) );
mp-wp_genesis 243 $valueFlag = true;
mp-wp_genesis 244 break;
mp-wp_genesis 245 /* Deal with stacks of arrays and structs */
mp-wp_genesis 246 case 'data':
mp-wp_genesis 247 case 'struct':
mp-wp_genesis 248 $value = array_pop($this->_arraystructs);
mp-wp_genesis 249 array_pop($this->_arraystructstypes);
mp-wp_genesis 250 $valueFlag = true;
mp-wp_genesis 251 break;
mp-wp_genesis 252 case 'member':
mp-wp_genesis 253 array_pop($this->_currentStructName);
mp-wp_genesis 254 break;
mp-wp_genesis 255 case 'name':
mp-wp_genesis 256 $this->_currentStructName[] = trim($this->_currentTagContents);
mp-wp_genesis 257 break;
mp-wp_genesis 258 case 'methodName':
mp-wp_genesis 259 $this->methodName = trim($this->_currentTagContents);
mp-wp_genesis 260 break;
mp-wp_genesis 261 }
mp-wp_genesis 262 if ($valueFlag) {
mp-wp_genesis 263 if (count($this->_arraystructs) > 0) {
mp-wp_genesis 264 // Add value to struct or array
mp-wp_genesis 265 if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
mp-wp_genesis 266 // Add to struct
mp-wp_genesis 267 $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
mp-wp_genesis 268 } else {
mp-wp_genesis 269 // Add to array
mp-wp_genesis 270 $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
mp-wp_genesis 271 }
mp-wp_genesis 272 } else {
mp-wp_genesis 273 // Just add as a paramater
mp-wp_genesis 274 $this->params[] = $value;
mp-wp_genesis 275 }
mp-wp_genesis 276 }
mp-wp_genesis 277 $this->_currentTagContents = '';
mp-wp_genesis 278 }
mp-wp_genesis 279 }
mp-wp_genesis 280
mp-wp_genesis 281 /**
mp-wp_genesis 282 * IXR_Server
mp-wp_genesis 283 *
mp-wp_genesis 284 * @package IXR
mp-wp_genesis 285 * @since 1.5
mp-wp_genesis 286 */
mp-wp_genesis 287 class IXR_Server {
mp-wp_genesis 288 var $data;
mp-wp_genesis 289 var $callbacks = array();
mp-wp_genesis 290 var $message;
mp-wp_genesis 291 var $capabilities;
mp-wp_genesis 292 function IXR_Server($callbacks = false, $data = false) {
mp-wp_genesis 293 $this->setCapabilities();
mp-wp_genesis 294 if ($callbacks) {
mp-wp_genesis 295 $this->callbacks = $callbacks;
mp-wp_genesis 296 }
mp-wp_genesis 297 $this->setCallbacks();
mp-wp_genesis 298 $this->serve($data);
mp-wp_genesis 299 }
mp-wp_genesis 300 function serve($data = false) {
mp-wp_genesis 301 if (!$data) {
mp-wp_genesis 302 global $HTTP_RAW_POST_DATA;
mp-wp_genesis 303 if (!$HTTP_RAW_POST_DATA) {
mp-wp_genesis 304 die('XML-RPC server accepts POST requests only.');
mp-wp_genesis 305 }
mp-wp_genesis 306 $data = $HTTP_RAW_POST_DATA;
mp-wp_genesis 307 }
mp-wp_genesis 308 $this->message = new IXR_Message($data);
mp-wp_genesis 309 if (!$this->message->parse()) {
mp-wp_genesis 310 $this->error(-32700, 'parse error. not well formed');
mp-wp_genesis 311 }
mp-wp_genesis 312 if ($this->message->messageType != 'methodCall') {
mp-wp_genesis 313 $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
mp-wp_genesis 314 }
mp-wp_genesis 315 $result = $this->call($this->message->methodName, $this->message->params);
mp-wp_genesis 316 // Is the result an error?
mp-wp_genesis 317 if (is_a($result, 'IXR_Error')) {
mp-wp_genesis 318 $this->error($result);
mp-wp_genesis 319 }
mp-wp_genesis 320 // Encode the result
mp-wp_genesis 321 $r = new IXR_Value($result);
mp-wp_genesis 322 $resultxml = $r->getXml();
mp-wp_genesis 323 // Create the XML
mp-wp_genesis 324 $xml = <<<EOD
mp-wp_genesis 325 <methodResponse>
mp-wp_genesis 326 <params>
mp-wp_genesis 327 <param>
mp-wp_genesis 328 <value>
mp-wp_genesis 329 $resultxml
mp-wp_genesis 330 </value>
mp-wp_genesis 331 </param>
mp-wp_genesis 332 </params>
mp-wp_genesis 333 </methodResponse>
mp-wp_genesis 334
mp-wp_genesis 335 EOD;
mp-wp_genesis 336 // Send it
mp-wp_genesis 337 $this->output($xml);
mp-wp_genesis 338 }
mp-wp_genesis 339 function call($methodname, $args) {
mp-wp_genesis 340 if (!$this->hasMethod($methodname)) {
mp-wp_genesis 341 return new IXR_Error(-32601, 'server error. requested method '.
mp-wp_genesis 342 $methodname.' does not exist.');
mp-wp_genesis 343 }
mp-wp_genesis 344 $method = $this->callbacks[$methodname];
mp-wp_genesis 345 // Perform the callback and send the response
mp-wp_genesis 346 if (count($args) == 1) {
mp-wp_genesis 347 // If only one paramater just send that instead of the whole array
mp-wp_genesis 348 $args = $args[0];
mp-wp_genesis 349 }
mp-wp_genesis 350 // Are we dealing with a function or a method?
mp-wp_genesis 351 if (substr($method, 0, 5) == 'this:') {
mp-wp_genesis 352 // It's a class method - check it exists
mp-wp_genesis 353 $method = substr($method, 5);
mp-wp_genesis 354 if (!method_exists($this, $method)) {
mp-wp_genesis 355 return new IXR_Error(-32601, 'server error. requested class method "'.
mp-wp_genesis 356 $method.'" does not exist.');
mp-wp_genesis 357 }
mp-wp_genesis 358 // Call the method
mp-wp_genesis 359 $result = $this->$method($args);
mp-wp_genesis 360 } else {
mp-wp_genesis 361 // It's a function - does it exist?
mp-wp_genesis 362 if (is_array($method)) {
mp-wp_genesis 363 if (!method_exists($method[0], $method[1])) {
mp-wp_genesis 364 return new IXR_Error(-32601, 'server error. requested object method "'.
mp-wp_genesis 365 $method[1].'" does not exist.');
mp-wp_genesis 366 }
mp-wp_genesis 367 } else if (!function_exists($method)) {
mp-wp_genesis 368 return new IXR_Error(-32601, 'server error. requested function "'.
mp-wp_genesis 369 $method.'" does not exist.');
mp-wp_genesis 370 }
mp-wp_genesis 371 // Call the function
mp-wp_genesis 372 $result = call_user_func($method, $args);
mp-wp_genesis 373 }
mp-wp_genesis 374 return $result;
mp-wp_genesis 375 }
mp-wp_genesis 376
mp-wp_genesis 377 function error($error, $message = false) {
mp-wp_genesis 378 // Accepts either an error object or an error code and message
mp-wp_genesis 379 if ($message && !is_object($error)) {
mp-wp_genesis 380 $error = new IXR_Error($error, $message);
mp-wp_genesis 381 }
mp-wp_genesis 382 $this->output($error->getXml());
mp-wp_genesis 383 }
mp-wp_genesis 384 function output($xml) {
mp-wp_genesis 385 $xml = '<?xml version="1.0"?>'."\n".$xml;
mp-wp_genesis 386 $length = strlen($xml);
mp-wp_genesis 387 header('Connection: close');
mp-wp_genesis 388 header('Content-Length: '.$length);
mp-wp_genesis 389 header('Content-Type: text/xml');
mp-wp_genesis 390 header('Date: '.date('r'));
mp-wp_genesis 391 echo $xml;
mp-wp_genesis 392 exit;
mp-wp_genesis 393 }
mp-wp_genesis 394 function hasMethod($method) {
mp-wp_genesis 395 return in_array($method, array_keys($this->callbacks));
mp-wp_genesis 396 }
mp-wp_genesis 397 function setCapabilities() {
mp-wp_genesis 398 // Initialises capabilities array
mp-wp_genesis 399 $this->capabilities = array(
mp-wp_genesis 400 'xmlrpc' => array(
mp-wp_genesis 401 'specUrl' => 'http://www.xmlrpc.com/spec',
mp-wp_genesis 402 'specVersion' => 1
mp-wp_genesis 403 ),
mp-wp_genesis 404 'faults_interop' => array(
mp-wp_genesis 405 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
mp-wp_genesis 406 'specVersion' => 20010516
mp-wp_genesis 407 ),
mp-wp_genesis 408 'system.multicall' => array(
mp-wp_genesis 409 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
mp-wp_genesis 410 'specVersion' => 1
mp-wp_genesis 411 ),
mp-wp_genesis 412 );
mp-wp_genesis 413 }
mp-wp_genesis 414 function getCapabilities($args) {
mp-wp_genesis 415 return $this->capabilities;
mp-wp_genesis 416 }
mp-wp_genesis 417 function setCallbacks() {
mp-wp_genesis 418 $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
mp-wp_genesis 419 $this->callbacks['system.listMethods'] = 'this:listMethods';
mp-wp_genesis 420 $this->callbacks['system.multicall'] = 'this:multiCall';
mp-wp_genesis 421 }
mp-wp_genesis 422 function listMethods($args) {
mp-wp_genesis 423 // Returns a list of methods - uses array_reverse to ensure user defined
mp-wp_genesis 424 // methods are listed before server defined methods
mp-wp_genesis 425 return array_reverse(array_keys($this->callbacks));
mp-wp_genesis 426 }
mp-wp_genesis 427 function multiCall($methodcalls) {
mp-wp_genesis 428 // See http://www.xmlrpc.com/discuss/msgReader$1208
mp-wp_genesis 429 $return = array();
mp-wp_genesis 430 foreach ($methodcalls as $call) {
mp-wp_genesis 431 $method = $call['methodName'];
mp-wp_genesis 432 $params = $call['params'];
mp-wp_genesis 433 if ($method == 'system.multicall') {
mp-wp_genesis 434 $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
mp-wp_genesis 435 } else {
mp-wp_genesis 436 $result = $this->call($method, $params);
mp-wp_genesis 437 }
mp-wp_genesis 438 if (is_a($result, 'IXR_Error')) {
mp-wp_genesis 439 $return[] = array(
mp-wp_genesis 440 'faultCode' => $result->code,
mp-wp_genesis 441 'faultString' => $result->message
mp-wp_genesis 442 );
mp-wp_genesis 443 } else {
mp-wp_genesis 444 $return[] = array($result);
mp-wp_genesis 445 }
mp-wp_genesis 446 }
mp-wp_genesis 447 return $return;
mp-wp_genesis 448 }
mp-wp_genesis 449 }
mp-wp_genesis 450
mp-wp_genesis 451 /**
mp-wp_genesis 452 * IXR_Request
mp-wp_genesis 453 *
mp-wp_genesis 454 * @package IXR
mp-wp_genesis 455 * @since 1.5
mp-wp_genesis 456 */
mp-wp_genesis 457 class IXR_Request {
mp-wp_genesis 458 var $method;
mp-wp_genesis 459 var $args;
mp-wp_genesis 460 var $xml;
mp-wp_genesis 461 function IXR_Request($method, $args) {
mp-wp_genesis 462 $this->method = $method;
mp-wp_genesis 463 $this->args = $args;
mp-wp_genesis 464 $this->xml = <<<EOD
mp-wp_genesis 465 <?xml version="1.0"?>
mp-wp_genesis 466 <methodCall>
mp-wp_genesis 467 <methodName>{$this->method}</methodName>
mp-wp_genesis 468 <params>
mp-wp_genesis 469
mp-wp_genesis 470 EOD;
mp-wp_genesis 471 foreach ($this->args as $arg) {
mp-wp_genesis 472 $this->xml .= '<param><value>';
mp-wp_genesis 473 $v = new IXR_Value($arg);
mp-wp_genesis 474 $this->xml .= $v->getXml();
mp-wp_genesis 475 $this->xml .= "</value></param>\n";
mp-wp_genesis 476 }
mp-wp_genesis 477 $this->xml .= '</params></methodCall>';
mp-wp_genesis 478 }
mp-wp_genesis 479 function getLength() {
mp-wp_genesis 480 return strlen($this->xml);
mp-wp_genesis 481 }
mp-wp_genesis 482 function getXml() {
mp-wp_genesis 483 return $this->xml;
mp-wp_genesis 484 }
mp-wp_genesis 485 }
mp-wp_genesis 486
mp-wp_genesis 487 /**
mp-wp_genesis 488 * IXR_Client
mp-wp_genesis 489 *
mp-wp_genesis 490 * @package IXR
mp-wp_genesis 491 * @since 1.5
mp-wp_genesis 492 */
mp-wp_genesis 493 class IXR_Client {
mp-wp_genesis 494 var $server;
mp-wp_genesis 495 var $port;
mp-wp_genesis 496 var $path;
mp-wp_genesis 497 var $useragent;
mp-wp_genesis 498 var $response;
mp-wp_genesis 499 var $message = false;
mp-wp_genesis 500 var $debug = false;
mp-wp_genesis 501 var $timeout;
mp-wp_genesis 502 // Storage place for an error message
mp-wp_genesis 503 var $error = false;
mp-wp_genesis 504 function IXR_Client($server, $path = false, $port = 80, $timeout = false) {
mp-wp_genesis 505 if (!$path) {
mp-wp_genesis 506 // Assume we have been given a URL instead
mp-wp_genesis 507 $bits = parse_url($server);
mp-wp_genesis 508 $this->server = $bits['host'];
mp-wp_genesis 509 $this->port = isset($bits['port']) ? $bits['port'] : 80;
mp-wp_genesis 510 $this->path = isset($bits['path']) ? $bits['path'] : '/';
mp-wp_genesis 511 // Make absolutely sure we have a path
mp-wp_genesis 512 if (!$this->path) {
mp-wp_genesis 513 $this->path = '/';
mp-wp_genesis 514 }
mp-wp_genesis 515 } else {
mp-wp_genesis 516 $this->server = $server;
mp-wp_genesis 517 $this->path = $path;
mp-wp_genesis 518 $this->port = $port;
mp-wp_genesis 519 }
mp-wp_genesis 520 $this->useragent = 'The Incutio XML-RPC PHP Library';
mp-wp_genesis 521 $this->timeout = $timeout;
mp-wp_genesis 522 }
mp-wp_genesis 523 function query() {
mp-wp_genesis 524 $args = func_get_args();
mp-wp_genesis 525 $method = array_shift($args);
mp-wp_genesis 526 $request = new IXR_Request($method, $args);
mp-wp_genesis 527 $length = $request->getLength();
mp-wp_genesis 528 $xml = $request->getXml();
mp-wp_genesis 529 $r = "\r\n";
mp-wp_genesis 530 $request = "POST {$this->path} HTTP/1.0$r";
mp-wp_genesis 531 $request .= "Host: {$this->server}$r";
mp-wp_genesis 532 $request .= "Content-Type: text/xml$r";
mp-wp_genesis 533 $request .= "User-Agent: {$this->useragent}$r";
mp-wp_genesis 534 $request .= "Content-length: {$length}$r$r";
mp-wp_genesis 535 $request .= $xml;
mp-wp_genesis 536 // Now send the request
mp-wp_genesis 537 if ($this->debug) {
mp-wp_genesis 538 echo '<pre>'.htmlspecialchars($request)."\n</pre>\n\n";
mp-wp_genesis 539 }
mp-wp_genesis 540 if ($this->timeout) {
mp-wp_genesis 541 $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);
mp-wp_genesis 542 } else {
mp-wp_genesis 543 $fp = @fsockopen($this->server, $this->port, $errno, $errstr);
mp-wp_genesis 544 }
mp-wp_genesis 545 if (!$fp) {
mp-wp_genesis 546 $this->error = new IXR_Error(-32300, "transport error - could not open socket: $errno $errstr");
mp-wp_genesis 547 return false;
mp-wp_genesis 548 }
mp-wp_genesis 549 fputs($fp, $request);
mp-wp_genesis 550 $contents = '';
mp-wp_genesis 551 $gotFirstLine = false;
mp-wp_genesis 552 $gettingHeaders = true;
mp-wp_genesis 553 while (!feof($fp)) {
mp-wp_genesis 554 $line = fgets($fp, 4096);
mp-wp_genesis 555 if (!$gotFirstLine) {
mp-wp_genesis 556 // Check line for '200'
mp-wp_genesis 557 if (strstr($line, '200') === false) {
mp-wp_genesis 558 $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
mp-wp_genesis 559 return false;
mp-wp_genesis 560 }
mp-wp_genesis 561 $gotFirstLine = true;
mp-wp_genesis 562 }
mp-wp_genesis 563 if (trim($line) == '') {
mp-wp_genesis 564 $gettingHeaders = false;
mp-wp_genesis 565 }
mp-wp_genesis 566 if (!$gettingHeaders) {
mp-wp_genesis 567 $contents .= trim($line);
mp-wp_genesis 568 }
mp-wp_genesis 569 }
mp-wp_genesis 570 if ($this->debug) {
mp-wp_genesis 571 echo '<pre>'.htmlspecialchars($contents)."\n</pre>\n\n";
mp-wp_genesis 572 }
mp-wp_genesis 573 // Now parse what we've got back
mp-wp_genesis 574 $this->message = new IXR_Message($contents);
mp-wp_genesis 575 if (!$this->message->parse()) {
mp-wp_genesis 576 // XML error
mp-wp_genesis 577 $this->error = new IXR_Error(-32700, 'parse error. not well formed');
mp-wp_genesis 578 return false;
mp-wp_genesis 579 }
mp-wp_genesis 580 // Is the message a fault?
mp-wp_genesis 581 if ($this->message->messageType == 'fault') {
mp-wp_genesis 582 $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
mp-wp_genesis 583 return false;
mp-wp_genesis 584 }
mp-wp_genesis 585 // Message must be OK
mp-wp_genesis 586 return true;
mp-wp_genesis 587 }
mp-wp_genesis 588 function getResponse() {
mp-wp_genesis 589 // methodResponses can only have one param - return that
mp-wp_genesis 590 return $this->message->params[0];
mp-wp_genesis 591 }
mp-wp_genesis 592 function isError() {
mp-wp_genesis 593 return (is_object($this->error));
mp-wp_genesis 594 }
mp-wp_genesis 595 function getErrorCode() {
mp-wp_genesis 596 return $this->error->code;
mp-wp_genesis 597 }
mp-wp_genesis 598 function getErrorMessage() {
mp-wp_genesis 599 return $this->error->message;
mp-wp_genesis 600 }
mp-wp_genesis 601 }
mp-wp_genesis 602
mp-wp_genesis 603 /**
mp-wp_genesis 604 * IXR_Error
mp-wp_genesis 605 *
mp-wp_genesis 606 * @package IXR
mp-wp_genesis 607 * @since 1.5
mp-wp_genesis 608 */
mp-wp_genesis 609 class IXR_Error {
mp-wp_genesis 610 var $code;
mp-wp_genesis 611 var $message;
mp-wp_genesis 612 function IXR_Error($code, $message) {
mp-wp_genesis 613 $this->code = $code;
mp-wp_genesis 614 // WP adds htmlspecialchars(). See #5666
mp-wp_genesis 615 $this->message = htmlspecialchars($message);
mp-wp_genesis 616 }
mp-wp_genesis 617 function getXml() {
mp-wp_genesis 618 $xml = <<<EOD
mp-wp_genesis 619 <methodResponse>
mp-wp_genesis 620 <fault>
mp-wp_genesis 621 <value>
mp-wp_genesis 622 <struct>
mp-wp_genesis 623 <member>
mp-wp_genesis 624 <name>faultCode</name>
mp-wp_genesis 625 <value><int>{$this->code}</int></value>
mp-wp_genesis 626 </member>
mp-wp_genesis 627 <member>
mp-wp_genesis 628 <name>faultString</name>
mp-wp_genesis 629 <value><string>{$this->message}</string></value>
mp-wp_genesis 630 </member>
mp-wp_genesis 631 </struct>
mp-wp_genesis 632 </value>
mp-wp_genesis 633 </fault>
mp-wp_genesis 634 </methodResponse>
mp-wp_genesis 635
mp-wp_genesis 636 EOD;
mp-wp_genesis 637 return $xml;
mp-wp_genesis 638 }
mp-wp_genesis 639 }
mp-wp_genesis 640
mp-wp_genesis 641 /**
mp-wp_genesis 642 * IXR_Date
mp-wp_genesis 643 *
mp-wp_genesis 644 * @package IXR
mp-wp_genesis 645 * @since 1.5
mp-wp_genesis 646 */
mp-wp_genesis 647 class IXR_Date {
mp-wp_genesis 648 var $year;
mp-wp_genesis 649 var $month;
mp-wp_genesis 650 var $day;
mp-wp_genesis 651 var $hour;
mp-wp_genesis 652 var $minute;
mp-wp_genesis 653 var $second;
mp-wp_genesis 654 var $timezone;
mp-wp_genesis 655 function IXR_Date($time) {
mp-wp_genesis 656 // $time can be a PHP timestamp or an ISO one
mp-wp_genesis 657 if (is_numeric($time)) {
mp-wp_genesis 658 $this->parseTimestamp($time);
mp-wp_genesis 659 } else {
mp-wp_genesis 660 $this->parseIso($time);
mp-wp_genesis 661 }
mp-wp_genesis 662 }
mp-wp_genesis 663 function parseTimestamp($timestamp) {
mp-wp_genesis 664 $this->year = date('Y', $timestamp);
mp-wp_genesis 665 $this->month = date('m', $timestamp);
mp-wp_genesis 666 $this->day = date('d', $timestamp);
mp-wp_genesis 667 $this->hour = date('H', $timestamp);
mp-wp_genesis 668 $this->minute = date('i', $timestamp);
mp-wp_genesis 669 $this->second = date('s', $timestamp);
mp-wp_genesis 670 // WP adds timezone. See #2036
mp-wp_genesis 671 $this->timezone = '';
mp-wp_genesis 672 }
mp-wp_genesis 673 function parseIso($iso) {
mp-wp_genesis 674 $this->year = substr($iso, 0, 4);
mp-wp_genesis 675 $this->month = substr($iso, 4, 2);
mp-wp_genesis 676 $this->day = substr($iso, 6, 2);
mp-wp_genesis 677 $this->hour = substr($iso, 9, 2);
mp-wp_genesis 678 $this->minute = substr($iso, 12, 2);
mp-wp_genesis 679 $this->second = substr($iso, 15, 2);
mp-wp_genesis 680 // WP adds timezone. See #2036
mp-wp_genesis 681 $this->timezone = substr($iso, 17);
mp-wp_genesis 682 }
mp-wp_genesis 683 function getIso() {
mp-wp_genesis 684 // WP adds timezone. See #2036
mp-wp_genesis 685 return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
mp-wp_genesis 686 }
mp-wp_genesis 687 function getXml() {
mp-wp_genesis 688 return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
mp-wp_genesis 689 }
mp-wp_genesis 690 function getTimestamp() {
mp-wp_genesis 691 return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
mp-wp_genesis 692 }
mp-wp_genesis 693 }
mp-wp_genesis 694
mp-wp_genesis 695 /**
mp-wp_genesis 696 * IXR_Base64
mp-wp_genesis 697 *
mp-wp_genesis 698 * @package IXR
mp-wp_genesis 699 * @since 1.5
mp-wp_genesis 700 */
mp-wp_genesis 701 class IXR_Base64 {
mp-wp_genesis 702 var $data;
mp-wp_genesis 703 function IXR_Base64($data) {
mp-wp_genesis 704 $this->data = $data;
mp-wp_genesis 705 }
mp-wp_genesis 706 function getXml() {
mp-wp_genesis 707 return '<base64>'.base64_encode($this->data).'</base64>';
mp-wp_genesis 708 }
mp-wp_genesis 709 }
mp-wp_genesis 710
mp-wp_genesis 711 /**
mp-wp_genesis 712 * IXR_IntrospectionServer
mp-wp_genesis 713 *
mp-wp_genesis 714 * @package IXR
mp-wp_genesis 715 * @since 1.5
mp-wp_genesis 716 */
mp-wp_genesis 717 class IXR_IntrospectionServer extends IXR_Server {
mp-wp_genesis 718 var $signatures;
mp-wp_genesis 719 var $help;
mp-wp_genesis 720 function IXR_IntrospectionServer() {
mp-wp_genesis 721 $this->setCallbacks();
mp-wp_genesis 722 $this->setCapabilities();
mp-wp_genesis 723 $this->capabilities['introspection'] = array(
mp-wp_genesis 724 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
mp-wp_genesis 725 'specVersion' => 1
mp-wp_genesis 726 );
mp-wp_genesis 727 $this->addCallback(
mp-wp_genesis 728 'system.methodSignature',
mp-wp_genesis 729 'this:methodSignature',
mp-wp_genesis 730 array('array', 'string'),
mp-wp_genesis 731 'Returns an array describing the return type and required parameters of a method'
mp-wp_genesis 732 );
mp-wp_genesis 733 $this->addCallback(
mp-wp_genesis 734 'system.getCapabilities',
mp-wp_genesis 735 'this:getCapabilities',
mp-wp_genesis 736 array('struct'),
mp-wp_genesis 737 'Returns a struct describing the XML-RPC specifications supported by this server'
mp-wp_genesis 738 );
mp-wp_genesis 739 $this->addCallback(
mp-wp_genesis 740 'system.listMethods',
mp-wp_genesis 741 'this:listMethods',
mp-wp_genesis 742 array('array'),
mp-wp_genesis 743 'Returns an array of available methods on this server'
mp-wp_genesis 744 );
mp-wp_genesis 745 $this->addCallback(
mp-wp_genesis 746 'system.methodHelp',
mp-wp_genesis 747 'this:methodHelp',
mp-wp_genesis 748 array('string', 'string'),
mp-wp_genesis 749 'Returns a documentation string for the specified method'
mp-wp_genesis 750 );
mp-wp_genesis 751 }
mp-wp_genesis 752 function addCallback($method, $callback, $args, $help) {
mp-wp_genesis 753 $this->callbacks[$method] = $callback;
mp-wp_genesis 754 $this->signatures[$method] = $args;
mp-wp_genesis 755 $this->help[$method] = $help;
mp-wp_genesis 756 }
mp-wp_genesis 757 function call($methodname, $args) {
mp-wp_genesis 758 // Make sure it's in an array
mp-wp_genesis 759 if ($args && !is_array($args)) {
mp-wp_genesis 760 $args = array($args);
mp-wp_genesis 761 }
mp-wp_genesis 762 // Over-rides default call method, adds signature check
mp-wp_genesis 763 if (!$this->hasMethod($methodname)) {
mp-wp_genesis 764 return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
mp-wp_genesis 765 }
mp-wp_genesis 766 $method = $this->callbacks[$methodname];
mp-wp_genesis 767 $signature = $this->signatures[$methodname];
mp-wp_genesis 768 $returnType = array_shift($signature);
mp-wp_genesis 769 // Check the number of arguments
mp-wp_genesis 770 if (count($args) != count($signature)) {
mp-wp_genesis 771 return new IXR_Error(-32602, 'server error. wrong number of method parameters');
mp-wp_genesis 772 }
mp-wp_genesis 773 // Check the argument types
mp-wp_genesis 774 $ok = true;
mp-wp_genesis 775 $argsbackup = $args;
mp-wp_genesis 776 for ($i = 0, $j = count($args); $i < $j; $i++) {
mp-wp_genesis 777 $arg = array_shift($args);
mp-wp_genesis 778 $type = array_shift($signature);
mp-wp_genesis 779 switch ($type) {
mp-wp_genesis 780 case 'int':
mp-wp_genesis 781 case 'i4':
mp-wp_genesis 782 if (is_array($arg) || !is_int($arg)) {
mp-wp_genesis 783 $ok = false;
mp-wp_genesis 784 }
mp-wp_genesis 785 break;
mp-wp_genesis 786 case 'base64':
mp-wp_genesis 787 case 'string':
mp-wp_genesis 788 if (!is_string($arg)) {
mp-wp_genesis 789 $ok = false;
mp-wp_genesis 790 }
mp-wp_genesis 791 break;
mp-wp_genesis 792 case 'boolean':
mp-wp_genesis 793 if ($arg !== false && $arg !== true) {
mp-wp_genesis 794 $ok = false;
mp-wp_genesis 795 }
mp-wp_genesis 796 break;
mp-wp_genesis 797 case 'float':
mp-wp_genesis 798 case 'double':
mp-wp_genesis 799 if (!is_float($arg)) {
mp-wp_genesis 800 $ok = false;
mp-wp_genesis 801 }
mp-wp_genesis 802 break;
mp-wp_genesis 803 case 'date':
mp-wp_genesis 804 case 'dateTime.iso8601':
mp-wp_genesis 805 if (!is_a($arg, 'IXR_Date')) {
mp-wp_genesis 806 $ok = false;
mp-wp_genesis 807 }
mp-wp_genesis 808 break;
mp-wp_genesis 809 }
mp-wp_genesis 810 if (!$ok) {
mp-wp_genesis 811 return new IXR_Error(-32602, 'server error. invalid method parameters');
mp-wp_genesis 812 }
mp-wp_genesis 813 }
mp-wp_genesis 814 // It passed the test - run the "real" method call
mp-wp_genesis 815 return parent::call($methodname, $argsbackup);
mp-wp_genesis 816 }
mp-wp_genesis 817 function methodSignature($method) {
mp-wp_genesis 818 if (!$this->hasMethod($method)) {
mp-wp_genesis 819 return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
mp-wp_genesis 820 }
mp-wp_genesis 821 // We should be returning an array of types
mp-wp_genesis 822 $types = $this->signatures[$method];
mp-wp_genesis 823 $return = array();
mp-wp_genesis 824 foreach ($types as $type) {
mp-wp_genesis 825 switch ($type) {
mp-wp_genesis 826 case 'string':
mp-wp_genesis 827 $return[] = 'string';
mp-wp_genesis 828 break;
mp-wp_genesis 829 case 'int':
mp-wp_genesis 830 case 'i4':
mp-wp_genesis 831 $return[] = 42;
mp-wp_genesis 832 break;
mp-wp_genesis 833 case 'double':
mp-wp_genesis 834 $return[] = 3.1415;
mp-wp_genesis 835 break;
mp-wp_genesis 836 case 'dateTime.iso8601':
mp-wp_genesis 837 $return[] = new IXR_Date(time());
mp-wp_genesis 838 break;
mp-wp_genesis 839 case 'boolean':
mp-wp_genesis 840 $return[] = true;
mp-wp_genesis 841 break;
mp-wp_genesis 842 case 'base64':
mp-wp_genesis 843 $return[] = new IXR_Base64('base64');
mp-wp_genesis 844 break;
mp-wp_genesis 845 case 'array':
mp-wp_genesis 846 $return[] = array('array');
mp-wp_genesis 847 break;
mp-wp_genesis 848 case 'struct':
mp-wp_genesis 849 $return[] = array('struct' => 'struct');
mp-wp_genesis 850 break;
mp-wp_genesis 851 }
mp-wp_genesis 852 }
mp-wp_genesis 853 return $return;
mp-wp_genesis 854 }
mp-wp_genesis 855 function methodHelp($method) {
mp-wp_genesis 856 return $this->help[$method];
mp-wp_genesis 857 }
mp-wp_genesis 858 }
mp-wp_genesis 859
mp-wp_genesis 860 /**
mp-wp_genesis 861 * IXR_ClientMulticall
mp-wp_genesis 862 *
mp-wp_genesis 863 * @package IXR
mp-wp_genesis 864 * @since 1.5
mp-wp_genesis 865 */
mp-wp_genesis 866 class IXR_ClientMulticall extends IXR_Client {
mp-wp_genesis 867 var $calls = array();
mp-wp_genesis 868 function IXR_ClientMulticall($server, $path = false, $port = 80) {
mp-wp_genesis 869 parent::IXR_Client($server, $path, $port);
mp-wp_genesis 870 $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
mp-wp_genesis 871 }
mp-wp_genesis 872 function addCall() {
mp-wp_genesis 873 $args = func_get_args();
mp-wp_genesis 874 $methodName = array_shift($args);
mp-wp_genesis 875 $struct = array(
mp-wp_genesis 876 'methodName' => $methodName,
mp-wp_genesis 877 'params' => $args
mp-wp_genesis 878 );
mp-wp_genesis 879 $this->calls[] = $struct;
mp-wp_genesis 880 }
mp-wp_genesis 881 function query() {
mp-wp_genesis 882 // Prepare multicall, then call the parent::query() method
mp-wp_genesis 883 return parent::query('system.multicall', $this->calls);
mp-wp_genesis 884 }
mp-wp_genesis 885 }
mp-wp_genesis 886
mp-wp_genesis 887 ?>