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