[ Index ] |
|
Code source de phpMyVisites 2.3 |
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.99 2006/06/16 16:00:54 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.0 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.0 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.0 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.0 1161 * @link http://pear.php.net/package/XML_RPC 1162 */ 1163 class XML_RPC_Message extends XML_RPC_Base 1164 { 1165 /** 1166 * The current debug mode (1 = on, 0 = off) 1167 * @var integer 1168 */ 1169 var $debug = 0; 1170 1171 /** 1172 * The encoding to be used for outgoing messages 1173 * 1174 * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var> 1175 * 1176 * @var string 1177 * @see XML_RPC_Message::setSendEncoding(), 1178 * $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header() 1179 */ 1180 var $send_encoding = ''; 1181 1182 /** 1183 * The method presently being evaluated 1184 * @var string 1185 */ 1186 var $methodname = ''; 1187 1188 /** 1189 * @var array 1190 */ 1191 var $params = array(); 1192 1193 /** 1194 * The XML message being generated 1195 * @var string 1196 */ 1197 var $payload = ''; 1198 1199 /** 1200 * Should extra line breaks be removed from the payload? 1201 * @since Property available since Release 1.4.6 1202 * @var boolean 1203 */ 1204 var $remove_extra_lines = true; 1205 1206 /** 1207 * The XML response from the remote server 1208 * @since Property available since Release 1.4.6 1209 * @var string 1210 */ 1211 var $response_payload = ''; 1212 1213 1214 /** 1215 * @return void 1216 */ 1217 function XML_RPC_Message($meth, $pars = 0) 1218 { 1219 $this->methodname = $meth; 1220 if (is_array($pars) && sizeof($pars) > 0) { 1221 for ($i = 0; $i < sizeof($pars); $i++) { 1222 $this->addParam($pars[$i]); 1223 } 1224 } 1225 } 1226 1227 /** 1228 * Produces the XML declaration including the encoding attribute 1229 * 1230 * The encoding is determined by this class' <var>$send_encoding</var> 1231 * property. If the <var>$send_encoding</var> property is not set, use 1232 * <var>$GLOBALS['XML_RPC_defencoding']</var>. 1233 * 1234 * @return string the XML declaration and <methodCall> element 1235 * 1236 * @see XML_RPC_Message::setSendEncoding(), 1237 * XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding'] 1238 */ 1239 function xml_header() 1240 { 1241 global $XML_RPC_defencoding; 1242 1243 if (!$this->send_encoding) { 1244 $this->send_encoding = $XML_RPC_defencoding; 1245 } 1246 return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>' 1247 . "\n<methodCall>\n"; 1248 } 1249 1250 /** 1251 * @return string the closing </methodCall> tag 1252 */ 1253 function xml_footer() 1254 { 1255 return "</methodCall>\n"; 1256 } 1257 1258 /** 1259 * Fills the XML_RPC_Message::$payload property 1260 * 1261 * Part of the process makes sure all line endings are in DOS format 1262 * (CRLF), which is probably required by specifications. 1263 * 1264 * If PHP's mbstring extension is enabled, the mb_convert_encoding() 1265 * function is used to ensure the payload matches the encoding set in the 1266 * XML declaration. The encoding type can be manually set via 1267 * XML_RPC_Message::setSendEncoding(). 1268 * 1269 * @return void 1270 * 1271 * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer() 1272 * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'] 1273 */ 1274 function createPayload() 1275 { 1276 $this->payload = $this->xml_header(); 1277 $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n"; 1278 $this->payload .= "<params>\n"; 1279 for ($i = 0; $i < sizeof($this->params); $i++) { 1280 $p = $this->params[$i]; 1281 $this->payload .= "<param>\n" . $p->serialize() . "</param>\n"; 1282 } 1283 $this->payload .= "</params>\n"; 1284 $this->payload .= $this->xml_footer(); 1285 if ($this->remove_extra_lines) { 1286 $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("[\r\n]+", "\r\n", $this->payload); 1287 } else { 1288 $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("\r\n|\n|\r|\n\r", "\r\n", $this->payload); 1289 } 1290 if (function_exists('mb_convert_encoding')) { 1291 $this->payload = mb_convert_encoding($this->payload, $this->send_encoding); 1292 } 1293 } 1294 1295 /** 1296 * @return string the name of the method 1297 */ 1298 function method($meth = '') 1299 { 1300 if ($meth != '') { 1301 $this->methodname = $meth; 1302 } 1303 return $this->methodname; 1304 } 1305 1306 /** 1307 * @return string the payload 1308 */ 1309 function serialize() 1310 { 1311 $this->createPayload(); 1312 return $this->payload; 1313 } 1314 1315 /** 1316 * @return void 1317 */ 1318 function addParam($par) 1319 { 1320 $this->params[] = $par; 1321 } 1322 1323 /** 1324 * Obtains an XML_RPC_Value object for the given parameter 1325 * 1326 * @param int $i the index number of the parameter to obtain 1327 * 1328 * @return object the XML_RPC_Value object. 1329 * If the parameter doesn't exist, an XML_RPC_Response object. 1330 * 1331 * @since Returns XML_RPC_Response object on error since Release 1.3.0 1332 */ 1333 function getParam($i) 1334 { 1335 global $XML_RPC_err, $XML_RPC_str; 1336 1337 if (isset($this->params[$i])) { 1338 return $this->params[$i]; 1339 } else { 1340 $this->raiseError('The submitted request did not contain this parameter', 1341 XML_RPC_ERROR_INCORRECT_PARAMS); 1342 return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], 1343 $XML_RPC_str['incorrect_params']); 1344 } 1345 } 1346 1347 /** 1348 * @return int the number of parameters 1349 */ 1350 function getNumParams() 1351 { 1352 return sizeof($this->params); 1353 } 1354 1355 /** 1356 * Sets the XML declaration's encoding attribute 1357 * 1358 * @param string $type the encoding type (ISO-8859-1, UTF-8 or US-ASCII) 1359 * 1360 * @return void 1361 * 1362 * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header() 1363 * @since Method available since Release 1.2.0 1364 */ 1365 function setSendEncoding($type) 1366 { 1367 $this->send_encoding = $type; 1368 } 1369 1370 /** 1371 * Determine the XML's encoding via the encoding attribute 1372 * in the XML declaration 1373 * 1374 * If the encoding parameter is not set or is not ISO-8859-1, UTF-8 1375 * or US-ASCII, $XML_RPC_defencoding will be returned. 1376 * 1377 * @param string $data the XML that will be parsed 1378 * 1379 * @return string the encoding to be used 1380 * 1381 * @link http://php.net/xml_parser_create 1382 * @since Method available since Release 1.2.0 1383 */ 1384 function getEncoding($data) 1385 { 1386 global $XML_RPC_defencoding; 1387 1388 if ($GLOBALS['XML_RPC_func_ereg']('<\?xml[^>]*[:space:]*encoding[:space:]*=[:space:]*[\'"]([^"\']*)[\'"]', 1389 $data, $match)) 1390 { 1391 $match[1] = trim(strtoupper($match[1])); 1392 switch ($match[1]) { 1393 case 'ISO-8859-1': 1394 case 'UTF-8': 1395 case 'US-ASCII': 1396 return $match[1]; 1397 break; 1398 1399 default: 1400 return $XML_RPC_defencoding; 1401 } 1402 } else { 1403 return $XML_RPC_defencoding; 1404 } 1405 } 1406 1407 /** 1408 * @return object a new XML_RPC_Response object 1409 */ 1410 function parseResponseFile($fp) 1411 { 1412 $ipd = ''; 1413 while ($data = @fread($fp, 8192)) { 1414 $ipd .= $data; 1415 } 1416 return $this->parseResponse($ipd); 1417 } 1418 1419 /** 1420 * @return object a new XML_RPC_Response object 1421 */ 1422 function parseResponse($data = '') 1423 { 1424 global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding; 1425 1426 $encoding = $this->getEncoding($data); 1427 $parser_resource = xml_parser_create($encoding); 1428 $parser = (int) $parser_resource; 1429 1430 $XML_RPC_xh = array(); 1431 $XML_RPC_xh[$parser] = array(); 1432 1433 $XML_RPC_xh[$parser]['cm'] = 0; 1434 $XML_RPC_xh[$parser]['isf'] = 0; 1435 $XML_RPC_xh[$parser]['ac'] = ''; 1436 $XML_RPC_xh[$parser]['qt'] = ''; 1437 $XML_RPC_xh[$parser]['stack'] = array(); 1438 $XML_RPC_xh[$parser]['valuestack'] = array(); 1439 1440 xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); 1441 xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); 1442 xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); 1443 1444 $hdrfnd = 0; 1445 if ($this->debug) { 1446 print "\n<pre>---GOT---\n"; 1447 print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data; 1448 print "\n---END---</pre>\n"; 1449 } 1450 1451 // See if response is a 200 or a 100 then a 200, else raise error. 1452 // But only do this if we're using the HTTP protocol. 1453 if ($GLOBALS['XML_RPC_func_ereg']('^HTTP', $data) && 1454 !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 200 ', $data) && 1455 !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200', $data)) 1456 { 1457 $errstr = substr($data, 0, strpos($data, "\n") - 1); 1458 error_log('HTTP error, got response: ' . $errstr); 1459 $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], 1460 $XML_RPC_str['http_error'] . ' (' . 1461 $errstr . ')'); 1462 xml_parser_free($parser_resource); 1463 return $r; 1464 } 1465 1466 // gotta get rid of headers here 1467 if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { 1468 $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); 1469 $data = substr($data, $brpos + 4); 1470 $hdrfnd = 1; 1471 } 1472 1473 /* 1474 * be tolerant of junk after methodResponse 1475 * (e.g. javascript automatically inserted by free hosts) 1476 * thanks to Luca Mariano <luca.mariano@email.it> 1477 */ 1478 $data = substr($data, 0, strpos($data, "</methodResponse>") + 17); 1479 $this->response_payload = $data; 1480 1481 if (!xml_parse($parser_resource, $data, sizeof($data))) { 1482 // thanks to Peter Kocks <peter.kocks@baygate.com> 1483 if (xml_get_current_line_number($parser_resource) == 1) { 1484 $errstr = 'XML error at line 1, check URL'; 1485 } else { 1486 $errstr = sprintf('XML error: %s at line %d', 1487 xml_error_string(xml_get_error_code($parser_resource)), 1488 xml_get_current_line_number($parser_resource)); 1489 } 1490 error_log($errstr); 1491 $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], 1492 $XML_RPC_str['invalid_return']); 1493 xml_parser_free($parser_resource); 1494 return $r; 1495 } 1496 1497 xml_parser_free($parser_resource); 1498 1499 if ($this->debug) { 1500 print "\n<pre>---PARSED---\n"; 1501 var_dump($XML_RPC_xh[$parser]['value']); 1502 print "---END---</pre>\n"; 1503 } 1504 1505 if ($XML_RPC_xh[$parser]['isf'] > 1) { 1506 $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], 1507 $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']); 1508 } elseif (!is_object($XML_RPC_xh[$parser]['value'])) { 1509 // then something odd has happened 1510 // and it's time to generate a client side error 1511 // indicating something odd went on 1512 $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], 1513 $XML_RPC_str['invalid_return']); 1514 } else { 1515 $v = $XML_RPC_xh[$parser]['value']; 1516 $allOK=1; 1517 if ($XML_RPC_xh[$parser]['isf']) { 1518 $f = $v->structmem('faultCode'); 1519 $fs = $v->structmem('faultString'); 1520 $r = new XML_RPC_Response($v, $f->scalarval(), 1521 $fs->scalarval()); 1522 } else { 1523 $r = new XML_RPC_Response($v); 1524 } 1525 } 1526 $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); 1527 return $r; 1528 } 1529 } 1530 1531 /** 1532 * The methods and properties that represent data in XML RPC format 1533 * 1534 * @category Web Services 1535 * @package XML_RPC 1536 * @author Edd Dumbill <edd@usefulinc.com> 1537 * @author Stig Bakken <stig@php.net> 1538 * @author Martin Jansen <mj@php.net> 1539 * @author Daniel Convissor <danielc@php.net> 1540 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 1541 * @version Release: 1.5.0 1542 * @link http://pear.php.net/package/XML_RPC 1543 */ 1544 class XML_RPC_Value extends XML_RPC_Base 1545 { 1546 var $me = array(); 1547 var $mytype = 0; 1548 1549 /** 1550 * @return void 1551 */ 1552 function XML_RPC_Value($val = -1, $type = '') 1553 { 1554 $this->me = array(); 1555 $this->mytype = 0; 1556 if ($val != -1 || $type != '') { 1557 if ($type == '') { 1558 $type = 'string'; 1559 } 1560 if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) { 1561 // XXX 1562 // need some way to report this error 1563 } elseif ($GLOBALS['XML_RPC_Types'][$type] == 1) { 1564 $this->addScalar($val, $type); 1565 } elseif ($GLOBALS['XML_RPC_Types'][$type] == 2) { 1566 $this->addArray($val); 1567 } elseif ($GLOBALS['XML_RPC_Types'][$type] == 3) { 1568 $this->addStruct($val); 1569 } 1570 } 1571 } 1572 1573 /** 1574 * @return int returns 1 if successful or 0 if there are problems 1575 */ 1576 function addScalar($val, $type = 'string') 1577 { 1578 if ($this->mytype == 1) { 1579 $this->raiseError('Scalar can have only one value', 1580 XML_RPC_ERROR_INVALID_TYPE); 1581 return 0; 1582 } 1583 $typeof = $GLOBALS['XML_RPC_Types'][$type]; 1584 if ($typeof != 1) { 1585 $this->raiseError("Not a scalar type ($typeof})", 1586 XML_RPC_ERROR_INVALID_TYPE); 1587 return 0; 1588 } 1589 1590 if ($type == $GLOBALS['XML_RPC_Boolean']) { 1591 if (strcasecmp($val, 'true') == 0 1592 || $val == 1 1593 || ($val == true && strcasecmp($val, 'false'))) 1594 { 1595 $val = 1; 1596 } else { 1597 $val = 0; 1598 } 1599 } 1600 1601 if ($this->mytype == 2) { 1602 // we're adding to an array here 1603 $ar = $this->me['array']; 1604 $ar[] = new XML_RPC_Value($val, $type); 1605 $this->me['array'] = $ar; 1606 } else { 1607 // a scalar, so set the value and remember we're scalar 1608 $this->me[$type] = $val; 1609 $this->mytype = $typeof; 1610 } 1611 return 1; 1612 } 1613 1614 /** 1615 * @return int returns 1 if successful or 0 if there are problems 1616 */ 1617 function addArray($vals) 1618 { 1619 if ($this->mytype != 0) { 1620 $this->raiseError( 1621 'Already initialized as a [' . $this->kindOf() . ']', 1622 XML_RPC_ERROR_ALREADY_INITIALIZED); 1623 return 0; 1624 } 1625 $this->mytype = $GLOBALS['XML_RPC_Types']['array']; 1626 $this->me['array'] = $vals; 1627 return 1; 1628 } 1629 1630 /** 1631 * @return int returns 1 if successful or 0 if there are problems 1632 */ 1633 function addStruct($vals) 1634 { 1635 if ($this->mytype != 0) { 1636 $this->raiseError( 1637 'Already initialized as a [' . $this->kindOf() . ']', 1638 XML_RPC_ERROR_ALREADY_INITIALIZED); 1639 return 0; 1640 } 1641 $this->mytype = $GLOBALS['XML_RPC_Types']['struct']; 1642 $this->me['struct'] = $vals; 1643 return 1; 1644 } 1645 1646 /** 1647 * @return void 1648 */ 1649 function dump($ar) 1650 { 1651 reset($ar); 1652 foreach ($ar as $key => $val) { 1653 echo "$key => $val<br />"; 1654 if ($key == 'array') { 1655 foreach ($val as $key2 => $val2) { 1656 echo "-- $key2 => $val2<br />"; 1657 } 1658 } 1659 } 1660 } 1661 1662 /** 1663 * @return string the data type of the current value 1664 */ 1665 function kindOf() 1666 { 1667 switch ($this->mytype) { 1668 case 3: 1669 return 'struct'; 1670 1671 case 2: 1672 return 'array'; 1673 1674 case 1: 1675 return 'scalar'; 1676 1677 default: 1678 return 'undef'; 1679 } 1680 } 1681 1682 /** 1683 * @return string the data in XML format 1684 */ 1685 function serializedata($typ, $val) 1686 { 1687 $rs = ''; 1688 if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) { 1689 // XXX 1690 // need some way to report this error 1691 return; 1692 } 1693 switch ($GLOBALS['XML_RPC_Types'][$typ]) { 1694 case 3: 1695 // struct 1696 $rs .= "<struct>\n"; 1697 reset($val); 1698 foreach ($val as $key2 => $val2) { 1699 $rs .= "<member><name>$key2}</name>\n"; 1700 $rs .= $this->serializeval($val2); 1701 $rs .= "</member>\n"; 1702 } 1703 $rs .= '</struct>'; 1704 break; 1705 1706 case 2: 1707 // array 1708 $rs .= "<array>\n<data>\n"; 1709 for ($i = 0; $i < sizeof($val); $i++) { 1710 $rs .= $this->serializeval($val[$i]); 1711 } 1712 $rs .= "</data>\n</array>"; 1713 break; 1714 1715 case 1: 1716 switch ($typ) { 1717 case $GLOBALS['XML_RPC_Base64']: 1718 $rs .= "<$typ}>" . base64_encode($val) . "</$typ}>"; 1719 break; 1720 case $GLOBALS['XML_RPC_Boolean']: 1721 $rs .= "<$typ}>" . ($val ? '1' : '0') . "</$typ}>"; 1722 break; 1723 case $GLOBALS['XML_RPC_String']: 1724 $rs .= "<$typ}>" . htmlspecialchars($val). "</$typ}>"; 1725 break; 1726 default: 1727 $rs .= "<$typ}>$val}</$typ}>"; 1728 } 1729 } 1730 return $rs; 1731 } 1732 1733 /** 1734 * @return string the data in XML format 1735 */ 1736 function serialize() 1737 { 1738 return $this->serializeval($this); 1739 } 1740 1741 /** 1742 * @return string the data in XML format 1743 */ 1744 function serializeval($o) 1745 { 1746 if (!is_object($o) || empty($o->me) || !is_array($o->me)) { 1747 return ''; 1748 } 1749 $ar = $o->me; 1750 reset($ar); 1751 list($typ, $val) = each($ar); 1752 return '<value>' . $this->serializedata($typ, $val) . "</value>\n"; 1753 } 1754 1755 /** 1756 * @return mixed the contents of the element requested 1757 */ 1758 function structmem($m) 1759 { 1760 return $this->me['struct'][$m]; 1761 } 1762 1763 /** 1764 * @return void 1765 */ 1766 function structreset() 1767 { 1768 reset($this->me['struct']); 1769 } 1770 1771 /** 1772 * @return the key/value pair of the struct's current element 1773 */ 1774 function structeach() 1775 { 1776 return each($this->me['struct']); 1777 } 1778 1779 /** 1780 * @return mixed the current value 1781 */ 1782 function getval() 1783 { 1784 // UNSTABLE 1785 1786 reset($this->me); 1787 $b = current($this->me); 1788 1789 // contributed by I Sofer, 2001-03-24 1790 // add support for nested arrays to scalarval 1791 // i've created a new method here, so as to 1792 // preserve back compatibility 1793 1794 if (is_array($b)) { 1795 foreach ($b as $id => $cont) { 1796 $b[$id] = $cont->scalarval(); 1797 } 1798 } 1799 1800 // add support for structures directly encoding php objects 1801 if (is_object($b)) { 1802 $t = get_object_vars($b); 1803 foreach ($t as $id => $cont) { 1804 $t[$id] = $cont->scalarval(); 1805 } 1806 foreach ($t as $id => $cont) { 1807 $b->$id = $cont; 1808 } 1809 } 1810 1811 // end contrib 1812 return $b; 1813 } 1814 1815 /** 1816 * @return mixed 1817 */ 1818 function scalarval() 1819 { 1820 reset($this->me); 1821 return current($this->me); 1822 } 1823 1824 /** 1825 * @return string 1826 */ 1827 function scalartyp() 1828 { 1829 reset($this->me); 1830 $a = key($this->me); 1831 if ($a == $GLOBALS['XML_RPC_I4']) { 1832 $a = $GLOBALS['XML_RPC_Int']; 1833 } 1834 return $a; 1835 } 1836 1837 /** 1838 * @return mixed the struct's current element 1839 */ 1840 function arraymem($m) 1841 { 1842 return $this->me['array'][$m]; 1843 } 1844 1845 /** 1846 * @return int the number of elements in the array 1847 */ 1848 function arraysize() 1849 { 1850 reset($this->me); 1851 list($a, $b) = each($this->me); 1852 return sizeof($b); 1853 } 1854 1855 /** 1856 * Determines if the item submitted is an XML_RPC_Value object 1857 * 1858 * @param mixed $val the variable to be evaluated 1859 * 1860 * @return bool TRUE if the item is an XML_RPC_Value object 1861 * 1862 * @static 1863 * @since Method available since Release 1.3.0 1864 */ 1865 function isValue($val) 1866 { 1867 return (strtolower(get_class($val)) == 'xml_rpc_value'); 1868 } 1869 } 1870 1871 /** 1872 * Return an ISO8601 encoded string 1873 * 1874 * While timezones ought to be supported, the XML-RPC spec says: 1875 * 1876 * "Don't assume a timezone. It should be specified by the server in its 1877 * documentation what assumptions it makes about timezones." 1878 * 1879 * This routine always assumes localtime unless $utc is set to 1, in which 1880 * case UTC is assumed and an adjustment for locale is made when encoding. 1881 * 1882 * @return string the formatted date 1883 */ 1884 function XML_RPC_iso8601_encode($timet, $utc = 0) 1885 { 1886 if (!$utc) { 1887 $t = strftime('%Y%m%dT%H:%M:%S', $timet); 1888 } else { 1889 if (function_exists('gmstrftime')) { 1890 // gmstrftime doesn't exist in some versions 1891 // of PHP 1892 $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); 1893 } else { 1894 $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); 1895 } 1896 } 1897 return $t; 1898 } 1899 1900 /** 1901 * Convert a datetime string into a Unix timestamp 1902 * 1903 * While timezones ought to be supported, the XML-RPC spec says: 1904 * 1905 * "Don't assume a timezone. It should be specified by the server in its 1906 * documentation what assumptions it makes about timezones." 1907 * 1908 * This routine always assumes localtime unless $utc is set to 1, in which 1909 * case UTC is assumed and an adjustment for locale is made when encoding. 1910 * 1911 * @return int the unix timestamp of the date submitted 1912 */ 1913 function XML_RPC_iso8601_decode($idate, $utc = 0) 1914 { 1915 $t = 0; 1916 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)) { 1917 if ($utc) { 1918 $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 1919 } else { 1920 $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 1921 } 1922 } 1923 return $t; 1924 } 1925 1926 /** 1927 * Converts an XML_RPC_Value object into native PHP types 1928 * 1929 * @param object $XML_RPC_val the XML_RPC_Value object to decode 1930 * 1931 * @return mixed the PHP values 1932 */ 1933 function XML_RPC_decode($XML_RPC_val) 1934 { 1935 $kind = $XML_RPC_val->kindOf(); 1936 1937 if ($kind == 'scalar') { 1938 return $XML_RPC_val->scalarval(); 1939 1940 } elseif ($kind == 'array') { 1941 $size = $XML_RPC_val->arraysize(); 1942 $arr = array(); 1943 for ($i = 0; $i < $size; $i++) { 1944 $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); 1945 } 1946 return $arr; 1947 1948 } elseif ($kind == 'struct') { 1949 $XML_RPC_val->structreset(); 1950 $arr = array(); 1951 while (list($key, $value) = $XML_RPC_val->structeach()) { 1952 $arr[$key] = XML_RPC_decode($value); 1953 } 1954 return $arr; 1955 } 1956 } 1957 1958 /** 1959 * Converts native PHP types into an XML_RPC_Value object 1960 * 1961 * @param mixed $php_val the PHP value or variable you want encoded 1962 * 1963 * @return object the XML_RPC_Value object 1964 */ 1965 function XML_RPC_encode($php_val) 1966 { 1967 $type = gettype($php_val); 1968 $XML_RPC_val = new XML_RPC_Value; 1969 1970 switch ($type) { 1971 case 'array': 1972 if (empty($php_val)) { 1973 $XML_RPC_val->addArray($php_val); 1974 break; 1975 } 1976 $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); 1977 if (empty($tmp)) { 1978 $arr = array(); 1979 foreach ($php_val as $k => $v) { 1980 $arr[$k] = XML_RPC_encode($v); 1981 } 1982 $XML_RPC_val->addArray($arr); 1983 break; 1984 } 1985 // fall though if it's not an enumerated array 1986 1987 case 'object': 1988 $arr = array(); 1989 foreach ($php_val as $k => $v) { 1990 $arr[$k] = XML_RPC_encode($v); 1991 } 1992 $XML_RPC_val->addStruct($arr); 1993 break; 1994 1995 case 'integer': 1996 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']); 1997 break; 1998 1999 case 'double': 2000 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']); 2001 break; 2002 2003 case 'string': 2004 case 'NULL': 2005 if ($GLOBALS['XML_RPC_func_ereg']('^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$', $php_val)) { 2006 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']); 2007 } elseif ($GLOBALS['XML_RPC_auto_base64'] 2008 && $GLOBALS['XML_RPC_func_ereg']("[^ -~\t\r\n]", $php_val)) 2009 { 2010 // Characters other than alpha-numeric, punctuation, SP, TAB, 2011 // LF and CR break the XML parser, encode value via Base 64. 2012 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']); 2013 } else { 2014 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']); 2015 } 2016 break; 2017 2018 case 'boolean': 2019 // Add support for encoding/decoding of booleans, since they 2020 // are supported in PHP 2021 // by <G_Giunta_2001-02-29> 2022 $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']); 2023 break; 2024 2025 case 'unknown type': 2026 default: 2027 $XML_RPC_val = false; 2028 } 2029 return $XML_RPC_val; 2030 } 2031 2032 /* 2033 * Local variables: 2034 * tab-width: 4 2035 * c-basic-offset: 4 2036 * c-hanging-comment-ender-p: nil 2037 * End: 2038 */ 2039 2040 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Mon Nov 26 14:10:01 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |