[ Index ] |
PHP Cross Reference of BackPress |
[Summary view] [Print] [Text view]
1 <?php 2 // Last sync [WP16063] 3 /** 4 * IXR - The Incutio XML-RPC Library 5 * 6 * Copyright (c) 2010, Incutio Ltd. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * - Neither the name of Incutio Ltd. nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 29 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 31 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * @package IXR 34 * @since 1.5 35 * 36 * @copyright Incutio Ltd 2010 (http://www.incutio.com) 37 * @version 1.7.4 7th September 2010 38 * @author Simon Willison 39 * @link http://scripts.incutio.com/xmlrpc/ Site/manual 40 * @license http://www.opensource.org/licenses/bsd-license.php BSD 41 */ 42 43 /** 44 * IXR_Value 45 * 46 * @package IXR 47 * @since 1.5 48 */ 49 class IXR_Value { 50 var $data; 51 var $type; 52 53 function __construct($data, $type = false) 54 { 55 $this->data = $data; 56 if (!$type) { 57 $type = $this->calculateType(); 58 } 59 $this->type = $type; 60 if ($type == 'struct') { 61 // Turn all the values in the array in to new IXR_Value objects 62 foreach ($this->data as $key => $value) { 63 $this->data[$key] = new IXR_Value($value); 64 } 65 } 66 if ($type == 'array') { 67 for ($i = 0, $j = count($this->data); $i < $j; $i++) { 68 $this->data[$i] = new IXR_Value($this->data[$i]); 69 } 70 } 71 } 72 73 function IXR_Value($data, $type = false) 74 { 75 self::__construct($data, $type); 76 } 77 78 function calculateType() 79 { 80 if ($this->data === true || $this->data === false) { 81 return 'boolean'; 82 } 83 if (is_integer($this->data)) { 84 return 'int'; 85 } 86 if (is_double($this->data)) { 87 return 'double'; 88 } 89 90 // Deal with IXR object types base64 and date 91 if (is_object($this->data) && is_a($this->data, 'IXR_Date')) { 92 return 'date'; 93 } 94 if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) { 95 return 'base64'; 96 } 97 98 // If it is a normal PHP object convert it in to a struct 99 if (is_object($this->data)) { 100 $this->data = get_object_vars($this->data); 101 return 'struct'; 102 } 103 if (!is_array($this->data)) { 104 return 'string'; 105 } 106 107 // We have an array - is it an array or a struct? 108 if ($this->isStruct($this->data)) { 109 return 'struct'; 110 } else { 111 return 'array'; 112 } 113 } 114 115 function getXml() 116 { 117 // Return XML for this value 118 switch ($this->type) { 119 case 'boolean': 120 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>'; 121 break; 122 case 'int': 123 return '<int>'.$this->data.'</int>'; 124 break; 125 case 'double': 126 return '<double>'.$this->data.'</double>'; 127 break; 128 case 'string': 129 return '<string>'.htmlspecialchars($this->data).'</string>'; 130 break; 131 case 'array': 132 $return = '<array><data>'."\n"; 133 foreach ($this->data as $item) { 134 $return .= ' <value>'.$item->getXml()."</value>\n"; 135 } 136 $return .= '</data></array>'; 137 return $return; 138 break; 139 case 'struct': 140 $return = '<struct>'."\n"; 141 foreach ($this->data as $name => $value) { 142 $name = htmlspecialchars($name); 143 $return .= " <member><name>$name</name><value>"; 144 $return .= $value->getXml()."</value></member>\n"; 145 } 146 $return .= '</struct>'; 147 return $return; 148 break; 149 case 'date': 150 case 'base64': 151 return $this->data->getXml(); 152 break; 153 } 154 return false; 155 } 156 157 /** 158 * Checks whether or not the supplied array is a struct or not 159 * 160 * @param unknown_type $array 161 * @return boolean 162 */ 163 function isStruct($array) 164 { 165 $expected = 0; 166 foreach ($array as $key => $value) { 167 if ((string)$key != (string)$expected) { 168 return true; 169 } 170 $expected++; 171 } 172 return false; 173 } 174 } 175 176 /** 177 * IXR_MESSAGE 178 * 179 * @package IXR 180 * @since 1.5 181 * 182 */ 183 class IXR_Message 184 { 185 var $message; 186 var $messageType; // methodCall / methodResponse / fault 187 var $faultCode; 188 var $faultString; 189 var $methodName; 190 var $params; 191 192 // Current variable stacks 193 var $_arraystructs = array(); // The stack used to keep track of the current array/struct 194 var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array 195 var $_currentStructName = array(); // A stack as well 196 var $_param; 197 var $_value; 198 var $_currentTag; 199 var $_currentTagContents; 200 // The XML parser 201 var $_parser; 202 203 function __construct($message) 204 { 205 $this->message =& $message; 206 } 207 208 function IXR_Message($message) 209 { 210 self::__construct($message); 211 } 212 213 function parse() 214 { 215 // first remove the XML declaration 216 // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages 217 $header = preg_replace( '/<\?xml.*?\?'.'>/', '', substr($this->message, 0, 100), 1); 218 $this->message = substr_replace($this->message, $header, 0, 100); 219 if (trim($this->message) == '') { 220 return false; 221 } 222 $this->_parser = xml_parser_create(); 223 // Set XML parser to take the case of tags in to account 224 xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); 225 // Set XML parser callback functions 226 xml_set_object($this->_parser, $this); 227 xml_set_element_handler($this->_parser, 'tag_open', 'tag_close'); 228 xml_set_character_data_handler($this->_parser, 'cdata'); 229 $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages 230 do { 231 if (strlen($this->message) <= $chunk_size) { 232 $final = true; 233 } 234 $part = substr($this->message, 0, $chunk_size); 235 $this->message = substr($this->message, $chunk_size); 236 if (!xml_parse($this->_parser, $part, $final)) { 237 return false; 238 } 239 if ($final) { 240 break; 241 } 242 } while (true); 243 xml_parser_free($this->_parser); 244 245 // Grab the error messages, if any 246 if ($this->messageType == 'fault') { 247 $this->faultCode = $this->params[0]['faultCode']; 248 $this->faultString = $this->params[0]['faultString']; 249 } 250 return true; 251 } 252 253 function tag_open($parser, $tag, $attr) 254 { 255 $this->_currentTagContents = ''; 256 $this->currentTag = $tag; 257 switch($tag) { 258 case 'methodCall': 259 case 'methodResponse': 260 case 'fault': 261 $this->messageType = $tag; 262 break; 263 /* Deal with stacks of arrays and structs */ 264 case 'data': // data is to all intents and puposes more interesting than array 265 $this->_arraystructstypes[] = 'array'; 266 $this->_arraystructs[] = array(); 267 break; 268 case 'struct': 269 $this->_arraystructstypes[] = 'struct'; 270 $this->_arraystructs[] = array(); 271 break; 272 } 273 } 274 275 function cdata($parser, $cdata) 276 { 277 $this->_currentTagContents .= $cdata; 278 } 279 280 function tag_close($parser, $tag) 281 { 282 $valueFlag = false; 283 switch($tag) { 284 case 'int': 285 case 'i4': 286 $value = (int)trim($this->_currentTagContents); 287 $valueFlag = true; 288 break; 289 case 'double': 290 $value = (double)trim($this->_currentTagContents); 291 $valueFlag = true; 292 break; 293 case 'string': 294 $value = (string)trim($this->_currentTagContents); 295 $valueFlag = true; 296 break; 297 case 'dateTime.iso8601': 298 $value = new IXR_Date(trim($this->_currentTagContents)); 299 $valueFlag = true; 300 break; 301 case 'value': 302 // "If no type is indicated, the type is string." 303 if (trim($this->_currentTagContents) != '') { 304 $value = (string)$this->_currentTagContents; 305 $valueFlag = true; 306 } 307 break; 308 case 'boolean': 309 $value = (boolean)trim($this->_currentTagContents); 310 $valueFlag = true; 311 break; 312 case 'base64': 313 $value = base64_decode($this->_currentTagContents); 314 $valueFlag = true; 315 break; 316 /* Deal with stacks of arrays and structs */ 317 case 'data': 318 case 'struct': 319 $value = array_pop($this->_arraystructs); 320 array_pop($this->_arraystructstypes); 321 $valueFlag = true; 322 break; 323 case 'member': 324 array_pop($this->_currentStructName); 325 break; 326 case 'name': 327 $this->_currentStructName[] = trim($this->_currentTagContents); 328 break; 329 case 'methodName': 330 $this->methodName = trim($this->_currentTagContents); 331 break; 332 } 333 334 if ($valueFlag) { 335 if (count($this->_arraystructs) > 0) { 336 // Add value to struct or array 337 if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') { 338 // Add to struct 339 $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value; 340 } else { 341 // Add to array 342 $this->_arraystructs[count($this->_arraystructs)-1][] = $value; 343 } 344 } else { 345 // Just add as a paramater 346 $this->params[] = $value; 347 } 348 } 349 $this->_currentTagContents = ''; 350 } 351 } 352 353 /** 354 * IXR_Server 355 * 356 * @package IXR 357 * @since 1.5 358 */ 359 class IXR_Server 360 { 361 var $data; 362 var $callbacks = array(); 363 var $message; 364 var $capabilities; 365 366 function __construct($callbacks = false, $data = false, $wait = false) 367 { 368 $this->setCapabilities(); 369 if ($callbacks) { 370 $this->callbacks = $callbacks; 371 } 372 $this->setCallbacks(); 373 if (!$wait) { 374 $this->serve($data); 375 } 376 } 377 378 function IXR_Server($callbacks = false, $data = false, $wait = false) 379 { 380 self::__construct($callbacks, $data, $wait); 381 } 382 383 function serve($data = false) 384 { 385 if (!$data) { 386 if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') { 387 header('Content-Type: text/plain'); // merged from WP #9093 388 die('XML-RPC server accepts POST requests only.'); 389 } 390 391 global $HTTP_RAW_POST_DATA; 392 if (empty($HTTP_RAW_POST_DATA)) { 393 // workaround for a bug in PHP 5.2.2 - http://bugs.php.net/bug.php?id=41293 394 $data = file_get_contents('php://input'); 395 } else { 396 $data =& $HTTP_RAW_POST_DATA; 397 } 398 } 399 $this->message = new IXR_Message($data); 400 if (!$this->message->parse()) { 401 $this->error(-32700, 'parse error. not well formed'); 402 } 403 if ($this->message->messageType != 'methodCall') { 404 $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall'); 405 } 406 $result = $this->call($this->message->methodName, $this->message->params); 407 408 // Is the result an error? 409 if (is_a($result, 'IXR_Error')) { 410 $this->error($result); 411 } 412 413 // Encode the result 414 $r = new IXR_Value($result); 415 $resultxml = $r->getXml(); 416 417 // Create the XML 418 $xml = <<<EOD 419 <methodResponse> 420 <params> 421 <param> 422 <value> 423 $resultxml 424 </value> 425 </param> 426 </params> 427 </methodResponse> 428 429 EOD; 430 // Send it 431 $this->output($xml); 432 } 433 434 function call($methodname, $args) 435 { 436 if (!$this->hasMethod($methodname)) { 437 return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.'); 438 } 439 $method = $this->callbacks[$methodname]; 440 441 // Perform the callback and send the response 442 if (count($args) == 1) { 443 // If only one paramater just send that instead of the whole array 444 $args = $args[0]; 445 } 446 447 // Are we dealing with a function or a method? 448 if (is_string($method) && substr($method, 0, 5) == 'this:') { 449 // It's a class method - check it exists 450 $method = substr($method, 5); 451 if (!method_exists($this, $method)) { 452 return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.'); 453 } 454 455 //Call the method 456 $result = $this->$method($args); 457 } else { 458 // It's a function - does it exist? 459 if (is_array($method)) { 460 if (!method_exists($method[0], $method[1])) { 461 return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.'); 462 } 463 } else if (!function_exists($method)) { 464 return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.'); 465 } 466 467 // Call the function 468 $result = call_user_func($method, $args); 469 } 470 return $result; 471 } 472 473 function error($error, $message = false) 474 { 475 // Accepts either an error object or an error code and message 476 if ($message && !is_object($error)) { 477 $error = new IXR_Error($error, $message); 478 } 479 $this->output($error->getXml()); 480 } 481 482 function output($xml) 483 { 484 $xml = '<?xml version="1.0"?>'."\n".$xml; 485 $length = strlen($xml); 486 header('Connection: close'); 487 header('Content-Length: '.$length); 488 header('Content-Type: text/xml'); 489 header('Date: '.date('r')); 490 echo $xml; 491 exit; 492 } 493 494 function hasMethod($method) 495 { 496 return in_array($method, array_keys($this->callbacks)); 497 } 498 499 function setCapabilities() 500 { 501 // Initialises capabilities array 502 $this->capabilities = array( 503 'xmlrpc' => array( 504 'specUrl' => 'http://www.xmlrpc.com/spec', 505 'specVersion' => 1 506 ), 507 'faults_interop' => array( 508 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', 509 'specVersion' => 20010516 510 ), 511 'system.multicall' => array( 512 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', 513 'specVersion' => 1 514 ), 515 ); 516 } 517 518 function getCapabilities($args) 519 { 520 return $this->capabilities; 521 } 522 523 function setCallbacks() 524 { 525 $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; 526 $this->callbacks['system.listMethods'] = 'this:listMethods'; 527 $this->callbacks['system.multicall'] = 'this:multiCall'; 528 } 529 530 function listMethods($args) 531 { 532 // Returns a list of methods - uses array_reverse to ensure user defined 533 // methods are listed before server defined methods 534 return array_reverse(array_keys($this->callbacks)); 535 } 536 537 function multiCall($methodcalls) 538 { 539 // See http://www.xmlrpc.com/discuss/msgReader$1208 540 $return = array(); 541 foreach ($methodcalls as $call) { 542 $method = $call['methodName']; 543 $params = $call['params']; 544 if ($method == 'system.multicall') { 545 $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden'); 546 } else { 547 $result = $this->call($method, $params); 548 } 549 if (is_a($result, 'IXR_Error')) { 550 $return[] = array( 551 'faultCode' => $result->code, 552 'faultString' => $result->message 553 ); 554 } else { 555 $return[] = array($result); 556 } 557 } 558 return $return; 559 } 560 } 561 562 /** 563 * IXR_Request 564 * 565 * @package IXR 566 * @since 1.5 567 */ 568 class IXR_Request 569 { 570 var $method; 571 var $args; 572 var $xml; 573 574 function __construct($method, $args) 575 { 576 $this->method = $method; 577 $this->args = $args; 578 $this->xml = <<<EOD 579 <?xml version="1.0"?> 580 <methodCall> 581 <methodName>{$this->method}</methodName> 582 <params> 583 584 EOD; 585 foreach ($this->args as $arg) { 586 $this->xml .= '<param><value>'; 587 $v = new IXR_Value($arg); 588 $this->xml .= $v->getXml(); 589 $this->xml .= "</value></param>\n"; 590 } 591 $this->xml .= '</params></methodCall>'; 592 } 593 594 function IXR_Request($method, $args) 595 { 596 self::__construct($method, $args); 597 } 598 599 function getLength() 600 { 601 return strlen($this->xml); 602 } 603 604 function getXml() 605 { 606 return $this->xml; 607 } 608 } 609 610 /** 611 * IXR_Client 612 * 613 * @package IXR 614 * @since 1.5 615 * 616 */ 617 class IXR_Client 618 { 619 var $server; 620 var $port; 621 var $path; 622 var $useragent; 623 var $response; 624 var $message = false; 625 var $debug = false; 626 var $timeout; 627 var $headers = array(); 628 629 // Storage place for an error message 630 var $error = false; 631 632 function __construct($server, $path = false, $port = 80, $timeout = 15) 633 { 634 if (!$path) { 635 // Assume we have been given a URL instead 636 $bits = parse_url($server); 637 $this->server = $bits['host']; 638 $this->port = isset($bits['port']) ? $bits['port'] : 80; 639 $this->path = isset($bits['path']) ? $bits['path'] : '/'; 640 641 // Make absolutely sure we have a path 642 if (!$this->path) { 643 $this->path = '/'; 644 } 645 } else { 646 $this->server = $server; 647 $this->path = $path; 648 $this->port = $port; 649 } 650 $this->useragent = 'The Incutio XML-RPC PHP Library'; 651 $this->timeout = $timeout; 652 } 653 654 function IXR_Client($server, $path = false, $port = 80, $timeout = 15) 655 { 656 self::__construct($server, $path, $port, $timeout); 657 } 658 659 function query() 660 { 661 $args = func_get_args(); 662 $method = array_shift($args); 663 $request = new IXR_Request($method, $args); 664 $length = $request->getLength(); 665 $xml = $request->getXml(); 666 $r = "\r\n"; 667 $request = "POST {$this->path} HTTP/1.0$r"; 668 669 // Merged from WP #8145 - allow custom headers 670 $this->headers['Host'] = $this->server; 671 $this->headers['Content-Type'] = 'text/xml'; 672 $this->headers['User-Agent'] = $this->useragent; 673 $this->headers['Content-Length']= $length; 674 675 foreach( $this->headers as $header => $value ) { 676 $request .= "{$header}: {$value}{$r}"; 677 } 678 $request .= $r; 679 680 $request .= $xml; 681 682 // Now send the request 683 if ($this->debug) { 684 echo '<pre class="ixr_request">'.htmlspecialchars($request)."\n</pre>\n\n"; 685 } 686 687 if ($this->timeout) { 688 $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout); 689 } else { 690 $fp = @fsockopen($this->server, $this->port, $errno, $errstr); 691 } 692 if (!$fp) { 693 $this->error = new IXR_Error(-32300, 'transport error - could not open socket'); 694 return false; 695 } 696 fputs($fp, $request); 697 $contents = ''; 698 $debugContents = ''; 699 $gotFirstLine = false; 700 $gettingHeaders = true; 701 while (!feof($fp)) { 702 $line = fgets($fp, 4096); 703 if (!$gotFirstLine) { 704 // Check line for '200' 705 if (strstr($line, '200') === false) { 706 $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200'); 707 return false; 708 } 709 $gotFirstLine = true; 710 } 711 if (trim($line) == '') { 712 $gettingHeaders = false; 713 } 714 if (!$gettingHeaders) { 715 // merged from WP #12559 - remove trim 716 $contents .= $line; 717 } 718 if ($this->debug) { 719 $debugContents .= $line; 720 } 721 } 722 if ($this->debug) { 723 echo '<pre class="ixr_response">'.htmlspecialchars($debugContents)."\n</pre>\n\n"; 724 } 725 726 // Now parse what we've got back 727 $this->message = new IXR_Message($contents); 728 if (!$this->message->parse()) { 729 // XML error 730 $this->error = new IXR_Error(-32700, 'parse error. not well formed'); 731 return false; 732 } 733 734 // Is the message a fault? 735 if ($this->message->messageType == 'fault') { 736 $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString); 737 return false; 738 } 739 740 // Message must be OK 741 return true; 742 } 743 744 function getResponse() 745 { 746 // methodResponses can only have one param - return that 747 return $this->message->params[0]; 748 } 749 750 function isError() 751 { 752 return (is_object($this->error)); 753 } 754 755 function getErrorCode() 756 { 757 return $this->error->code; 758 } 759 760 function getErrorMessage() 761 { 762 return $this->error->message; 763 } 764 } 765 766 767 /** 768 * IXR_Error 769 * 770 * @package IXR 771 * @since 1.5 772 */ 773 class IXR_Error 774 { 775 var $code; 776 var $message; 777 778 function __construct($code, $message) 779 { 780 $this->code = $code; 781 $this->message = htmlspecialchars($message); 782 } 783 784 function IXR_Error($code, $message) 785 { 786 self::__construct($code, $message); 787 } 788 789 function getXml() 790 { 791 $xml = <<<EOD 792 <methodResponse> 793 <fault> 794 <value> 795 <struct> 796 <member> 797 <name>faultCode</name> 798 <value><int>{$this->code}</int></value> 799 </member> 800 <member> 801 <name>faultString</name> 802 <value><string>{$this->message}</string></value> 803 </member> 804 </struct> 805 </value> 806 </fault> 807 </methodResponse> 808 809 EOD; 810 return $xml; 811 } 812 } 813 814 /** 815 * IXR_Date 816 * 817 * @package IXR 818 * @since 1.5 819 */ 820 class IXR_Date { 821 var $year; 822 var $month; 823 var $day; 824 var $hour; 825 var $minute; 826 var $second; 827 var $timezone; 828 829 function __construct($time) 830 { 831 // $time can be a PHP timestamp or an ISO one 832 if (is_numeric($time)) { 833 $this->parseTimestamp($time); 834 } else { 835 $this->parseIso($time); 836 } 837 } 838 839 function IXR_Date($time) 840 { 841 self::__construct($time); 842 } 843 844 function parseTimestamp($timestamp) 845 { 846 $this->year = date('Y', $timestamp); 847 $this->month = date('m', $timestamp); 848 $this->day = date('d', $timestamp); 849 $this->hour = date('H', $timestamp); 850 $this->minute = date('i', $timestamp); 851 $this->second = date('s', $timestamp); 852 $this->timezone = ''; 853 } 854 855 function parseIso($iso) 856 { 857 $this->year = substr($iso, 0, 4); 858 $this->month = substr($iso, 4, 2); 859 $this->day = substr($iso, 6, 2); 860 $this->hour = substr($iso, 9, 2); 861 $this->minute = substr($iso, 12, 2); 862 $this->second = substr($iso, 15, 2); 863 $this->timezone = substr($iso, 17); 864 } 865 866 function getIso() 867 { 868 return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone; 869 } 870 871 function getXml() 872 { 873 return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>'; 874 } 875 876 function getTimestamp() 877 { 878 return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); 879 } 880 } 881 882 /** 883 * IXR_Base64 884 * 885 * @package IXR 886 * @since 1.5 887 */ 888 class IXR_Base64 889 { 890 var $data; 891 892 function __construct($data) 893 { 894 $this->data = $data; 895 } 896 897 function IXR_Base64($data) 898 { 899 self::__construct($data); 900 } 901 902 function getXml() 903 { 904 return '<base64>'.base64_encode($this->data).'</base64>'; 905 } 906 } 907 908 /** 909 * IXR_IntrospectionServer 910 * 911 * @package IXR 912 * @since 1.5 913 */ 914 class IXR_IntrospectionServer extends IXR_Server 915 { 916 var $signatures; 917 var $help; 918 919 function __construct() 920 { 921 $this->setCallbacks(); 922 $this->setCapabilities(); 923 $this->capabilities['introspection'] = array( 924 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', 925 'specVersion' => 1 926 ); 927 $this->addCallback( 928 'system.methodSignature', 929 'this:methodSignature', 930 array('array', 'string'), 931 'Returns an array describing the return type and required parameters of a method' 932 ); 933 $this->addCallback( 934 'system.getCapabilities', 935 'this:getCapabilities', 936 array('struct'), 937 'Returns a struct describing the XML-RPC specifications supported by this server' 938 ); 939 $this->addCallback( 940 'system.listMethods', 941 'this:listMethods', 942 array('array'), 943 'Returns an array of available methods on this server' 944 ); 945 $this->addCallback( 946 'system.methodHelp', 947 'this:methodHelp', 948 array('string', 'string'), 949 'Returns a documentation string for the specified method' 950 ); 951 } 952 953 function IXR_IntrospectionServer() 954 { 955 self::__construct(); 956 } 957 958 function addCallback($method, $callback, $args, $help) 959 { 960 $this->callbacks[$method] = $callback; 961 $this->signatures[$method] = $args; 962 $this->help[$method] = $help; 963 } 964 965 function call($methodname, $args) 966 { 967 // Make sure it's in an array 968 if ($args && !is_array($args)) { 969 $args = array($args); 970 } 971 972 // Over-rides default call method, adds signature check 973 if (!$this->hasMethod($methodname)) { 974 return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.'); 975 } 976 $method = $this->callbacks[$methodname]; 977 $signature = $this->signatures[$methodname]; 978 $returnType = array_shift($signature); 979 980 // Check the number of arguments 981 if (count($args) != count($signature)) { 982 return new IXR_Error(-32602, 'server error. wrong number of method parameters'); 983 } 984 985 // Check the argument types 986 $ok = true; 987 $argsbackup = $args; 988 for ($i = 0, $j = count($args); $i < $j; $i++) { 989 $arg = array_shift($args); 990 $type = array_shift($signature); 991 switch ($type) { 992 case 'int': 993 case 'i4': 994 if (is_array($arg) || !is_int($arg)) { 995 $ok = false; 996 } 997 break; 998 case 'base64': 999 case 'string': 1000 if (!is_string($arg)) { 1001 $ok = false; 1002 } 1003 break; 1004 case 'boolean': 1005 if ($arg !== false && $arg !== true) { 1006 $ok = false; 1007 } 1008 break; 1009 case 'float': 1010 case 'double': 1011 if (!is_float($arg)) { 1012 $ok = false; 1013 } 1014 break; 1015 case 'date': 1016 case 'dateTime.iso8601': 1017 if (!is_a($arg, 'IXR_Date')) { 1018 $ok = false; 1019 } 1020 break; 1021 } 1022 if (!$ok) { 1023 return new IXR_Error(-32602, 'server error. invalid method parameters'); 1024 } 1025 } 1026 // It passed the test - run the "real" method call 1027 return parent::call($methodname, $argsbackup); 1028 } 1029 1030 function methodSignature($method) 1031 { 1032 if (!$this->hasMethod($method)) { 1033 return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.'); 1034 } 1035 // We should be returning an array of types 1036 $types = $this->signatures[$method]; 1037 $return = array(); 1038 foreach ($types as $type) { 1039 switch ($type) { 1040 case 'string': 1041 $return[] = 'string'; 1042 break; 1043 case 'int': 1044 case 'i4': 1045 $return[] = 42; 1046 break; 1047 case 'double': 1048 $return[] = 3.1415; 1049 break; 1050 case 'dateTime.iso8601': 1051 $return[] = new IXR_Date(time()); 1052 break; 1053 case 'boolean': 1054 $return[] = true; 1055 break; 1056 case 'base64': 1057 $return[] = new IXR_Base64('base64'); 1058 break; 1059 case 'array': 1060 $return[] = array('array'); 1061 break; 1062 case 'struct': 1063 $return[] = array('struct' => 'struct'); 1064 break; 1065 } 1066 } 1067 return $return; 1068 } 1069 1070 function methodHelp($method) 1071 { 1072 return $this->help[$method]; 1073 } 1074 } 1075 1076 /** 1077 * IXR_ClientMulticall 1078 * 1079 * @package IXR 1080 * @since 1.5 1081 */ 1082 class IXR_ClientMulticall extends IXR_Client 1083 { 1084 var $calls = array(); 1085 1086 function __construct($server, $path = false, $port = 80) 1087 { 1088 parent::__construct($server, $path, $port); 1089 $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)'; 1090 } 1091 1092 function IXR_ClientMulticall($server, $path = false, $port = 80) 1093 { 1094 self::__construct($server, $path, $port); 1095 } 1096 1097 function addCall() 1098 { 1099 $args = func_get_args(); 1100 $methodName = array_shift($args); 1101 $struct = array( 1102 'methodName' => $methodName, 1103 'params' => $args 1104 ); 1105 $this->calls[] = $struct; 1106 } 1107 1108 function query() 1109 { 1110 // Prepare multicall, then call the parent::query() method 1111 return parent::query('system.multicall', $this->calls); 1112 } 1113 } 1114 1115 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Dec 26 01:01:01 2024 | Cross-referenced by PHPXref 0.7.1 |