[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 4 5 /** 6 * PHP implementation of the XML-RPC protocol 7 * 8 * This is a PEAR-ified version of Useful inc's XML-RPC for PHP. 9 * It has support for HTTP transport, proxies and authentication. 10 * 11 * PHP versions 4 and 5 12 * 13 * LICENSE: License is granted to use or modify this software 14 * ("XML-RPC for PHP") for commercial or non-commercial use provided the 15 * copyright of the author is preserved in any distributed or derivative work. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESSED OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * @category Web Services 29 * @package XML_RPC 30 * @author Edd Dumbill <edd@usefulinc.com> 31 * @author Stig Bakken <stig@php.net> 32 * @author Martin Jansen <mj@php.net> 33 * @author Daniel Convissor <danielc@php.net> 34 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 35 * @version CVS: $Id: RPC.php,v 1.101 2006/10/28 16:42:34 danielc Exp $ 36 * @link http://pear.php.net/package/XML_RPC 37 */ 38 39 40 if (!function_exists('xml_parser_create')) { 41 include_once 'PEAR.php'; 42 PEAR::loadExtension('xml'); 43 } 44 45 /**#@+ 46 * Error constants 47 */ 48 /** 49 * Parameter values don't match parameter types 50 */ 51 define('XML_RPC_ERROR_INVALID_TYPE', 101); 52 /** 53 * Parameter declared to be numeric but the values are not 54 */ 55 define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102); 56 /** 57 * Communication error 58 */ 59 define('XML_RPC_ERROR_CONNECTION_FAILED', 103); 60 /** 61 * The array or struct has already been started 62 */ 63 define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104); 64 /** 65 * Incorrect parameters submitted 66 */ 67 define('XML_RPC_ERROR_INCORRECT_PARAMS', 105); 68 /** 69 * Programming error by developer 70 */ 71 define('XML_RPC_ERROR_PROGRAMMING', 106); 72 /**#@-*/ 73 74 75 /** 76 * Data types 77 * @global string $GLOBALS['XML_RPC_I4'] 78 */ 79 $GLOBALS['XML_RPC_I4'] = 'i4'; 80 81 /** 82 * Data types 83 * @global string $GLOBALS['XML_RPC_Int'] 84 */ 85 $GLOBALS['XML_RPC_Int'] = 'int'; 86 87 /** 88 * Data types 89 * @global string $GLOBALS['XML_RPC_Boolean'] 90 */ 91 $GLOBALS['XML_RPC_Boolean'] = 'boolean'; 92 93 /** 94 * Data types 95 * @global string $GLOBALS['XML_RPC_Double'] 96 */ 97 $GLOBALS['XML_RPC_Double'] = 'double'; 98 99 /** 100 * Data types 101 * @global string $GLOBALS['XML_RPC_String'] 102 */ 103 $GLOBALS['XML_RPC_String'] = 'string'; 104 105 /** 106 * Data types 107 * @global string $GLOBALS['XML_RPC_DateTime'] 108 */ 109 $GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601'; 110 111 /** 112 * Data types 113 * @global string $GLOBALS['XML_RPC_Base64'] 114 */ 115 $GLOBALS['XML_RPC_Base64'] = 'base64'; 116 117 /** 118 * Data types 119 * @global string $GLOBALS['XML_RPC_Array'] 120 */ 121 $GLOBALS['XML_RPC_Array'] = 'array'; 122 123 /** 124 * Data types 125 * @global string $GLOBALS['XML_RPC_Struct'] 126 */ 127 $GLOBALS['XML_RPC_Struct'] = 'struct'; 128 129 130 /** 131 * Data type meta-types 132 * @global array $GLOBALS['XML_RPC_Types'] 133 */ 134 $GLOBALS['XML_RPC_Types'] = array( 135 $GLOBALS['XML_RPC_I4'] => 1, 136 $GLOBALS['XML_RPC_Int'] => 1, 137 $GLOBALS['XML_RPC_Boolean'] => 1, 138 $GLOBALS['XML_RPC_String'] => 1, 139 $GLOBALS['XML_RPC_Double'] => 1, 140 $GLOBALS['XML_RPC_DateTime'] => 1, 141 $GLOBALS['XML_RPC_Base64'] => 1, 142 $GLOBALS['XML_RPC_Array'] => 2, 143 $GLOBALS['XML_RPC_Struct'] => 3, 144 ); 145 146 147 /** 148 * Error message numbers 149 * @global array $GLOBALS['XML_RPC_err'] 150 */ 151 $GLOBALS['XML_RPC_err'] = array( 152 'unknown_method' => 1, 153 'invalid_return' => 2, 154 'incorrect_params' => 3, 155 'introspect_unknown' => 4, 156 'http_error' => 5, 157 'not_response_object' => 6, 158 'invalid_request' => 7, 159 ); 160 161 /** 162 * Error message strings 163 * @global array $GLOBALS['XML_RPC_str'] 164 */ 165 $GLOBALS['XML_RPC_str'] = array( 166 'unknown_method' => 'Unknown method', 167 'invalid_return' => 'Invalid return payload: enable debugging to examine incoming payload', 168 'incorrect_params' => 'Incorrect parameters passed to method', 169 'introspect_unknown' => 'Can\'t introspect: method unknown', 170 'http_error' => 'Didn\'t receive 200 OK from remote server.', 171 'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.', 172 'invalid_request' => 'Invalid request payload', 173 ); 174 175 176 /** 177 * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII) 178 * @global string $GLOBALS['XML_RPC_defencoding'] 179 */ 180 $GLOBALS['XML_RPC_defencoding'] = 'UTF-8'; 181 182 /** 183 * User error codes start at 800 184 * @global int $GLOBALS['XML_RPC_erruser'] 185 */ 186 $GLOBALS['XML_RPC_erruser'] = 800; 187 188 /** 189 * XML parse error codes start at 100 190 * @global int $GLOBALS['XML_RPC_errxml'] 191 */ 192 $GLOBALS['XML_RPC_errxml'] = 100; 193 194 195 /** 196 * Compose backslashes for escaping regexp 197 * @global string $GLOBALS['XML_RPC_backslash'] 198 */ 199 $GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92); 200 201 202 /**#@+ 203 * Which functions to use, depending on whether mbstring is enabled or not. 204 */ 205 if (function_exists('mb_ereg')) { 206 /** @global string $GLOBALS['XML_RPC_func_ereg'] */ 207 $GLOBALS['XML_RPC_func_ereg'] = 'mb_eregi'; 208 /** @global string $GLOBALS['XML_RPC_func_ereg_replace'] */ 209 $GLOBALS['XML_RPC_func_ereg_replace'] = 'mb_eregi_replace'; 210 /** @global string $GLOBALS['XML_RPC_func_split'] */ 211 $GLOBALS['XML_RPC_func_split'] = 'mb_split'; 212 } else { 213 /** @ignore */ 214 $GLOBALS['XML_RPC_func_ereg'] = 'eregi'; 215 /** @ignore */ 216 $GLOBALS['XML_RPC_func_ereg_replace'] = 'eregi_replace'; 217 /** @ignore */ 218 $GLOBALS['XML_RPC_func_split'] = 'split'; 219 } 220 /**#@-*/ 221 222 223 /** 224 * Should we automatically base64 encode strings that contain characters 225 * which can cause PHP's SAX-based XML parser to break? 226 * @global boolean $GLOBALS['XML_RPC_auto_base64'] 227 */ 228 $GLOBALS['XML_RPC_auto_base64'] = false; 229 230 231 /** 232 * Valid parents of XML elements 233 * @global array $GLOBALS['XML_RPC_valid_parents'] 234 */ 235 $GLOBALS['XML_RPC_valid_parents'] = array( 236 'BOOLEAN' => array('VALUE'), 237 'I4' => array('VALUE'), 238 'INT' => array('VALUE'), 239 'STRING' => array('VALUE'), 240 'DOUBLE' => array('VALUE'), 241 'DATETIME.ISO8601' => array('VALUE'), 242 'BASE64' => array('VALUE'), 243 'ARRAY' => array('VALUE'), 244 'STRUCT' => array('VALUE'), 245 'PARAM' => array('PARAMS'), 246 'METHODNAME' => array('METHODCALL'), 247 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), 248 'MEMBER' => array('STRUCT'), 249 'NAME' => array('MEMBER'), 250 'DATA' => array('ARRAY'), 251 'FAULT' => array('METHODRESPONSE'), 252 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), 253 ); 254 255 256 /** 257 * Stores state during parsing 258 * 259 * quick explanation of components: 260 * + ac = accumulates values 261 * + qt = decides if quotes are needed for evaluation 262 * + cm = denotes struct or array (comma needed) 263 * + isf = indicates a fault 264 * + lv = indicates "looking for a value": implements the logic 265 * to allow values with no types to be strings 266 * + params = stores parameters in method calls 267 * + method = stores method name 268 * 269 * @global array $GLOBALS['XML_RPC_xh'] 270 */ 271 $GLOBALS['XML_RPC_xh'] = array(); 272 273 274 /** 275 * Start element handler for the XML parser 276 * 277 * @return void 278 */ 279 function XML_RPC_se($parser_resource, $name, $attrs) 280 { 281 global $XML_RPC_xh, $XML_RPC_valid_parents; 282 283 $parser = (int) $parser_resource; 284 285 // if invalid xmlrpc already detected, skip all processing 286 if ($XML_RPC_xh[$parser]['isf'] >= 2) { 287 return; 288 } 289 290 // check for correct element nesting 291 // top level element can only be of 2 types 292 if (count($XML_RPC_xh[$parser]['stack']) == 0) { 293 if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') { 294 $XML_RPC_xh[$parser]['isf'] = 2; 295 $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element'; 296 return; 297 } 298 } else { 299 // not top level element: see if parent is OK 300 if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) { 301 $name = $GLOBALS['XML_RPC_func_ereg_replace']('[^a-zA-Z0-9._-]', '', $name); 302 $XML_RPC_xh[$parser]['isf'] = 2; 303 $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}"; 304 return; 305 } 306 } 307 308 switch ($name) { 309 case 'STRUCT': 310 $XML_RPC_xh[$parser]['cm']++; 311 312 // turn quoting off 313 $XML_RPC_xh[$parser]['qt'] = 0; 314 315 $cur_val = array(); 316 $cur_val['value'] = array(); 317 $cur_val['members'] = 1; 318 array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); 319 break; 320 321 case 'ARRAY': 322 $XML_RPC_xh[$parser]['cm']++; 323 324 // turn quoting off 325 $XML_RPC_xh[$parser]['qt'] = 0; 326 327 $cur_val = array(); 328 $cur_val['value'] = array(); 329 $cur_val['members'] = 0; 330 array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); 331 break; 332 333 case 'NAME': 334 $XML_RPC_xh[$parser]['ac'] = ''; 335 break; 336 337 case 'FAULT': 338 $XML_RPC_xh[$parser]['isf'] = 1; 339 break; 340 341 case 'PARAM': 342 $XML_RPC_xh[$parser]['valuestack'] = array(); 343 break; 344 345 case 'VALUE': 346 $XML_RPC_xh[$parser]['lv'] = 1; 347 $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_String']; 348 $XML_RPC_xh[$parser]['ac'] = ''; 349 $XML_RPC_xh[$parser]['qt'] = 0; 350 // look for a value: if this is still 1 by the 351 // time we reach the first data segment then the type is string 352 // by implication and we need to add in a quote 353 break; 354 355 case 'I4': 356 case 'INT': 357 case 'STRING': 358 case 'BOOLEAN': 359 case 'DOUBLE': 360 case 'DATETIME.ISO8601': 361 case 'BASE64': 362 $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator 363 364 if ($name == 'DATETIME.ISO8601' || $name == 'STRING') { 365 $XML_RPC_xh[$parser]['qt'] = 1; 366 367 if ($name == 'DATETIME.ISO8601') { 368 $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime']; 369 } 370 371 } elseif ($name == 'BASE64') { 372 $XML_RPC_xh[$parser]['qt'] = 2; 373 } else { 374 // No quoting is required here -- but 375 // at the end of the element we must check 376 // for data format errors. 377 $XML_RPC_xh[$parser]['qt'] = 0; 378 } 379 break; 380 381 case 'MEMBER': 382 $XML_RPC_xh[$parser]['ac'] = ''; 383 break; 384 385 case 'DATA': 386 case 'METHODCALL': 387 case 'METHODNAME': 388 case 'METHODRESPONSE': 389 case 'PARAMS': 390 // valid elements that add little to processing 391 break; 392 } 393 394 395 // Save current element to stack 396 array_unshift($XML_RPC_xh[$parser]['stack'], $name); 397 398 if ($name != 'VALUE') { 399 $XML_RPC_xh[$parser]['lv'] = 0; 400 } 401 } 402 403 /** 404 * End element handler for the XML parser 405 * 406 * @return void 407 */ 408 function XML_RPC_ee($parser_resource, $name) 409 { 410 global $XML_RPC_xh; 411 412 $parser = (int) $parser_resource; 413 414 if ($XML_RPC_xh[$parser]['isf'] >= 2) { 415 return; 416 } 417 418 // push this element from stack 419 // NB: if XML validates, correct opening/closing is guaranteed and 420 // we do not have to check for $name == $curr_elem. 421 // we also checked for proper nesting at start of elements... 422 $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']); 423 424 switch ($name) { 425 case 'STRUCT': 426 case 'ARRAY': 427 $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); 428 $XML_RPC_xh[$parser]['value'] = $cur_val['value']; 429 $XML_RPC_xh[$parser]['vt'] = strtolower($name); 430 $XML_RPC_xh[$parser]['cm']--; 431 break; 432 433 case 'NAME': 434 $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac']; 435 break; 436 437 case 'BOOLEAN': 438 // special case here: we translate boolean 1 or 0 into PHP 439 // constants true or false 440 if ($XML_RPC_xh[$parser]['ac'] == '1') { 441 $XML_RPC_xh[$parser]['ac'] = 'true'; 442 } else { 443 $XML_RPC_xh[$parser]['ac'] = 'false'; 444 } 445 446 $XML_RPC_xh[$parser]['vt'] = strtolower($name); 447 // Drop through intentionally. 448 449 case 'I4': 450 case 'INT': 451 case 'STRING': 452 case 'DOUBLE': 453 case 'DATETIME.ISO8601': 454 case 'BASE64': 455 if ($XML_RPC_xh[$parser]['qt'] == 1) { 456 // we use double quotes rather than single so backslashification works OK 457 $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; 458 } elseif ($XML_RPC_xh[$parser]['qt'] == 2) { 459 $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']); 460 } elseif ($name == 'BOOLEAN') { 461 $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; 462 } else { 463 // we have an I4, INT or a DOUBLE 464 // we must check that only 0123456789-.<space> are characters here 465 if (!$GLOBALS['XML_RPC_func_ereg']("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) { 466 XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE', 467 XML_RPC_ERROR_NON_NUMERIC_FOUND); 468 $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND; 469 } else { 470 // it's ok, add it on 471 $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; 472 } 473 } 474 475 $XML_RPC_xh[$parser]['ac'] = ''; 476 $XML_RPC_xh[$parser]['qt'] = 0; 477 $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value 478 break; 479 480 case 'VALUE': 481 if ($XML_RPC_xh[$parser]['vt'] == $GLOBALS['XML_RPC_String']) { 482 if (strlen($XML_RPC_xh[$parser]['ac']) > 0) { 483 $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; 484 } elseif ($XML_RPC_xh[$parser]['lv'] == 1) { 485 // The <value> element was empty. 486 $XML_RPC_xh[$parser]['value'] = ''; 487 } 488 } 489 490 $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']); 491 492 $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); 493 if (is_array($cur_val)) { 494 if ($cur_val['members']==0) { 495 $cur_val['value'][] = $temp; 496 } else { 497 $XML_RPC_xh[$parser]['value'] = $temp; 498 } 499 array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); 500 } else { 501 $XML_RPC_xh[$parser]['value'] = $temp; 502 } 503 break; 504 505 case 'MEMBER': 506 $XML_RPC_xh[$parser]['ac'] = ''; 507 $XML_RPC_xh[$parser]['qt'] = 0; 508 509 $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); 510 if (is_array($cur_val)) { 511 if ($cur_val['members']==1) { 512 $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value']; 513 } 514 array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); 515 } 516 break; 517 518 case 'DATA': 519 $XML_RPC_xh[$parser]['ac'] = ''; 520 $XML_RPC_xh[$parser]['qt'] = 0; 521 break; 522 523 case 'PARAM': 524 $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value']; 525 break; 526 527 case 'METHODNAME': 528 case 'RPCMETHODNAME': 529 $XML_RPC_xh[$parser]['method'] = $GLOBALS['XML_RPC_func_ereg_replace']("^[\n\r\t ]+", '', 530 $XML_RPC_xh[$parser]['ac']); 531 break; 532 } 533 534 // if it's a valid type name, set the type 535 if (isset($GLOBALS['XML_RPC_Types'][strtolower($name)])) { 536 $XML_RPC_xh[$parser]['vt'] = strtolower($name); 537 } 538 } 539 540 /** 541 * Character data handler for the XML parser 542 * 543 * @return void 544 */ 545 function XML_RPC_cd($parser_resource, $data) 546 { 547 global $XML_RPC_xh, $XML_RPC_backslash; 548 549 $parser = (int) $parser_resource; 550 551 if ($XML_RPC_xh[$parser]['lv'] != 3) { 552 // "lookforvalue==3" means that we've found an entire value 553 // and should discard any further character data 554 555 if ($XML_RPC_xh[$parser]['lv'] == 1) { 556 // if we've found text and we're just in a <value> then 557 // turn quoting on, as this will be a string 558 $XML_RPC_xh[$parser]['qt'] = 1; 559 // and say we've found a value 560 $XML_RPC_xh[$parser]['lv'] = 2; 561 } 562 563 // replace characters that eval would 564 // do special things with 565 if (!isset($XML_RPC_xh[$parser]['ac'])) { 566 $XML_RPC_xh[$parser]['ac'] = ''; 567 } 568 $XML_RPC_xh[$parser]['ac'] .= $data; 569 } 570 } 571 572 /** 573 * The common methods and properties for all of the XML_RPC classes 574 * 575 * @category Web Services 576 * @package XML_RPC 577 * @author Edd Dumbill <edd@usefulinc.com> 578 * @author Stig Bakken <stig@php.net> 579 * @author Martin Jansen <mj@php.net> 580 * @author Daniel Convissor <danielc@php.net> 581 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 582 * @version Release: 1.5.1 583 * @link http://pear.php.net/package/XML_RPC 584 */ 585 class XML_RPC_Base { 586 587 /** 588 * PEAR Error handling 589 * 590 * @return object PEAR_Error object 591 */ 592 function raiseError($msg, $code) 593 { 594 include_once 'PEAR.php'; 595 if (is_object(@$this)) { 596 return PEAR::raiseError(get_class($this) . ': ' . $msg, $code); 597 } else { 598 return PEAR::raiseError('XML_RPC: ' . $msg, $code); 599 } 600 } 601 602 /** 603 * Tell whether something is a PEAR_Error object 604 * 605 * @param mixed $value the item to check 606 * 607 * @return bool whether $value is a PEAR_Error object or not 608 * 609 * @access public 610 */ 611 function isError($value) 612 { 613 return is_a($value, 'PEAR_Error'); 614 } 615 } 616 617 /** 618 * The methods and properties for submitting XML RPC requests 619 * 620 * @category Web Services 621 * @package XML_RPC 622 * @author Edd Dumbill <edd@usefulinc.com> 623 * @author Stig Bakken <stig@php.net> 624 * @author Martin Jansen <mj@php.net> 625 * @author Daniel Convissor <danielc@php.net> 626 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 627 * @version Release: 1.5.1 628 * @link http://pear.php.net/package/XML_RPC 629 */ 630 class XML_RPC_Client extends XML_RPC_Base { 631 632 /** 633 * The path and name of the RPC server script you want the request to go to 634 * @var string 635 */ 636 var $path = ''; 637 638 /** 639 * The name of the remote server to connect to 640 * @var string 641 */ 642 var $server = ''; 643 644 /** 645 * The protocol to use in contacting the remote server 646 * @var string 647 */ 648 var $protocol = 'http://'; 649 650 /** 651 * The port for connecting to the remote server 652 * 653 * The default is 80 for http:// connections 654 * and 443 for https:// and ssl:// connections. 655 * 656 * @var integer 657 */ 658 var $port = 80; 659 660 /** 661 * A user name for accessing the RPC server 662 * @var string 663 * @see XML_RPC_Client::setCredentials() 664 */ 665 var $username = ''; 666 667 /** 668 * A password for accessing the RPC server 669 * @var string 670 * @see XML_RPC_Client::setCredentials() 671 */ 672 var $password = ''; 673 674 /** 675 * The name of the proxy server to use, if any 676 * @var string 677 */ 678 var $proxy = ''; 679 680 /** 681 * The protocol to use in contacting the proxy server, if any 682 * @var string 683 */ 684 var $proxy_protocol = 'http://'; 685 686 /** 687 * The port for connecting to the proxy server 688 * 689 * The default is 8080 for http:// connections 690 * and 443 for https:// and ssl:// connections. 691 * 692 * @var integer 693 */ 694 var $proxy_port = 8080; 695 696 /** 697 * A user name for accessing the proxy server 698 * @var string 699 */ 700 var $proxy_user = ''; 701 702 /** 703 * A password for accessing the proxy server 704 * @var string 705 */ 706 var $proxy_pass = ''; 707 708 /** 709 * The error number, if any 710 * @var integer 711 */ 712 var $errno = 0; 713 714 /** 715 * The error message, if any 716 * @var string 717 */ 718 var $errstr = ''; 719 720 /** 721 * The current debug mode (1 = on, 0 = off) 722 * @var integer 723 */ 724 var $debug = 0; 725 726 /** 727 * The HTTP headers for the current request. 728 * @var string 729 */ 730 var $headers = ''; 731 732 733 /** 734 * Sets the object's properties 735 * 736 * @param string $path the path and name of the RPC server script 737 * you want the request to go to 738 * @param string $server the URL of the remote server to connect to. 739 * If this parameter doesn't specify a 740 * protocol and $port is 443, ssl:// is 741 * assumed. 742 * @param integer $port a port for connecting to the remote server. 743 * Defaults to 80 for http:// connections and 744 * 443 for https:// and ssl:// connections. 745 * @param string $proxy the URL of the proxy server to use, if any. 746 * If this parameter doesn't specify a 747 * protocol and $port is 443, ssl:// is 748 * assumed. 749 * @param integer $proxy_port a port for connecting to the remote server. 750 * Defaults to 8080 for http:// connections and 751 * 443 for https:// and ssl:// connections. 752 * @param string $proxy_user a user name for accessing the proxy server 753 * @param string $proxy_pass a password for accessing the proxy server 754 * 755 * @return void 756 */ 757 function XML_RPC_Client($path, $server, $port = 0, 758 $proxy = '', $proxy_port = 0, 759 $proxy_user = '', $proxy_pass = '') 760 { 761 $this->path = $path; 762 $this->proxy_user = $proxy_user; 763 $this->proxy_pass = $proxy_pass; 764 765 $GLOBALS['XML_RPC_func_ereg']('^(http://|https://|ssl://)?(.*)$', $server, $match); 766 if ($match[1] == '') { 767 if ($port == 443) { 768 $this->server = $match[2]; 769 $this->protocol = 'ssl://'; 770 $this->port = 443; 771 } else { 772 $this->server = $match[2]; 773 if ($port) { 774 $this->port = $port; 775 } 776 } 777 } elseif ($match[1] == 'http://') { 778 $this->server = $match[2]; 779 if ($port) { 780 $this->port = $port; 781 } 782 } else { 783 $this->server = $match[2]; 784 $this->protocol = 'ssl://'; 785 if ($port) { 786 $this->port = $port; 787 } else { 788 $this->port = 443; 789 } 790 } 791 792 if ($proxy) { 793 $GLOBALS['XML_RPC_func_ereg']('^(http://|https://|ssl://)?(.*)$', $proxy, $match); 794 if ($match[1] == '') { 795 if ($proxy_port == 443) { 796 $this->proxy = $match[2]; 797 $this->proxy_protocol = 'ssl://'; 798 $this->proxy_port = 443; 799 } else { 800 $this->proxy = $match[2]; 801 if ($proxy_port) { 802 $this->proxy_port = $proxy_port; 803 } 804 } 805 } elseif ($match[1] == 'http://') { 806 $this->proxy = $match[2]; 807 if ($proxy_port) { 808 $this->proxy_port = $proxy_port; 809 } 810 } else { 811 $this->proxy = $match[2]; 812 $this->proxy_protocol = 'ssl://'; 813 if ($proxy_port) { 814 $this->proxy_port = $proxy_port; 815 } else { 816 $this->proxy_port = 443; 817 } 818 } 819 } 820 } 821 822 /** 823 * Change the current debug mode 824 * 825 * @param int $in where 1 = on, 0 = off 826 * 827 * @return void 828 */ 829 function setDebug($in) 830 { 831 if ($in) { 832 $this->debug = 1; 833 } else { 834 $this->debug = 0; 835 } 836 } 837 838 /** 839 * Sets whether strings that contain characters which may cause PHP's 840 * SAX-based XML parser to break should be automatically base64 encoded 841 * 842 * This is is a workaround for systems that don't have PHP's mbstring 843 * extension available. 844 * 845 * @param int $in where 1 = on, 0 = off 846 * 847 * @return void 848 */ 849 function setAutoBase64($in) 850 { 851 if ($in) { 852 $GLOBALS['XML_RPC_auto_base64'] = true; 853 } else { 854 $GLOBALS['XML_RPC_auto_base64'] = false; 855 } 856 } 857 858 /** 859 * Set username and password properties for connecting to the RPC server 860 * 861 * @param string $u the user name 862 * @param string $p the password 863 * 864 * @return void 865 * 866 * @see XML_RPC_Client::$username, XML_RPC_Client::$password 867 */ 868 function setCredentials($u, $p) 869 { 870 $this->username = $u; 871 $this->password = $p; 872 } 873 874 /** 875 * Transmit the RPC request via HTTP 1.0 protocol 876 * 877 * @param object $msg the XML_RPC_Message object 878 * @param int $timeout how many seconds to wait for the request 879 * 880 * @return object an XML_RPC_Response object. 0 is returned if any 881 * problems happen. 882 * 883 * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(), 884 * XML_RPC_Client::setCredentials() 885 */ 886 function send($msg, $timeout = 0) 887 { 888 if (!is_a($msg, 'XML_RPC_Message')) { 889 $this->errstr = 'send()\'s $msg parameter must be an' 890 . ' XML_RPC_Message object.'; 891 $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING); 892 return 0; 893 } 894 $msg->debug = $this->debug; 895 return $this->sendPayloadHTTP10($msg, $this->server, $this->port, 896 $timeout, $this->username, 897 $this->password); 898 } 899 900 /** 901 * Transmit the RPC request via HTTP 1.0 protocol 902 * 903 * Requests should be sent using XML_RPC_Client send() rather than 904 * calling this method directly. 905 * 906 * @param object $msg the XML_RPC_Message object 907 * @param string $server the server to send the request to 908 * @param int $port the server port send the request to 909 * @param int $timeout how many seconds to wait for the request 910 * before giving up 911 * @param string $username a user name for accessing the RPC server 912 * @param string $password a password for accessing the RPC server 913 * 914 * @return object an XML_RPC_Response object. 0 is returned if any 915 * problems happen. 916 * 917 * @access protected 918 * @see XML_RPC_Client::send() 919 */ 920 function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, 921 $username = '', $password = '') 922 { 923 /* 924 * If we're using a proxy open a socket to the proxy server 925 * instead to the xml-rpc server 926 */ 927 if ($this->proxy) { 928 if ($this->proxy_protocol == 'http://') { 929 $protocol = ''; 930 } else { 931 $protocol = $this->proxy_protocol; 932 } 933 if ($timeout > 0) { 934 $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port, 935 $this->errno, $this->errstr, $timeout); 936 } else { 937 $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port, 938 $this->errno, $this->errstr); 939 } 940 } else { 941 if ($this->protocol == 'http://') { 942 $protocol = ''; 943 } else { 944 $protocol = $this->protocol; 945 } 946 if ($timeout > 0) { 947 $fp = @fsockopen($protocol . $server, $port, 948 $this->errno, $this->errstr, $timeout); 949 } else { 950 $fp = @fsockopen($protocol . $server, $port, 951 $this->errno, $this->errstr); 952 } 953 } 954 955 /* 956 * Just raising the error without returning it is strange, 957 * but keep it here for backwards compatibility. 958 */ 959 if (!$fp && $this->proxy) { 960 $this->raiseError('Connection to proxy server ' 961 . $this->proxy . ':' . $this->proxy_port 962 . ' failed. ' . $this->errstr, 963 XML_RPC_ERROR_CONNECTION_FAILED); 964 return 0; 965 } elseif (!$fp) { 966 $this->raiseError('Connection to RPC server ' 967 . $server . ':' . $port 968 . ' failed. ' . $this->errstr, 969 XML_RPC_ERROR_CONNECTION_FAILED); 970 return 0; 971 } 972 973 if ($timeout) { 974 /* 975 * Using socket_set_timeout() because stream_set_timeout() 976 * was introduced in 4.3.0, but we need to support 4.2.0. 977 */ 978 socket_set_timeout($fp, $timeout); 979 } 980 981 // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly 982 if ($username != $this->username) { 983 $this->setCredentials($username, $password); 984 } 985 986 // Only create the payload if it was not created previously 987 if (empty($msg->payload)) { 988 $msg->createPayload(); 989 } 990 $this->createHeaders($msg); 991 992 $op = $this->headers . "\r\n\r\n"; 993 $op .= $msg->payload; 994 995 if (!fputs($fp, $op, strlen($op))) { 996 $this->errstr = 'Write error'; 997 return 0; 998 } 999 $resp = $msg->parseResponseFile($fp); 1000 1001 $meta = socket_get_status($fp); 1002 if ($meta['timed_out']) { 1003 fclose($fp); 1004 $this->errstr = 'RPC server did not send response before timeout.'; 1005 $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED); 1006 return 0; 1007 } 1008 1009 fclose($fp); 1010 return $resp; 1011 } 1012 1013 /** 1014 * Determines the HTTP headers and puts it in the $headers property 1015 * 1016 * @param object $msg the XML_RPC_Message object 1017 * 1018 * @return boolean TRUE if okay, FALSE if the message payload isn't set. 1019 * 1020 * @access protected 1021 */ 1022 function createHeaders($msg) 1023 { 1024 if (empty($msg->payload)) { 1025 return false; 1026 } 1027 if ($this->proxy) { 1028 $this->headers = 'POST ' . $this->protocol . $this->server; 1029 if ($this->proxy_port) { 1030 $this->headers .= ':' . $this->port; 1031 } 1032 } else { 1033 $this->headers = 'POST '; 1034 } 1035 $this->headers .= $this->path. " HTTP/1.0\r\n"; 1036 1037 $this->headers .= "User-Agent: PEAR XML_RPC\r\n"; 1038 $this->headers .= 'Host: ' . $this->server . "\r\n"; 1039 1040 if ($this->proxy && $this->proxy_user) { 1041 $this->headers .= 'Proxy-Authorization: Basic ' 1042 . base64_encode("$this->proxy_user:$this->proxy_pass") 1043 . "\r\n"; 1044 } 1045 1046 // thanks to Grant Rauscher <grant7@firstworld.net> for this 1047 if ($this->username) { 1048 $this->headers .= 'Authorization: Basic ' 1049 . base64_encode("$this->username:$this->password") 1050 . "\r\n"; 1051 } 1052 1053 $this->headers .= "Content-Type: text/xml\r\n"; 1054 $this->headers .= 'Content-Length: ' . strlen($msg->payload); 1055 return true; 1056 } 1057 } 1058 1059 /** 1060 * The methods and properties for interpreting responses to XML RPC requests 1061 * 1062 * @category Web Services 1063 * @package XML_RPC 1064 * @author Edd Dumbill <edd@usefulinc.com> 1065 * @author Stig Bakken <stig@php.net> 1066 * @author Martin Jansen <mj@php.net> 1067 * @author Daniel Convissor <danielc@php.net> 1068 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 1069 * @version Release: 1.5.1 1070 * @link http://pear.php.net/package/XML_RPC 1071 */ 1072 class XML_RPC_Response extends XML_RPC_Base 1073 { 1074 var $xv; 1075 var $fn; 1076 var $fs; 1077 var $hdrs; 1078 1079 /** 1080 * @return void 1081 */ 1082 function XML_RPC_Response($val, $fcode = 0, $fstr = '') 1083 { 1084 if ($fcode != 0) { 1085 $this->fn = $fcode; 1086 $this->fs = htmlspecialchars($fstr); 1087 } else { 1088 $this->xv = $val; 1089 } 1090 } 1091 1092 /** 1093 * @return int the error code 1094 */ 1095 function faultCode() 1096 { 1097 if (isset($this->fn)) { 1098 return $this->fn; 1099 } else { 1100 return 0; 1101 } 1102 } 1103 1104 /** 1105 * @return string the error string 1106 */ 1107 function faultString() 1108 { 1109 return $this->fs; 1110 } 1111 1112 /** 1113 * @return mixed the value 1114 */ 1115 function value() 1116 { 1117 return $this->xv; 1118 } 1119 1120 /** 1121 * @return string the error message in XML format 1122 */ 1123 function serialize() 1124 { 1125 $rs = "<methodResponse>\n"; 1126 if ($this->fn) { 1127 $rs .= "<fault> 1128 <value> 1129 <struct> 1130 <member> 1131 <name>faultCode</name> 1132 <value><int>" . $this->fn . "</int></value> 1133 </member> 1134 <member> 1135 <name>faultString</name> 1136 <value><string>" . $this->fs . "</string></value> 1137 </member> 1138 </struct> 1139 </value> 1140 </fault>"; 1141 } else { 1142 $rs .= "<params>\n<param>\n" . $this->xv->serialize() . 1143 "</param>\n</params>"; 1144 } 1145 $rs .= "\n</methodResponse>"; 1146 return $rs; 1147 } 1148 } 1149 1150 /** 1151 * The methods and properties for composing XML RPC messages 1152 * 1153 * @category Web Services 1154 * @package XML_RPC 1155 * @author Edd Dumbill <edd@usefulinc.com> 1156 * @author Stig Bakken <stig@php.net> 1157 * @author Martin Jansen <mj@php.net> 1158 * @author Daniel Convissor <danielc@php.net> 1159 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 1160 * @version Release: 1.5.1 1161 * @link http://pear.php.net/package/XML_RPC 1162 */ 1163 class XML_RPC_Message extends XML_RPC_Base 1164 { 1165 /** 1166 * Should the payload's content be passed through mb_convert_encoding()? 1167 * 1168 * @see XML_RPC_Message::setConvertPayloadEncoding() 1169 * @since Property available since Release 1.5.1 1170 * @var boolean 1171 */ 1172 var $convert_payload_encoding = false; 1173 1174 /** 1175 * The current debug mode (1 = on, 0 = off) 1176 * @var integer 1177 */ 1178 var $debug = 0; 1179 1180 /** 1181 * The encoding to be used for outgoing messages 1182 * 1183 * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var> 1184 * 1185 * @var string 1186 * @see XML_RPC_Message::setSendEncoding(), 1187 * $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header() 1188 */ 1189 var $send_encoding = ''; 1190 1191 /** 1192 * The method presently being evaluated 1193 * @var string 1194 */ 1195 var $methodname = ''; 1196 1197 /** 1198 * @var array 1199 */ 1200 var $params = array(); 1201 1202 /** 1203 * The XML message being generated 1204 * @var string 1205 */ 1206 var $payload = ''; 1207 1208 /** 1209 * Should extra line breaks be removed from the payload? 1210 * @since Property available since Release 1.4.6 1211 * @var boolean 1212 */ 1213 var $remove_extra_lines = true; 1214 1215 /** 1216 * The XML response from the remote server 1217 * @since Property available since Release 1.4.6 1218 * @var string 1219 */ 1220 var $response_payload = ''; 1221 1222 1223 /** 1224 * @return void 1225 */ 1226 function XML_RPC_Message($meth, $pars = 0) 1227 { 1228 $this->methodname = $meth; 1229 if (is_array($pars) && sizeof($pars) > 0) { 1230 for ($i = 0; $i < sizeof($pars); $i++) { 1231 $this->addParam($pars[$i]); 1232 } 1233 } 1234 } 1235 1236 /** 1237 * Produces the XML declaration including the encoding attribute 1238 * 1239 * The encoding is determined by this class' <var>$send_encoding</var> 1240 * property. If the <var>$send_encoding</var> property is not set, use 1241 * <var>$GLOBALS['XML_RPC_defencoding']</var>. 1242 * 1243 * @return string the XML declaration and <methodCall> element 1244 * 1245 * @see XML_RPC_Message::setSendEncoding(), 1246 * XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding'] 1247 */ 1248 function xml_header() 1249 { 1250 global $XML_RPC_defencoding; 1251 1252 if (!$this->send_encoding) { 1253 $this->send_encoding = $XML_RPC_defencoding; 1254 } 1255 return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>' 1256 . "\n<methodCall>\n"; 1257 } 1258 1259 /** 1260 * @return string the closing </methodCall> tag 1261 */ 1262 function xml_footer() 1263 { 1264 return "</methodCall>\n"; 1265 } 1266 1267 /** 1268 * Fills the XML_RPC_Message::$payload property 1269 * 1270 * Part of the process makes sure all line endings are in DOS format 1271 * (CRLF), which is probably required by specifications. 1272 * 1273 * If XML_RPC_Message::setConvertPayloadEncoding() was set to true, 1274 * the payload gets passed through mb_convert_encoding() 1275 * to ensure the payload matches the encoding set in the 1276 * XML declaration. The encoding type can be manually set via 1277 * XML_RPC_Message::setSendEncoding(). 1278 * 1279 * @return void 1280 * 1281 * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer() 1282 * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'], 1283 * XML_RPC_Message::setConvertPayloadEncoding() 1284 */ 1285 function createPayload() 1286 { 1287 $this->payload = $this->xml_header(); 1288 $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n"; 1289 $this->payload .= "<params>\n"; 1290 for ($i = 0; $i < sizeof($this->params); $i++) { 1291 $p = $this->params[$i]; 1292 $this->payload .= "<param>\n" . $p->serialize() . "</param>\n"; 1293 } 1294 $this->payload .= "</params>\n"; 1295 $this->payload .= $this->xml_footer(); 1296 if ($this->remove_extra_lines) { 1297 $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("[\r\n]+", "\r\n", $this->payload); 1298 } else { 1299 $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("\r\n|\n|\r|\n\r", "\r\n", $this->payload); 1300 } 1301 if ($this->convert_payload_encoding) { 1302 $this->payload = mb_convert_encoding($this->payload, $this->send_encoding); 1303 } 1304 } 1305 1306 /** 1307 * @return string the name of the method 1308 */ 1309 function method($meth = '') 1310 { 1311 if ($meth != '') { 1312 $this->methodname = $meth; 1313 } 1314 return $this->methodname; 1315 } 1316 1317 /** 1318 * @return string the payload 1319 */ 1320 function serialize() 1321 { 1322 $this->createPayload(); 1323 return $this->payload; 1324 } 1325 1326 /** 1327 * @return void 1328 */ 1329 function addParam($par) 1330 { 1331 $this->params[] = $par; 1332 } 1333 1334 /** 1335 * Obtains an XML_RPC_Value object for the given parameter 1336 * 1337 * @param int $i the index number of the parameter to obtain 1338 * 1339 * @return object the XML_RPC_Value object. 1340 * If the parameter doesn't exist, an XML_RPC_Response object. 1341 * 1342 * @since Returns XML_RPC_Response object on error since Release 1.3.0 1343 */ 1344 function getParam($i) 1345 { 1346 global $XML_RPC_err, $XML_RPC_str; 1347 1348 if (isset($this->params[$i])) { 1349 return $this->params[$i]; 1350 } else { 1351 $this->raiseError('The submitted request did not contain this parameter', 1352 XML_RPC_ERROR_INCORRECT_PARAMS); 1353 return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], 1354 $XML_RPC_str['incorrect_params']); 1355 } 1356 } 1357 1358 /** 1359 * @return int the number of parameters 1360 */ 1361 function getNumParams() 1362 { 1363 return sizeof($this->params); 1364 } 1365 1366 /** 1367 * Sets whether the payload's content gets passed through 1368 * mb_convert_encoding() 1369 * 1370 * Returns PEAR_ERROR object if mb_convert_encoding() isn't available. 1371 * 1372 * @param int $in where 1 = on, 0 = off 1373 * 1374 * @return void 1375 * 1376 * @see XML_RPC_Message::setSendEncoding() 1377 * @since Method available since Release 1.5.1 1378 */ 1379 function setConvertPayloadEncoding($in) 1380 { 1381 if ($in && !function_exists('mb_convert_encoding')) { 1382 return $this->raiseError('mb_convert_encoding() is not available', 1383 XML_RPC_ERROR_PROGRAMMING); 1384 } 1385 $this->convert_payload_encoding = $in; 1386 } 1387 1388 /** 1389 * Sets the XML declaration's encoding attribute 1390 * 1391 * @param string $type the encoding type (ISO-8859-1, UTF-8 or US-ASCII) 1392 * 1393 * @return void 1394 * 1395 * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header() 1396 * @since Method available since Release 1.2.0 1397 */ 1398 function setSendEncoding($type) 1399 { 1400 $this->send_encoding = $type; 1401 } 1402 1403 /** 1404 * Determine the XML's encoding via the encoding attribute 1405 * in the XML declaration 1406 * 1407 * If the encoding parameter is not set or is not ISO-8859-1, UTF-8 1408 * or US-ASCII, $XML_RPC_defencoding will be returned. 1409 * 1410 * @param string $data the XML that will be parsed 1411 * 1412 * @return string the encoding to be used 1413 * 1414 * @link http://php.net/xml_parser_create 1415 * @since Method available since Release 1.2.0 1416 */ 1417 function getEncoding($data) 1418 { 1419 global $XML_RPC_defencoding; 1420 1421 if ($GLOBALS['XML_RPC_func_ereg']('<\?xml[^>]*[:space:]*encoding[:space:]*=[:space:]*[\'"]([^"\']*)[\'"]', 1422 $data, $match)) 1423 { 1424 $match[1] = trim(strtoupper($match[1])); 1425 switch ($match[1]) { 1426 case 'ISO-8859-1': 1427 case 'UTF-8': 1428 case 'US-ASCII': 1429 return $match[1]; 1430 break; 1431 1432 default: 1433 return $XML_RPC_defencoding; 1434 } 1435 } else { 1436 return $XML_RPC_defencoding; 1437 } 1438 } 1439 1440 /** 1441 * @return object a new XML_RPC_Response object 1442 */ 1443 function parseResponseFile($fp) 1444 { 1445 $ipd = ''; 1446 while ($data = @fread($fp, 8192)) { 1447 $ipd .= $data; 1448 } 1449 return $this->parseResponse($ipd); 1450 } 1451 1452 /** 1453 * @return object a new XML_RPC_Response object 1454 */ 1455 function parseResponse($data = '') 1456 { 1457 global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding; 1458 1459 $encoding = $this->getEncoding($data); 1460 $parser_resource = xml_parser_create($encoding); 1461 $parser = (int) $parser_resource; 1462 1463 $XML_RPC_xh = array(); 1464 $XML_RPC_xh[$parser] = array(); 1465 1466 $XML_RPC_xh[$parser]['cm'] = 0; 1467 $XML_RPC_xh[$parser]['isf'] = 0; 1468 $XML_RPC_xh[$parser]['ac'] = ''; 1469 $XML_RPC_xh[$parser]['qt'] = ''; 1470 $XML_RPC_xh[$parser]['stack'] = array(); 1471 $XML_RPC_xh[$parser]['valuestack'] = array(); 1472 1473 xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); 1474 xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); 1475 xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); 1476 1477 $hdrfnd = 0; 1478 if ($this->debug) { 1479 print "\n<pre>---GOT---\n"; 1480 print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data; 1481 print "\n---END---</pre>\n"; 1482 } 1483 1484 // See if response is a 200 or a 100 then a 200, else raise error. 1485 // But only do this if we're using the HTTP protocol. 1486 if ($GLOBALS['XML_RPC_func_ereg']('^HTTP', $data) && 1487 !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 200 ', $data) && 1488 !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200', $data)) 1489 { 1490 $errstr = substr($data, 0, strpos($data, "\n") - 1); 1491 error_log('HTTP error, got response: ' . $errstr); 1492 $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], 1493 $XML_RPC_str['http_error'] . ' (' . 1494 $errstr . ')'); 1495 xml_parser_free($parser_resource); 1496 return $r; 1497 } 1498 1499 // gotta get rid of headers here 1500 if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { 1501 $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); 1502 $data = substr($data, $brpos + 4); 1503 $hdrfnd = 1; 1504 } 1505 1506 /* 1507 * be tolerant of junk after methodResponse 1508 * (e.g. javascript automatically inserted by free hosts) 1509 * thanks to Luca Mariano <luca.mariano@email.it> 1510 */ 1511 $data = substr($data, 0, strpos($data, "</methodResponse>") + 17); 1512 $this->response_payload = $data; 1513 1514 if (!xml_parse($parser_resource, $data, sizeof($data))) { 1515 // thanks to Peter Kocks <peter.kocks@baygate.com> 1516 if (xml_get_current_line_number($parser_resource) == 1) { 1517 $errstr = 'XML error at line 1, check URL'; 1518 } else { 1519 $errstr = sprintf('XML error: %s at line %d', 1520 xml_error_string(xml_get_error_code($parser_resource)), 1521 xml_get_current_line_number($parser_resource)); 1522 } 1523 error_log($errstr); 1524 $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], 1525 $XML_RPC_str['invalid_return']); 1526 xml_parser_free($parser_resource); 1527 return $r; 1528 } 1529 1530 xml_parser_free($parser_resource); 1531 1532 if ($this->debug) { 1533 print "\n<pre>---PARSED---\n"; 1534 var_dump($XML_RPC_xh[$parser]['value']); 1535 print "---END---</pre>\n"; 1536 } 1537 1538 if ($XML_RPC_xh[$parser]['isf'] > 1) { 1539 $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], 1540 $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']); 1541 } elseif (!is_object($XML_RPC_xh[$parser]['value'])) { 1542 // then something odd has happened 1543 // and it's time to generate a client side error 1544 // indicating something odd went on 1545 $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], 1546 $XML_RPC_str['invalid_return']); 1547 } else { 1548 $v = $XML_RPC_xh[$parser]['value']; 1549 if ($XML_RPC_xh[$parser]['isf']) { 1550 $f = $v->structmem('faultCode'); 1551 $fs = $v->structmem('faultString'); 1552 $r = new XML_RPC_Response($v, $f->scalarval(), 1553 $fs->scalarval()); 1554 } else { 1555 $r = new XML_RPC_Response($v); 1556 } 1557 } 1558 $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); 1559 return $r; 1560 } 1561 } 1562 1563 /** 1564 * The methods and properties that represent data in XML RPC format 1565 * 1566 * @category Web Services 1567 * @package XML_RPC 1568 * @author Edd Dumbill <edd@usefulinc.com> 1569 * @author Stig Bakken <stig@php.net> 1570 * @author Martin Jansen <mj@php.net> 1571 * @author Daniel Convissor <danielc@php.net> 1572 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 1573 * @version Release: 1.5.1 1574 * @link http://pear.php.net/package/XML_RPC 1575 */ 1576 class XML_RPC_Value extends XML_RPC_Base 1577 { 1578 var $me = array(); 1579 var $mytype = 0; 1580 1581 /** 1582 * @return void 1583 */ 1584 function XML_RPC_Value($val = -1, $type = '') 1585 { 1586 $this->me = array(); 1587 $this->mytype = 0; 1588 if ($val != -1 || $type != '') { 1589 if ($type == '') { 1590 $type = 'string'; 1591 } 1592 if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) { 1593 // XXX 1594 // need some way to report this error 1595 } elseif ($GLOBALS['XML_RPC_Types'][$type] == 1) { 1596 $this->addScalar($val, $type); 1597 } elseif ($GLOBALS['XML_RPC_Types'][$type] == 2) { 1598 $this->addArray($val); 1599 } elseif ($GLOBALS['XML_RPC_Types'][$type] == 3) { 1600 $this->addStruct($val); 1601 } 1602 } 1603 } 1604 1605 /** 1606 * @return int returns 1 if successful or 0 if there are problems 1607 */ 1608 function addScalar($val, $type = 'string') 1609 { 1610 if ($this->mytype == 1) { 1611 $this->raiseError('Scalar can have only one value', 1612 XML_RPC_ERROR_INVALID_TYPE); 1613 return 0; 1614 } 1615 $typeof = $GLOBALS['XML_RPC_Types'][$type]; 1616 if ($typeof != 1) { 1617 $this->raiseError("Not a scalar type ($typeof})", 1618 XML_RPC_ERROR_INVALID_TYPE); 1619 return 0; 1620 } 1621 1622 if ($type == $GLOBALS['XML_RPC_Boolean']) { 1623 if (strcasecmp($val, 'true') == 0 1624 || $val == 1 1625 || ($val == true && strcasecmp($val, 'false'))) 1626 { 1627 $val = 1; 1628 } else { 1629 $val = 0; 1630 } 1631 } 1632 1633 if ($this->mytype == 2) { 1634 // we're adding to an array here 1635 $ar = $this->me['array']; 1636 $ar[] = new XML_RPC_Value($val, $type); 1637 $this->me['array'] = $ar; 1638 } else { 1639 // a scalar, so set the value and remember we're scalar 1640 $this->me[$type] = $val; 1641 $this->mytype = $typeof; 1642 } 1643 return 1; 1644 } 1645 1646 /** 1647 * @return int returns 1 if successful or 0 if there are problems 1648 */ 1649 function addArray($vals) 1650 { 1651 if ($this->mytype != 0) { 1652 $this->raiseError( 1653 'Already initialized as a [' . $this->kindOf() . ']', 1654 XML_RPC_ERROR_ALREADY_INITIALIZED); 1655 return 0; 1656 } 1657 $this->mytype = $GLOBALS['XML_RPC_Types']['array']; 1658 $this->me['array'] = $vals; 1659 return 1; 1660 } 1661 1662 /** 1663 * @return int returns 1 if successful or 0 if there are problems 1664 */ 1665 function addStruct($vals) 1666 { 1667 if ($this->mytype != 0) { 1668 $this->raiseError( 1669 'Already initialized as a [' . $this->kindOf() . ']', 1670 XML_RPC_ERROR_ALREADY_INITIALIZED); 1671 return 0; 1672 } 1673 $this->mytype = $GLOBALS['XML_RPC_Types']['struct']; 1674 $this->me['struct'] = $vals; 1675 return 1; 1676 } 1677 1678 /** 1679 * @return void 1680 */ 1681 function dump($ar) 1682 { 1683 reset($ar); 1684 foreach ($ar as $key => $val) { 1685 echo "$key => $val<br />"; 1686 if ($key == 'array') { 1687 foreach ($val as $key2 => $val2) { 1688 echo "-- $key2 => $val2<br />"; 1689 } 1690 } 1691 } 1692 } 1693 1694 /** 1695 * @return string the data type of the current value 1696 */ 1697 function kindOf() 1698 { 1699 switch ($this->mytype) { 1700 case 3: 1701 return 'struct'; 1702 1703 case 2: 1704 return 'array'; 1705 1706 case 1: 1707 return 'scalar'; 1708 1709 default: 1710 return 'undef'; 1711 } 1712 } 1713 1714 /** 1715 * @return string the data in XML format 1716 */ 1717 function serializedata($typ, $val) 1718 { 1719 $rs = ''; 1720 if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) { 1721 // XXX 1722 // need some way to report this error 1723 return; 1724 } 1725 switch ($GLOBALS['XML_RPC_Types'][$typ]) { 1726 case 3: 1727 // struct 1728 $rs .= "<struct>\n"; 1729 reset($val); 1730 foreach ($val as $key2 => $val2) { 1731 $rs .= "<member><name>$key2}</name>\n"; 1732 $rs .= $this->serializeval($val2); 1733 $rs .= "</member>\n"; 1734 } 1735 $rs .= '</struct>'; 1736 break; 1737 1738 case 2: 1739 // array 1740 $rs .= "<array>\n<data>\n"; 1741 for ($i = 0; $i < sizeof($val); $i++) { 1742 $rs .= $this->serializeval($val[$i]); 1743 } 1744 $rs .= "</data>\n</array>"; 1745 break; 1746 1747 case 1: 1748 switch ($typ) { 1749 case $GLOBALS['XML_RPC_Base64']: 1750 $rs .= "<$typ}>" . base64_encode($val) . "</$typ}>"; 1751 break; 1752 case $GLOBALS['XML_RPC_Boolean']: 1753 $rs .= "<$typ}>" . ($val ? '1' : '0') . "</$typ}>"; 1754 break; 1755 case $GLOBALS['XML_RPC_String']: 1756 $rs .= "<$typ}>" . htmlspecialchars($val). "</$typ}>"; 1757 break; 1758 default: 1759 $rs .= "<$typ}>$val}</$typ}>"; 1760 } 1761 } 1762 return $rs; 1763 } 1764 1765 /** 1766 * @return string the data in XML format 1767 */ 1768 function serialize() 1769 { 1770 return $this->serializeval($this); 1771 } 1772 1773 /** 1774 * @return string the data in XML format 1775 */ 1776 function serializeval($o) 1777 { 1778 if (!is_object($o) || empty($o->me) || !is_array($o->me)) { 1779 return ''; 1780 } 1781 $ar = $o->me; 1782 reset($ar); 1783 list($typ, $val) = each($ar); 1784 return '<value>' . $this->serializedata($typ, $val) . "</value>\n"; 1785 } 1786 1787 /** 1788 * @return mixed the contents of the element requested 1789 */ 1790 function structmem($m) 1791 { 1792 return $this->me['struct'][$m]; 1793 } 1794 1795 /** 1796 * @return void 1797 */ 1798 function structreset() 1799 { 1800 reset($this->me['struct']); 1801 } 1802 1803 /** 1804 * @return the key/value pair of the struct's current element 1805 */ 1806 function structeach() 1807 { 1808 return each($this->me['struct']); 1809 } 1810 1811 /** 1812 * @return mixed the current value 1813 */ 1814 function getval() 1815 { 1816 // UNSTABLE 1817 1818 reset($this->me); 1819 $b = current($this->me); 1820 1821 // contributed by I Sofer, 2001-03-24 1822 // add support for nested arrays to scalarval 1823 // i've created a new method here, so as to 1824 // preserve back compatibility 1825 1826 if (is_array($b)) { 1827 foreach ($b as $id => $cont) { 1828 $b[$id] = $cont->scalarval(); 1829 } 1830 } 1831 1832 // add support for structures directly encoding php objects 1833 if (is_object($b)) { 1834 $t = get_object_vars($b); 1835 foreach ($t as $id => $cont) { 1836 $t[$id] = $cont->scalarval(); 1837 } 1838 foreach ($t as $id => $cont) { 1839 $b->$id = $cont; 1840 } 1841 } 1842 1843 // end contrib 1844 return $b; 1845 } 1846 1847 /** 1848 * @return mixed the current element's scalar value. If the value is 1849 * not scalar, FALSE is returned. 1850 */ 1851 function scalarval() 1852 { 1853 reset($this->me); 1854 $v = current($this->me); 1855 if (!is_scalar($v)) { 1856 $v = false; 1857 } 1858 return $v; 1859 } 1860 1861 /** 1862 * @return string 1863 */ 1864 function scalartyp() 1865 { 1866 reset($this->me); 1867 $a = key($this->me); 1868 if ($a == $GLOBALS['XML_RPC_I4']) { 1869 $a = $GLOBALS['XML_RPC_Int']; 1870 } 1871 return $a; 1872 } 1873 1874 /** 1875 * @return mixed the struct's current element 1876 */ 1877 function arraymem($m) 1878 { 1879 return $this->me['array'][$m]; 1880 } 1881 1882 /** 1883 * @return int the number of elements in the array 1884 */ 1885 function arraysize() 1886 { 1887 reset($this->me); 1888 list($a, $b) = each($this->me); 1889 return sizeof($b); 1890 } 1891 1892 /** 1893 * Determines if the item submitted is an XML_RPC_Value object 1894 * 1895 * @param mixed $val the variable to be evaluated 1896 * 1897 * @return bool TRUE if the item is an XML_RPC_Value object 1898 * 1899 * @static 1900 * @since Method available since Release 1.3.0 1901 */ 1902 function isValue($val) 1903 { 1904 return (strtolower(get_class($val)) == 'xml_rpc_value'); 1905 } 1906 } 1907 1908 /** 1909 * Return an ISO8601 encoded string 1910 * 1911 * While timezones ought to be supported, the XML-RPC spec says: 1912 * 1913 * "Don't assume a timezone. It should be specified by the server in its 1914 * documentation what assumptions it makes about timezones." 1915 * 1916 * This routine always assumes localtime unless $utc is set to 1, in which 1917 * case UTC is assumed and an adjustment for locale is made when encoding. 1918 * 1919 * @return string the formatted date 1920 */ 1921 function XML_RPC_iso8601_encode($timet, $utc = 0) 1922 { 1923 if (!$utc) { 1924 $t = strftime('%Y%m%dT%H:%M:%S', $timet); 1925 } else { 1926 if (function_exists('gmstrftime')) { 1927 // gmstrftime doesn't exist in some versions 1928 // of PHP 1929 $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); 1930 } else { 1931 $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); 1932 } 1933 } 1934 return $t; 1935 } 1936 1937 /** 1938 * Convert a datetime string into a Unix timestamp 1939 * 1940 * While timezones ought to be supported, the XML-RPC spec says: 1941 * 1942 * "Don't assume a timezone. It should be specified by the server in its 1943 * documentation what assumptions it makes about timezones." 1944 * 1945 * This routine always assumes localtime unless $utc is set to 1, in which 1946 * case UTC is assumed and an adjustment for locale is made when encoding. 1947 * 1948 * @return int the unix timestamp of the date submitted 1949 */ 1950 function XML_RPC_iso8601_decode($idate, $utc = 0) 1951 { 1952 $t = 0; 1953 if ($GLOBALS['XML_RPC_func_ereg']('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { 1954 if ($utc) { 1955 $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 1956 } else { 1957 $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 1958 } 1959 } 1960 return $t; 1961 } 1962 1963 /** 1964 * Converts an XML_RPC_Value object into native PHP types 1965 * 1966 * @param object $XML_RPC_val the XML_RPC_Value object to decode 1967 * 1968 * @return mixed the PHP values 1969 */ 1970 function XML_RPC_decode($XML_RPC_val) 1971 { 1972 $kind = $XML_RPC_val->kindOf(); 1973 1974 if ($kind == 'scalar') { 1975 return $XML_RPC_val->scalarval(); 1976 1977 } elseif ($kind == 'array') { 1978 $size = $XML_RPC_val->arraysize(); 1979 $arr = array(); 1980 for ($i = 0; $i < $size; $i++) { 1981 $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); 1982 } 1983 return $arr; 1984 1985 } elseif ($kind == 'struct') { 1986 $XML_RPC_val->structreset(); 1987 $arr = array(); 1988 while (list($key, $value) = $XML_RPC_val->structeach()) { 1989 $arr[$key] = XML_RPC_decode($value); 1990 } 1991 return $arr; 1992 } 1993 } 1994 1995 /** 1996 * Converts native PHP types into an XML_RPC_Value object 1997 * 1998 * @param mixed $php_val the PHP value or variable you want encoded 1999 * 2000 * @return object the XML_RPC_Value object 2001 */ 2002 function XML_RPC_encode($php_val) 2003 { 2004 $type = gettype($php_val); 2005 $XML_RPC_val = new XML_RPC_Value; 2006 2007 switch ($type) { 2008 case 'array': 2009 if (empty($php_val)) { 2010 $XML_RPC_val->addArray($php_val); 2011 break; 2012 } 2013 $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); 2014 if (empty($tmp)) { 2015 $arr = array(); 2016 foreach ($php_val as $k => $v) { 2017 $arr[$k] = XML_RPC_encode($v); 2018 } 2019 $XML_RPC_val->addArray($arr); 2020 break; 2021 } 2022 // fall though if it's not an enumerated array 2023 2024 case 'object': 2025 $arr = array(); 2026 foreach ($php_val as $k => $v) { 2027 $arr[$k] = XML_RPC_encode($v); 2028 } 2029 $XML_RPC_val->addStruct($arr); 2030 break; 2031 2032 case 'integer': 2033 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']); 2034 break; 2035 2036 case 'double': 2037 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']); 2038 break; 2039 2040 case 'string': 2041 case 'NULL': 2042 if ($GLOBALS['XML_RPC_func_ereg']('^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$', $php_val)) { 2043 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']); 2044 } elseif ($GLOBALS['XML_RPC_auto_base64'] 2045 && $GLOBALS['XML_RPC_func_ereg']("[^ -~\t\r\n]", $php_val)) 2046 { 2047 // Characters other than alpha-numeric, punctuation, SP, TAB, 2048 // LF and CR break the XML parser, encode value via Base 64. 2049 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']); 2050 } else { 2051 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']); 2052 } 2053 break; 2054 2055 case 'boolean': 2056 // Add support for encoding/decoding of booleans, since they 2057 // are supported in PHP 2058 // by <G_Giunta_2001-02-29> 2059 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']); 2060 break; 2061 2062 case 'unknown type': 2063 default: 2064 $XML_RPC_val = false; 2065 } 2066 return $XML_RPC_val; 2067 } 2068 2069 /* 2070 * Local variables: 2071 * tab-width: 4 2072 * c-basic-offset: 4 2073 * c-hanging-comment-ender-p: nil 2074 * End: 2075 */ 2076 2077 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |