├── PEAR.inc ├── PEAR.php ├── array_intersect_key.php ├── license.txt ├── pkg_tester.php ├── test.php ├── version ├── xml_parser.inc ├── xml_serializer.inc ├── xml_unserializer.inc ├── xml_util.inc ├── xmlparse.inc ├── xmlrpc.inc ├── xmlrpc.php ├── xmlrpc ├── echo_time.php ├── version ├── version_base ├── version_comment ├── version_embedded └── version_pfSense ├── xmlrpc_client.inc ├── xmlrpc_server.inc └── xmlrpc_tester.php /PEAR.inc: -------------------------------------------------------------------------------- 1 | 18 | * @author Stig Bakken 19 | * @author Tomas V.V.Cox 20 | * @author Greg Beaver 21 | * @copyright 1997-2005 The PHP Group 22 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 23 | * @version CVS: $Id: PEAR.inc,v 1.1 2005/10/15 20:14:36 colin Exp $ 24 | * @link http://pear.php.net/package/PEAR 25 | * @since File available since Release 0.1 26 | */ 27 | 28 | /**#@+ 29 | * ERROR constants 30 | */ 31 | define('PEAR_ERROR_RETURN', 1); 32 | define('PEAR_ERROR_PRINT', 2); 33 | define('PEAR_ERROR_TRIGGER', 4); 34 | define('PEAR_ERROR_DIE', 8); 35 | define('PEAR_ERROR_CALLBACK', 16); 36 | /** 37 | * WARNING: obsolete 38 | * @deprecated 39 | */ 40 | define('PEAR_ERROR_EXCEPTION', 32); 41 | /**#@-*/ 42 | define('PEAR_ZE2', (function_exists('version_compare') && 43 | version_compare(zend_version(), "2-dev", "ge"))); 44 | 45 | if (substr(PHP_OS, 0, 3) == 'WIN') { 46 | define('OS_WINDOWS', true); 47 | define('OS_UNIX', false); 48 | define('PEAR_OS', 'Windows'); 49 | } else { 50 | define('OS_WINDOWS', false); 51 | define('OS_UNIX', true); 52 | define('PEAR_OS', 'Unix'); // blatant assumption 53 | } 54 | 55 | // instant backwards compatibility 56 | if (!defined('PATH_SEPARATOR')) { 57 | if (OS_WINDOWS) { 58 | define('PATH_SEPARATOR', ';'); 59 | } else { 60 | define('PATH_SEPARATOR', ':'); 61 | } 62 | } 63 | 64 | $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; 65 | $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; 66 | $GLOBALS['_PEAR_destructor_object_list'] = array(); 67 | $GLOBALS['_PEAR_shutdown_funcs'] = array(); 68 | $GLOBALS['_PEAR_error_handler_stack'] = array(); 69 | 70 | @ini_set('track_errors', true); 71 | 72 | /** 73 | * Base class for other PEAR classes. Provides rudimentary 74 | * emulation of destructors. 75 | * 76 | * If you want a destructor in your class, inherit PEAR and make a 77 | * destructor method called _yourclassname (same name as the 78 | * constructor, but with a "_" prefix). Also, in your constructor you 79 | * have to call the PEAR constructor: $this->PEAR();. 80 | * The destructor method will be called without parameters. Note that 81 | * at in some SAPI implementations (such as Apache), any output during 82 | * the request shutdown (in which destructors are called) seems to be 83 | * discarded. If you need to get any debug information from your 84 | * destructor, use error_log(), syslog() or something similar. 85 | * 86 | * IMPORTANT! To use the emulated destructors you need to create the 87 | * objects by reference: $obj =& new PEAR_child; 88 | * 89 | * @category pear 90 | * @package PEAR 91 | * @author Stig Bakken 92 | * @author Tomas V.V. Cox 93 | * @author Greg Beaver 94 | * @copyright 1997-2005 The PHP Group 95 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 96 | * @version Release: 1.4.0a8 97 | * @link http://pear.php.net/package/PEAR 98 | * @see PEAR_Error 99 | * @since Class available since PHP 4.0.2 100 | * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear 101 | */ 102 | class PEAR 103 | { 104 | // {{{ properties 105 | 106 | /** 107 | * Whether to enable internal debug messages. 108 | * 109 | * @var bool 110 | * @access private 111 | */ 112 | var $_debug = false; 113 | 114 | /** 115 | * Default error mode for this object. 116 | * 117 | * @var int 118 | * @access private 119 | */ 120 | var $_default_error_mode = null; 121 | 122 | /** 123 | * Default error options used for this object when error mode 124 | * is PEAR_ERROR_TRIGGER. 125 | * 126 | * @var int 127 | * @access private 128 | */ 129 | var $_default_error_options = null; 130 | 131 | /** 132 | * Default error handler (callback) for this object, if error mode is 133 | * PEAR_ERROR_CALLBACK. 134 | * 135 | * @var string 136 | * @access private 137 | */ 138 | var $_default_error_handler = ''; 139 | 140 | /** 141 | * Which class to use for error objects. 142 | * 143 | * @var string 144 | * @access private 145 | */ 146 | var $_error_class = 'PEAR_Error'; 147 | 148 | /** 149 | * An array of expected errors. 150 | * 151 | * @var array 152 | * @access private 153 | */ 154 | var $_expected_errors = array(); 155 | 156 | // }}} 157 | 158 | // {{{ constructor 159 | 160 | /** 161 | * Constructor. Registers this object in 162 | * $_PEAR_destructor_object_list for destructor emulation if a 163 | * destructor object exists. 164 | * 165 | * @param string $error_class (optional) which class to use for 166 | * error objects, defaults to PEAR_Error. 167 | * @access public 168 | * @return void 169 | */ 170 | function PEAR($error_class = null) 171 | { 172 | $classname = strtolower(get_class($this)); 173 | if ($this->_debug) { 174 | print "PEAR constructor called, class=$classname\n"; 175 | } 176 | if ($error_class !== null) { 177 | $this->_error_class = $error_class; 178 | } 179 | while ($classname && strcasecmp($classname, "pear")) { 180 | $destructor = "_$classname"; 181 | if (method_exists($this, $destructor)) { 182 | global $_PEAR_destructor_object_list; 183 | $_PEAR_destructor_object_list[] = &$this; 184 | if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { 185 | register_shutdown_function("_PEAR_call_destructors"); 186 | $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; 187 | } 188 | break; 189 | } else { 190 | $classname = get_parent_class($classname); 191 | } 192 | } 193 | } 194 | 195 | // }}} 196 | // {{{ destructor 197 | 198 | /** 199 | * Destructor (the emulated type of...). Does nothing right now, 200 | * but is included for forward compatibility, so subclass 201 | * destructors should always call it. 202 | * 203 | * See the note in the class desciption about output from 204 | * destructors. 205 | * 206 | * @access public 207 | * @return void 208 | */ 209 | function _PEAR() { 210 | if ($this->_debug) { 211 | printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); 212 | } 213 | } 214 | 215 | // }}} 216 | // {{{ getStaticProperty() 217 | 218 | /** 219 | * If you have a class that's mostly/entirely static, and you need static 220 | * properties, you can use this method to simulate them. Eg. in your method(s) 221 | * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); 222 | * You MUST use a reference, or they will not persist! 223 | * 224 | * @access public 225 | * @param string $class The calling classname, to prevent clashes 226 | * @param string $var The variable to retrieve. 227 | * @return mixed A reference to the variable. If not set it will be 228 | * auto initialised to NULL. 229 | */ 230 | function &getStaticProperty($class, $var) 231 | { 232 | static $properties; 233 | return $properties[$class][$var]; 234 | } 235 | 236 | // }}} 237 | // {{{ registerShutdownFunc() 238 | 239 | /** 240 | * Use this function to register a shutdown method for static 241 | * classes. 242 | * 243 | * @access public 244 | * @param mixed $func The function name (or array of class/method) to call 245 | * @param mixed $args The arguments to pass to the function 246 | * @return void 247 | */ 248 | function registerShutdownFunc($func, $args = array()) 249 | { 250 | $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); 251 | } 252 | 253 | // }}} 254 | // {{{ isError() 255 | 256 | /** 257 | * Tell whether a value is a PEAR error. 258 | * 259 | * @param mixed $data the value to test 260 | * @param int $code if $data is an error object, return true 261 | * only if $code is a string and 262 | * $obj->getMessage() == $code or 263 | * $code is an integer and $obj->getCode() == $code 264 | * @access public 265 | * @return bool true if parameter is an error 266 | */ 267 | function isError($data, $code = null) 268 | { 269 | if (is_a($data, 'PEAR_Error')) { 270 | if (is_null($code)) { 271 | return true; 272 | } elseif (is_string($code)) { 273 | return $data->getMessage() == $code; 274 | } else { 275 | return $data->getCode() == $code; 276 | } 277 | } 278 | return false; 279 | } 280 | 281 | // }}} 282 | // {{{ setErrorHandling() 283 | 284 | /** 285 | * Sets how errors generated by this object should be handled. 286 | * Can be invoked both in objects and statically. If called 287 | * statically, setErrorHandling sets the default behaviour for all 288 | * PEAR objects. If called in an object, setErrorHandling sets 289 | * the default behaviour for that object. 290 | * 291 | * @param int $mode 292 | * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, 293 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, 294 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. 295 | * 296 | * @param mixed $options 297 | * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one 298 | * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). 299 | * 300 | * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected 301 | * to be the callback function or method. A callback 302 | * function is a string with the name of the function, a 303 | * callback method is an array of two elements: the element 304 | * at index 0 is the object, and the element at index 1 is 305 | * the name of the method to call in the object. 306 | * 307 | * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is 308 | * a printf format string used when printing the error 309 | * message. 310 | * 311 | * @access public 312 | * @return void 313 | * @see PEAR_ERROR_RETURN 314 | * @see PEAR_ERROR_PRINT 315 | * @see PEAR_ERROR_TRIGGER 316 | * @see PEAR_ERROR_DIE 317 | * @see PEAR_ERROR_CALLBACK 318 | * @see PEAR_ERROR_EXCEPTION 319 | * 320 | * @since PHP 4.0.5 321 | */ 322 | 323 | function setErrorHandling($mode = null, $options = null) 324 | { 325 | if (isset($this) && is_a($this, 'PEAR')) { 326 | $setmode = &$this->_default_error_mode; 327 | $setoptions = &$this->_default_error_options; 328 | } else { 329 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; 330 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; 331 | } 332 | 333 | switch ($mode) { 334 | case PEAR_ERROR_EXCEPTION: 335 | case PEAR_ERROR_RETURN: 336 | case PEAR_ERROR_PRINT: 337 | case PEAR_ERROR_TRIGGER: 338 | case PEAR_ERROR_DIE: 339 | case null: 340 | $setmode = $mode; 341 | $setoptions = $options; 342 | break; 343 | 344 | case PEAR_ERROR_CALLBACK: 345 | $setmode = $mode; 346 | // class/object method callback 347 | if (is_callable($options)) { 348 | $setoptions = $options; 349 | } else { 350 | trigger_error("invalid error callback", E_USER_WARNING); 351 | } 352 | break; 353 | 354 | default: 355 | trigger_error("invalid error mode", E_USER_WARNING); 356 | break; 357 | } 358 | } 359 | 360 | // }}} 361 | // {{{ expectError() 362 | 363 | /** 364 | * This method is used to tell which errors you expect to get. 365 | * Expected errors are always returned with error mode 366 | * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, 367 | * and this method pushes a new element onto it. The list of 368 | * expected errors are in effect until they are popped off the 369 | * stack with the popExpect() method. 370 | * 371 | * Note that this method can not be called statically 372 | * 373 | * @param mixed $code a single error code or an array of error codes to expect 374 | * 375 | * @return int the new depth of the "expected errors" stack 376 | * @access public 377 | */ 378 | function expectError($code = '*') 379 | { 380 | if (is_array($code)) { 381 | array_push($this->_expected_errors, $code); 382 | } else { 383 | array_push($this->_expected_errors, array($code)); 384 | } 385 | return sizeof($this->_expected_errors); 386 | } 387 | 388 | // }}} 389 | // {{{ popExpect() 390 | 391 | /** 392 | * This method pops one element off the expected error codes 393 | * stack. 394 | * 395 | * @return array the list of error codes that were popped 396 | */ 397 | function popExpect() 398 | { 399 | return array_pop($this->_expected_errors); 400 | } 401 | 402 | // }}} 403 | // {{{ _checkDelExpect() 404 | 405 | /** 406 | * This method checks unsets an error code if available 407 | * 408 | * @param mixed error code 409 | * @return bool true if the error code was unset, false otherwise 410 | * @access private 411 | * @since PHP 4.3.0 412 | */ 413 | function _checkDelExpect($error_code) 414 | { 415 | $deleted = false; 416 | 417 | foreach ($this->_expected_errors AS $key => $error_array) { 418 | if (in_array($error_code, $error_array)) { 419 | unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); 420 | $deleted = true; 421 | } 422 | 423 | // clean up empty arrays 424 | if (0 == count($this->_expected_errors[$key])) { 425 | unset($this->_expected_errors[$key]); 426 | } 427 | } 428 | return $deleted; 429 | } 430 | 431 | // }}} 432 | // {{{ delExpect() 433 | 434 | /** 435 | * This method deletes all occurences of the specified element from 436 | * the expected error codes stack. 437 | * 438 | * @param mixed $error_code error code that should be deleted 439 | * @return mixed list of error codes that were deleted or error 440 | * @access public 441 | * @since PHP 4.3.0 442 | */ 443 | function delExpect($error_code) 444 | { 445 | $deleted = false; 446 | 447 | if ((is_array($error_code) && (0 != count($error_code)))) { 448 | // $error_code is a non-empty array here; 449 | // we walk through it trying to unset all 450 | // values 451 | foreach($error_code as $key => $error) { 452 | if ($this->_checkDelExpect($error)) { 453 | $deleted = true; 454 | } else { 455 | $deleted = false; 456 | } 457 | } 458 | return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME 459 | } elseif (!empty($error_code)) { 460 | // $error_code comes alone, trying to unset it 461 | if ($this->_checkDelExpect($error_code)) { 462 | return true; 463 | } else { 464 | return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME 465 | } 466 | } else { 467 | // $error_code is empty 468 | return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME 469 | } 470 | } 471 | 472 | // }}} 473 | // {{{ raiseError() 474 | 475 | /** 476 | * This method is a wrapper that returns an instance of the 477 | * configured error class with this object's default error 478 | * handling applied. If the $mode and $options parameters are not 479 | * specified, the object's defaults are used. 480 | * 481 | * @param mixed $message a text error message or a PEAR error object 482 | * 483 | * @param int $code a numeric error code (it is up to your class 484 | * to define these if you want to use codes) 485 | * 486 | * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, 487 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, 488 | * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. 489 | * 490 | * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter 491 | * specifies the PHP-internal error level (one of 492 | * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). 493 | * If $mode is PEAR_ERROR_CALLBACK, this 494 | * parameter specifies the callback function or 495 | * method. In other error modes this parameter 496 | * is ignored. 497 | * 498 | * @param string $userinfo If you need to pass along for example debug 499 | * information, this parameter is meant for that. 500 | * 501 | * @param string $error_class The returned error object will be 502 | * instantiated from this class, if specified. 503 | * 504 | * @param bool $skipmsg If true, raiseError will only pass error codes, 505 | * the error message parameter will be dropped. 506 | * 507 | * @access public 508 | * @return object a PEAR error object 509 | * @see PEAR::setErrorHandling 510 | * @since PHP 4.0.5 511 | */ 512 | function raiseError($message = null, 513 | $code = null, 514 | $mode = null, 515 | $options = null, 516 | $userinfo = null, 517 | $error_class = null, 518 | $skipmsg = false) 519 | { 520 | // The error is yet a PEAR error object 521 | if (is_object($message)) { 522 | $code = $message->getCode(); 523 | $userinfo = $message->getUserInfo(); 524 | $error_class = $message->getType(); 525 | $message->error_message_prefix = ''; 526 | $message = $message->getMessage(); 527 | } 528 | 529 | if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { 530 | if ($exp[0] == "*" || 531 | (is_int(reset($exp)) && in_array($code, $exp)) || 532 | (is_string(reset($exp)) && in_array($message, $exp))) { 533 | $mode = PEAR_ERROR_RETURN; 534 | } 535 | } 536 | // No mode given, try global ones 537 | if ($mode === null) { 538 | // Class error handler 539 | if (isset($this) && isset($this->_default_error_mode)) { 540 | $mode = $this->_default_error_mode; 541 | $options = $this->_default_error_options; 542 | // Global error handler 543 | } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { 544 | $mode = $GLOBALS['_PEAR_default_error_mode']; 545 | $options = $GLOBALS['_PEAR_default_error_options']; 546 | } 547 | } 548 | 549 | if ($error_class !== null) { 550 | $ec = $error_class; 551 | } elseif (isset($this) && isset($this->_error_class)) { 552 | $ec = $this->_error_class; 553 | } else { 554 | $ec = 'PEAR_Error'; 555 | } 556 | if ($skipmsg) { 557 | return new $ec($code, $mode, $options, $userinfo); 558 | } else { 559 | return new $ec($message, $code, $mode, $options, $userinfo); 560 | } 561 | } 562 | 563 | // }}} 564 | // {{{ throwError() 565 | 566 | /** 567 | * Simpler form of raiseError with fewer options. In most cases 568 | * message, code and userinfo are enough. 569 | * 570 | * @param string $message 571 | * 572 | */ 573 | function throwError($message = null, 574 | $code = null, 575 | $userinfo = null) 576 | { 577 | if (isset($this) && is_a($this, 'PEAR')) { 578 | return $this->raiseError($message, $code, null, null, $userinfo); 579 | } else { 580 | return PEAR::raiseError($message, $code, null, null, $userinfo); 581 | } 582 | } 583 | 584 | // }}} 585 | function staticPushErrorHandling($mode, $options = null) 586 | { 587 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 588 | $def_mode = &$GLOBALS['_PEAR_default_error_mode']; 589 | $def_options = &$GLOBALS['_PEAR_default_error_options']; 590 | $stack[] = array($def_mode, $def_options); 591 | switch ($mode) { 592 | case PEAR_ERROR_EXCEPTION: 593 | case PEAR_ERROR_RETURN: 594 | case PEAR_ERROR_PRINT: 595 | case PEAR_ERROR_TRIGGER: 596 | case PEAR_ERROR_DIE: 597 | case null: 598 | $def_mode = $mode; 599 | $def_options = $options; 600 | break; 601 | 602 | case PEAR_ERROR_CALLBACK: 603 | $def_mode = $mode; 604 | // class/object method callback 605 | if (is_callable($options)) { 606 | $def_options = $options; 607 | } else { 608 | trigger_error("invalid error callback", E_USER_WARNING); 609 | } 610 | break; 611 | 612 | default: 613 | trigger_error("invalid error mode", E_USER_WARNING); 614 | break; 615 | } 616 | $stack[] = array($mode, $options); 617 | return true; 618 | } 619 | 620 | function staticPopErrorHandling() 621 | { 622 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 623 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; 624 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; 625 | array_pop($stack); 626 | list($mode, $options) = $stack[sizeof($stack) - 1]; 627 | array_pop($stack); 628 | switch ($mode) { 629 | case PEAR_ERROR_EXCEPTION: 630 | case PEAR_ERROR_RETURN: 631 | case PEAR_ERROR_PRINT: 632 | case PEAR_ERROR_TRIGGER: 633 | case PEAR_ERROR_DIE: 634 | case null: 635 | $setmode = $mode; 636 | $setoptions = $options; 637 | break; 638 | 639 | case PEAR_ERROR_CALLBACK: 640 | $setmode = $mode; 641 | // class/object method callback 642 | if (is_callable($options)) { 643 | $setoptions = $options; 644 | } else { 645 | trigger_error("invalid error callback", E_USER_WARNING); 646 | } 647 | break; 648 | 649 | default: 650 | trigger_error("invalid error mode", E_USER_WARNING); 651 | break; 652 | } 653 | return true; 654 | } 655 | 656 | // {{{ pushErrorHandling() 657 | 658 | /** 659 | * Push a new error handler on top of the error handler options stack. With this 660 | * you can easily override the actual error handler for some code and restore 661 | * it later with popErrorHandling. 662 | * 663 | * @param mixed $mode (same as setErrorHandling) 664 | * @param mixed $options (same as setErrorHandling) 665 | * 666 | * @return bool Always true 667 | * 668 | * @see PEAR::setErrorHandling 669 | */ 670 | function pushErrorHandling($mode, $options = null) 671 | { 672 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 673 | if (isset($this) && is_a($this, 'PEAR')) { 674 | $def_mode = &$this->_default_error_mode; 675 | $def_options = &$this->_default_error_options; 676 | } else { 677 | $def_mode = &$GLOBALS['_PEAR_default_error_mode']; 678 | $def_options = &$GLOBALS['_PEAR_default_error_options']; 679 | } 680 | $stack[] = array($def_mode, $def_options); 681 | 682 | if (isset($this) && is_a($this, 'PEAR')) { 683 | $this->setErrorHandling($mode, $options); 684 | } else { 685 | PEAR::setErrorHandling($mode, $options); 686 | } 687 | $stack[] = array($mode, $options); 688 | return true; 689 | } 690 | 691 | // }}} 692 | // {{{ popErrorHandling() 693 | 694 | /** 695 | * Pop the last error handler used 696 | * 697 | * @return bool Always true 698 | * 699 | * @see PEAR::pushErrorHandling 700 | */ 701 | function popErrorHandling() 702 | { 703 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 704 | array_pop($stack); 705 | list($mode, $options) = $stack[sizeof($stack) - 1]; 706 | array_pop($stack); 707 | if (isset($this) && is_a($this, 'PEAR')) { 708 | $this->setErrorHandling($mode, $options); 709 | } else { 710 | PEAR::setErrorHandling($mode, $options); 711 | } 712 | return true; 713 | } 714 | 715 | // }}} 716 | // {{{ loadExtension() 717 | 718 | /** 719 | * OS independant PHP extension load. Remember to take care 720 | * on the correct extension name for case sensitive OSes. 721 | * 722 | * @param string $ext The extension name 723 | * @return bool Success or not on the dl() call 724 | */ 725 | function loadExtension($ext) 726 | { 727 | if (!extension_loaded($ext)) { 728 | // if either returns true dl() will produce a FATAL error, stop that 729 | if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { 730 | return false; 731 | } 732 | if (OS_WINDOWS) { 733 | $suffix = '.dll'; 734 | } elseif (PHP_OS == 'HP-UX') { 735 | $suffix = '.sl'; 736 | } elseif (PHP_OS == 'AIX') { 737 | $suffix = '.a'; 738 | } elseif (PHP_OS == 'OSX') { 739 | $suffix = '.bundle'; 740 | } else { 741 | $suffix = '.so'; 742 | } 743 | return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); 744 | } 745 | return true; 746 | } 747 | 748 | // }}} 749 | } 750 | 751 | // {{{ _PEAR_call_destructors() 752 | 753 | function _PEAR_call_destructors() 754 | { 755 | global $_PEAR_destructor_object_list; 756 | if (is_array($_PEAR_destructor_object_list) && 757 | sizeof($_PEAR_destructor_object_list)) 758 | { 759 | reset($_PEAR_destructor_object_list); 760 | while (list($k, $objref) = each($_PEAR_destructor_object_list)) { 761 | $classname = get_class($objref); 762 | while ($classname) { 763 | $destructor = "_$classname"; 764 | if (method_exists($objref, $destructor)) { 765 | $objref->$destructor(); 766 | break; 767 | } else { 768 | $classname = get_parent_class($classname); 769 | } 770 | } 771 | } 772 | // Empty the object list to ensure that destructors are 773 | // not called more than once. 774 | $_PEAR_destructor_object_list = array(); 775 | } 776 | 777 | // Now call the shutdown functions 778 | if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { 779 | foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { 780 | call_user_func_array($value[0], $value[1]); 781 | } 782 | } 783 | } 784 | 785 | // }}} 786 | /** 787 | * Standard PEAR error class for PHP 4 788 | * 789 | * This class is supserseded by {@link PEAR_Exception} in PHP 5 790 | * 791 | * @category pear 792 | * @package PEAR 793 | * @author Stig Bakken 794 | * @author Tomas V.V. Cox 795 | * @author Gregory Beaver 796 | * @copyright 1997-2005 The PHP Group 797 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 798 | * @version Release: 1.4.0a8 799 | * @link http://pear.php.net/manual/en/core.pear.pear-error.php 800 | * @see PEAR::raiseError(), PEAR::throwError() 801 | * @since Class available since PHP 4.0.2 802 | */ 803 | class PEAR_Error 804 | { 805 | // {{{ properties 806 | 807 | var $error_message_prefix = ''; 808 | var $mode = PEAR_ERROR_RETURN; 809 | var $level = E_USER_NOTICE; 810 | var $code = -1; 811 | var $message = ''; 812 | var $userinfo = ''; 813 | var $backtrace = null; 814 | 815 | // }}} 816 | // {{{ constructor 817 | 818 | /** 819 | * PEAR_Error constructor 820 | * 821 | * @param string $message message 822 | * 823 | * @param int $code (optional) error code 824 | * 825 | * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, 826 | * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, 827 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION 828 | * 829 | * @param mixed $options (optional) error level, _OR_ in the case of 830 | * PEAR_ERROR_CALLBACK, the callback function or object/method 831 | * tuple. 832 | * 833 | * @param string $userinfo (optional) additional user/debug info 834 | * 835 | * @access public 836 | * 837 | */ 838 | function PEAR_Error($message = 'unknown error', $code = null, 839 | $mode = null, $options = null, $userinfo = null) 840 | { 841 | if ($mode === null) { 842 | $mode = PEAR_ERROR_RETURN; 843 | } 844 | $this->message = $message; 845 | $this->code = $code; 846 | $this->mode = $mode; 847 | $this->userinfo = $userinfo; 848 | if (function_exists("debug_backtrace") && !defined('PEAR_IGNORE_BACKTRACE')) { 849 | $this->backtrace = debug_backtrace(); 850 | } 851 | if ($mode & PEAR_ERROR_CALLBACK) { 852 | $this->level = E_USER_NOTICE; 853 | $this->callback = $options; 854 | } else { 855 | if ($options === null) { 856 | $options = E_USER_NOTICE; 857 | } 858 | $this->level = $options; 859 | $this->callback = null; 860 | } 861 | if ($this->mode & PEAR_ERROR_PRINT) { 862 | if (is_null($options) || is_int($options)) { 863 | $format = "%s"; 864 | } else { 865 | $format = $options; 866 | } 867 | printf($format, $this->getMessage()); 868 | } 869 | if ($this->mode & PEAR_ERROR_TRIGGER) { 870 | trigger_error($this->getMessage(), $this->level); 871 | } 872 | if ($this->mode & PEAR_ERROR_DIE) { 873 | $msg = $this->getMessage(); 874 | if (is_null($options) || is_int($options)) { 875 | $format = "%s"; 876 | if (substr($msg, -1) != "\n") { 877 | $msg .= "\n"; 878 | } 879 | } else { 880 | $format = $options; 881 | } 882 | die(sprintf($format, $msg)); 883 | } 884 | if ($this->mode & PEAR_ERROR_CALLBACK) { 885 | if (is_callable($this->callback)) { 886 | call_user_func($this->callback, $this); 887 | } 888 | } 889 | if ($this->mode & PEAR_ERROR_EXCEPTION) { 890 | trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING); 891 | eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);'); 892 | } 893 | } 894 | 895 | // }}} 896 | // {{{ getMode() 897 | 898 | /** 899 | * Get the error mode from an error object. 900 | * 901 | * @return int error mode 902 | * @access public 903 | */ 904 | function getMode() { 905 | return $this->mode; 906 | } 907 | 908 | // }}} 909 | // {{{ getCallback() 910 | 911 | /** 912 | * Get the callback function/method from an error object. 913 | * 914 | * @return mixed callback function or object/method array 915 | * @access public 916 | */ 917 | function getCallback() { 918 | return $this->callback; 919 | } 920 | 921 | // }}} 922 | // {{{ getMessage() 923 | 924 | 925 | /** 926 | * Get the error message from an error object. 927 | * 928 | * @return string full error message 929 | * @access public 930 | */ 931 | function getMessage() 932 | { 933 | return ($this->error_message_prefix . $this->message); 934 | } 935 | 936 | 937 | // }}} 938 | // {{{ getCode() 939 | 940 | /** 941 | * Get error code from an error object 942 | * 943 | * @return int error code 944 | * @access public 945 | */ 946 | function getCode() 947 | { 948 | return $this->code; 949 | } 950 | 951 | // }}} 952 | // {{{ getType() 953 | 954 | /** 955 | * Get the name of this error/exception. 956 | * 957 | * @return string error/exception name (type) 958 | * @access public 959 | */ 960 | function getType() 961 | { 962 | return get_class($this); 963 | } 964 | 965 | // }}} 966 | // {{{ getUserInfo() 967 | 968 | /** 969 | * Get additional user-supplied information. 970 | * 971 | * @return string user-supplied information 972 | * @access public 973 | */ 974 | function getUserInfo() 975 | { 976 | return $this->userinfo; 977 | } 978 | 979 | // }}} 980 | // {{{ getDebugInfo() 981 | 982 | /** 983 | * Get additional debug information supplied by the application. 984 | * 985 | * @return string debug information 986 | * @access public 987 | */ 988 | function getDebugInfo() 989 | { 990 | return $this->getUserInfo(); 991 | } 992 | 993 | // }}} 994 | // {{{ getBacktrace() 995 | 996 | /** 997 | * Get the call backtrace from where the error was generated. 998 | * Supported with PHP 4.3.0 or newer. 999 | * 1000 | * @param int $frame (optional) what frame to fetch 1001 | * @return array Backtrace, or NULL if not available. 1002 | * @access public 1003 | */ 1004 | function getBacktrace($frame = null) 1005 | { 1006 | if (defined('PEAR_IGNORE_BACKTRACE')) { 1007 | return null; 1008 | } 1009 | if ($frame === null) { 1010 | return $this->backtrace; 1011 | } 1012 | return $this->backtrace[$frame]; 1013 | } 1014 | 1015 | // }}} 1016 | // {{{ addUserInfo() 1017 | 1018 | function addUserInfo($info) 1019 | { 1020 | if (empty($this->userinfo)) { 1021 | $this->userinfo = $info; 1022 | } else { 1023 | $this->userinfo .= " ** $info"; 1024 | } 1025 | } 1026 | 1027 | // }}} 1028 | // {{{ toString() 1029 | 1030 | /** 1031 | * Make a string representation of this object. 1032 | * 1033 | * @return string a string with an object summary 1034 | * @access public 1035 | */ 1036 | function toString() { 1037 | $modes = array(); 1038 | $levels = array(E_USER_NOTICE => 'notice', 1039 | E_USER_WARNING => 'warning', 1040 | E_USER_ERROR => 'error'); 1041 | if ($this->mode & PEAR_ERROR_CALLBACK) { 1042 | if (is_array($this->callback)) { 1043 | $callback = (is_object($this->callback[0]) ? 1044 | strtolower(get_class($this->callback[0])) : 1045 | $this->callback[0]) . '::' . 1046 | $this->callback[1]; 1047 | } else { 1048 | $callback = $this->callback; 1049 | } 1050 | return sprintf('[%s: message="%s" code=%d mode=callback '. 1051 | 'callback=%s prefix="%s" info="%s"]', 1052 | strtolower(get_class($this)), $this->message, $this->code, 1053 | $callback, $this->error_message_prefix, 1054 | $this->userinfo); 1055 | } 1056 | if ($this->mode & PEAR_ERROR_PRINT) { 1057 | $modes[] = 'print'; 1058 | } 1059 | if ($this->mode & PEAR_ERROR_TRIGGER) { 1060 | $modes[] = 'trigger'; 1061 | } 1062 | if ($this->mode & PEAR_ERROR_DIE) { 1063 | $modes[] = 'die'; 1064 | } 1065 | if ($this->mode & PEAR_ERROR_RETURN) { 1066 | $modes[] = 'return'; 1067 | } 1068 | return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. 1069 | 'prefix="%s" info="%s"]', 1070 | strtolower(get_class($this)), $this->message, $this->code, 1071 | implode("|", $modes), $levels[$this->level], 1072 | $this->error_message_prefix, 1073 | $this->userinfo); 1074 | } 1075 | 1076 | // }}} 1077 | } 1078 | 1079 | /* 1080 | * Local Variables: 1081 | * mode: php 1082 | * tab-width: 4 1083 | * c-basic-offset: 4 1084 | * End: 1085 | */ 1086 | ?> 1087 | -------------------------------------------------------------------------------- /PEAR.php: -------------------------------------------------------------------------------- 1 | 18 | * @author Stig Bakken 19 | * @author Tomas V.V.Cox 20 | * @author Greg Beaver 21 | * @copyright 1997-2005 The PHP Group 22 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 23 | * @version CVS: $Id: PEAR.php,v 1.1 2005/03/24 05:21:48 colin Exp $ 24 | * @link http://pear.php.net/package/PEAR 25 | * @since File available since Release 0.1 26 | */ 27 | 28 | /**#@+ 29 | * ERROR constants 30 | */ 31 | define('PEAR_ERROR_RETURN', 1); 32 | define('PEAR_ERROR_PRINT', 2); 33 | define('PEAR_ERROR_TRIGGER', 4); 34 | define('PEAR_ERROR_DIE', 8); 35 | define('PEAR_ERROR_CALLBACK', 16); 36 | /** 37 | * WARNING: obsolete 38 | * @deprecated 39 | */ 40 | define('PEAR_ERROR_EXCEPTION', 32); 41 | /**#@-*/ 42 | define('PEAR_ZE2', (function_exists('version_compare') && 43 | version_compare(zend_version(), "2-dev", "ge"))); 44 | 45 | if (substr(PHP_OS, 0, 3) == 'WIN') { 46 | define('OS_WINDOWS', true); 47 | define('OS_UNIX', false); 48 | define('PEAR_OS', 'Windows'); 49 | } else { 50 | define('OS_WINDOWS', false); 51 | define('OS_UNIX', true); 52 | define('PEAR_OS', 'Unix'); // blatant assumption 53 | } 54 | 55 | // instant backwards compatibility 56 | if (!defined('PATH_SEPARATOR')) { 57 | if (OS_WINDOWS) { 58 | define('PATH_SEPARATOR', ';'); 59 | } else { 60 | define('PATH_SEPARATOR', ':'); 61 | } 62 | } 63 | 64 | $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; 65 | $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; 66 | $GLOBALS['_PEAR_destructor_object_list'] = array(); 67 | $GLOBALS['_PEAR_shutdown_funcs'] = array(); 68 | $GLOBALS['_PEAR_error_handler_stack'] = array(); 69 | 70 | @ini_set('track_errors', true); 71 | 72 | /** 73 | * Base class for other PEAR classes. Provides rudimentary 74 | * emulation of destructors. 75 | * 76 | * If you want a destructor in your class, inherit PEAR and make a 77 | * destructor method called _yourclassname (same name as the 78 | * constructor, but with a "_" prefix). Also, in your constructor you 79 | * have to call the PEAR constructor: $this->PEAR();. 80 | * The destructor method will be called without parameters. Note that 81 | * at in some SAPI implementations (such as Apache), any output during 82 | * the request shutdown (in which destructors are called) seems to be 83 | * discarded. If you need to get any debug information from your 84 | * destructor, use error_log(), syslog() or something similar. 85 | * 86 | * IMPORTANT! To use the emulated destructors you need to create the 87 | * objects by reference: $obj =& new PEAR_child; 88 | * 89 | * @category pear 90 | * @package PEAR 91 | * @author Stig Bakken 92 | * @author Tomas V.V. Cox 93 | * @author Greg Beaver 94 | * @copyright 1997-2005 The PHP Group 95 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 96 | * @version Release: 1.4.0a8 97 | * @link http://pear.php.net/package/PEAR 98 | * @see PEAR_Error 99 | * @since Class available since PHP 4.0.2 100 | * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear 101 | */ 102 | class PEAR 103 | { 104 | // {{{ properties 105 | 106 | /** 107 | * Whether to enable internal debug messages. 108 | * 109 | * @var bool 110 | * @access private 111 | */ 112 | var $_debug = false; 113 | 114 | /** 115 | * Default error mode for this object. 116 | * 117 | * @var int 118 | * @access private 119 | */ 120 | var $_default_error_mode = null; 121 | 122 | /** 123 | * Default error options used for this object when error mode 124 | * is PEAR_ERROR_TRIGGER. 125 | * 126 | * @var int 127 | * @access private 128 | */ 129 | var $_default_error_options = null; 130 | 131 | /** 132 | * Default error handler (callback) for this object, if error mode is 133 | * PEAR_ERROR_CALLBACK. 134 | * 135 | * @var string 136 | * @access private 137 | */ 138 | var $_default_error_handler = ''; 139 | 140 | /** 141 | * Which class to use for error objects. 142 | * 143 | * @var string 144 | * @access private 145 | */ 146 | var $_error_class = 'PEAR_Error'; 147 | 148 | /** 149 | * An array of expected errors. 150 | * 151 | * @var array 152 | * @access private 153 | */ 154 | var $_expected_errors = array(); 155 | 156 | // }}} 157 | 158 | // {{{ constructor 159 | 160 | /** 161 | * Constructor. Registers this object in 162 | * $_PEAR_destructor_object_list for destructor emulation if a 163 | * destructor object exists. 164 | * 165 | * @param string $error_class (optional) which class to use for 166 | * error objects, defaults to PEAR_Error. 167 | * @access public 168 | * @return void 169 | */ 170 | function PEAR($error_class = null) 171 | { 172 | $classname = strtolower(get_class($this)); 173 | if ($this->_debug) { 174 | print "PEAR constructor called, class=$classname\n"; 175 | } 176 | if ($error_class !== null) { 177 | $this->_error_class = $error_class; 178 | } 179 | while ($classname && strcasecmp($classname, "pear")) { 180 | $destructor = "_$classname"; 181 | if (method_exists($this, $destructor)) { 182 | global $_PEAR_destructor_object_list; 183 | $_PEAR_destructor_object_list[] = &$this; 184 | if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { 185 | register_shutdown_function("_PEAR_call_destructors"); 186 | $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; 187 | } 188 | break; 189 | } else { 190 | $classname = get_parent_class($classname); 191 | } 192 | } 193 | } 194 | 195 | // }}} 196 | // {{{ destructor 197 | 198 | /** 199 | * Destructor (the emulated type of...). Does nothing right now, 200 | * but is included for forward compatibility, so subclass 201 | * destructors should always call it. 202 | * 203 | * See the note in the class desciption about output from 204 | * destructors. 205 | * 206 | * @access public 207 | * @return void 208 | */ 209 | function _PEAR() { 210 | if ($this->_debug) { 211 | printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); 212 | } 213 | } 214 | 215 | // }}} 216 | // {{{ getStaticProperty() 217 | 218 | /** 219 | * If you have a class that's mostly/entirely static, and you need static 220 | * properties, you can use this method to simulate them. Eg. in your method(s) 221 | * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); 222 | * You MUST use a reference, or they will not persist! 223 | * 224 | * @access public 225 | * @param string $class The calling classname, to prevent clashes 226 | * @param string $var The variable to retrieve. 227 | * @return mixed A reference to the variable. If not set it will be 228 | * auto initialised to NULL. 229 | */ 230 | function &getStaticProperty($class, $var) 231 | { 232 | static $properties; 233 | return $properties[$class][$var]; 234 | } 235 | 236 | // }}} 237 | // {{{ registerShutdownFunc() 238 | 239 | /** 240 | * Use this function to register a shutdown method for static 241 | * classes. 242 | * 243 | * @access public 244 | * @param mixed $func The function name (or array of class/method) to call 245 | * @param mixed $args The arguments to pass to the function 246 | * @return void 247 | */ 248 | function registerShutdownFunc($func, $args = array()) 249 | { 250 | $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); 251 | } 252 | 253 | // }}} 254 | // {{{ isError() 255 | 256 | /** 257 | * Tell whether a value is a PEAR error. 258 | * 259 | * @param mixed $data the value to test 260 | * @param int $code if $data is an error object, return true 261 | * only if $code is a string and 262 | * $obj->getMessage() == $code or 263 | * $code is an integer and $obj->getCode() == $code 264 | * @access public 265 | * @return bool true if parameter is an error 266 | */ 267 | function isError($data, $code = null) 268 | { 269 | if (is_a($data, 'PEAR_Error')) { 270 | if (is_null($code)) { 271 | return true; 272 | } elseif (is_string($code)) { 273 | return $data->getMessage() == $code; 274 | } else { 275 | return $data->getCode() == $code; 276 | } 277 | } 278 | return false; 279 | } 280 | 281 | // }}} 282 | // {{{ setErrorHandling() 283 | 284 | /** 285 | * Sets how errors generated by this object should be handled. 286 | * Can be invoked both in objects and statically. If called 287 | * statically, setErrorHandling sets the default behaviour for all 288 | * PEAR objects. If called in an object, setErrorHandling sets 289 | * the default behaviour for that object. 290 | * 291 | * @param int $mode 292 | * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, 293 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, 294 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. 295 | * 296 | * @param mixed $options 297 | * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one 298 | * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). 299 | * 300 | * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected 301 | * to be the callback function or method. A callback 302 | * function is a string with the name of the function, a 303 | * callback method is an array of two elements: the element 304 | * at index 0 is the object, and the element at index 1 is 305 | * the name of the method to call in the object. 306 | * 307 | * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is 308 | * a printf format string used when printing the error 309 | * message. 310 | * 311 | * @access public 312 | * @return void 313 | * @see PEAR_ERROR_RETURN 314 | * @see PEAR_ERROR_PRINT 315 | * @see PEAR_ERROR_TRIGGER 316 | * @see PEAR_ERROR_DIE 317 | * @see PEAR_ERROR_CALLBACK 318 | * @see PEAR_ERROR_EXCEPTION 319 | * 320 | * @since PHP 4.0.5 321 | */ 322 | 323 | function setErrorHandling($mode = null, $options = null) 324 | { 325 | if (isset($this) && is_a($this, 'PEAR')) { 326 | $setmode = &$this->_default_error_mode; 327 | $setoptions = &$this->_default_error_options; 328 | } else { 329 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; 330 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; 331 | } 332 | 333 | switch ($mode) { 334 | case PEAR_ERROR_EXCEPTION: 335 | case PEAR_ERROR_RETURN: 336 | case PEAR_ERROR_PRINT: 337 | case PEAR_ERROR_TRIGGER: 338 | case PEAR_ERROR_DIE: 339 | case null: 340 | $setmode = $mode; 341 | $setoptions = $options; 342 | break; 343 | 344 | case PEAR_ERROR_CALLBACK: 345 | $setmode = $mode; 346 | // class/object method callback 347 | if (is_callable($options)) { 348 | $setoptions = $options; 349 | } else { 350 | trigger_error("invalid error callback", E_USER_WARNING); 351 | } 352 | break; 353 | 354 | default: 355 | trigger_error("invalid error mode", E_USER_WARNING); 356 | break; 357 | } 358 | } 359 | 360 | // }}} 361 | // {{{ expectError() 362 | 363 | /** 364 | * This method is used to tell which errors you expect to get. 365 | * Expected errors are always returned with error mode 366 | * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, 367 | * and this method pushes a new element onto it. The list of 368 | * expected errors are in effect until they are popped off the 369 | * stack with the popExpect() method. 370 | * 371 | * Note that this method can not be called statically 372 | * 373 | * @param mixed $code a single error code or an array of error codes to expect 374 | * 375 | * @return int the new depth of the "expected errors" stack 376 | * @access public 377 | */ 378 | function expectError($code = '*') 379 | { 380 | if (is_array($code)) { 381 | array_push($this->_expected_errors, $code); 382 | } else { 383 | array_push($this->_expected_errors, array($code)); 384 | } 385 | return sizeof($this->_expected_errors); 386 | } 387 | 388 | // }}} 389 | // {{{ popExpect() 390 | 391 | /** 392 | * This method pops one element off the expected error codes 393 | * stack. 394 | * 395 | * @return array the list of error codes that were popped 396 | */ 397 | function popExpect() 398 | { 399 | return array_pop($this->_expected_errors); 400 | } 401 | 402 | // }}} 403 | // {{{ _checkDelExpect() 404 | 405 | /** 406 | * This method checks unsets an error code if available 407 | * 408 | * @param mixed error code 409 | * @return bool true if the error code was unset, false otherwise 410 | * @access private 411 | * @since PHP 4.3.0 412 | */ 413 | function _checkDelExpect($error_code) 414 | { 415 | $deleted = false; 416 | 417 | foreach ($this->_expected_errors AS $key => $error_array) { 418 | if (in_array($error_code, $error_array)) { 419 | unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); 420 | $deleted = true; 421 | } 422 | 423 | // clean up empty arrays 424 | if (0 == count($this->_expected_errors[$key])) { 425 | unset($this->_expected_errors[$key]); 426 | } 427 | } 428 | return $deleted; 429 | } 430 | 431 | // }}} 432 | // {{{ delExpect() 433 | 434 | /** 435 | * This method deletes all occurences of the specified element from 436 | * the expected error codes stack. 437 | * 438 | * @param mixed $error_code error code that should be deleted 439 | * @return mixed list of error codes that were deleted or error 440 | * @access public 441 | * @since PHP 4.3.0 442 | */ 443 | function delExpect($error_code) 444 | { 445 | $deleted = false; 446 | 447 | if ((is_array($error_code) && (0 != count($error_code)))) { 448 | // $error_code is a non-empty array here; 449 | // we walk through it trying to unset all 450 | // values 451 | foreach($error_code as $key => $error) { 452 | if ($this->_checkDelExpect($error)) { 453 | $deleted = true; 454 | } else { 455 | $deleted = false; 456 | } 457 | } 458 | return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME 459 | } elseif (!empty($error_code)) { 460 | // $error_code comes alone, trying to unset it 461 | if ($this->_checkDelExpect($error_code)) { 462 | return true; 463 | } else { 464 | return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME 465 | } 466 | } else { 467 | // $error_code is empty 468 | return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME 469 | } 470 | } 471 | 472 | // }}} 473 | // {{{ raiseError() 474 | 475 | /** 476 | * This method is a wrapper that returns an instance of the 477 | * configured error class with this object's default error 478 | * handling applied. If the $mode and $options parameters are not 479 | * specified, the object's defaults are used. 480 | * 481 | * @param mixed $message a text error message or a PEAR error object 482 | * 483 | * @param int $code a numeric error code (it is up to your class 484 | * to define these if you want to use codes) 485 | * 486 | * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, 487 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, 488 | * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. 489 | * 490 | * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter 491 | * specifies the PHP-internal error level (one of 492 | * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). 493 | * If $mode is PEAR_ERROR_CALLBACK, this 494 | * parameter specifies the callback function or 495 | * method. In other error modes this parameter 496 | * is ignored. 497 | * 498 | * @param string $userinfo If you need to pass along for example debug 499 | * information, this parameter is meant for that. 500 | * 501 | * @param string $error_class The returned error object will be 502 | * instantiated from this class, if specified. 503 | * 504 | * @param bool $skipmsg If true, raiseError will only pass error codes, 505 | * the error message parameter will be dropped. 506 | * 507 | * @access public 508 | * @return object a PEAR error object 509 | * @see PEAR::setErrorHandling 510 | * @since PHP 4.0.5 511 | */ 512 | function raiseError($message = null, 513 | $code = null, 514 | $mode = null, 515 | $options = null, 516 | $userinfo = null, 517 | $error_class = null, 518 | $skipmsg = false) 519 | { 520 | // The error is yet a PEAR error object 521 | if (is_object($message)) { 522 | $code = $message->getCode(); 523 | $userinfo = $message->getUserInfo(); 524 | $error_class = $message->getType(); 525 | $message->error_message_prefix = ''; 526 | $message = $message->getMessage(); 527 | } 528 | 529 | if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { 530 | if ($exp[0] == "*" || 531 | (is_int(reset($exp)) && in_array($code, $exp)) || 532 | (is_string(reset($exp)) && in_array($message, $exp))) { 533 | $mode = PEAR_ERROR_RETURN; 534 | } 535 | } 536 | // No mode given, try global ones 537 | if ($mode === null) { 538 | // Class error handler 539 | if (isset($this) && isset($this->_default_error_mode)) { 540 | $mode = $this->_default_error_mode; 541 | $options = $this->_default_error_options; 542 | // Global error handler 543 | } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { 544 | $mode = $GLOBALS['_PEAR_default_error_mode']; 545 | $options = $GLOBALS['_PEAR_default_error_options']; 546 | } 547 | } 548 | 549 | if ($error_class !== null) { 550 | $ec = $error_class; 551 | } elseif (isset($this) && isset($this->_error_class)) { 552 | $ec = $this->_error_class; 553 | } else { 554 | $ec = 'PEAR_Error'; 555 | } 556 | if ($skipmsg) { 557 | return new $ec($code, $mode, $options, $userinfo); 558 | } else { 559 | return new $ec($message, $code, $mode, $options, $userinfo); 560 | } 561 | } 562 | 563 | // }}} 564 | // {{{ throwError() 565 | 566 | /** 567 | * Simpler form of raiseError with fewer options. In most cases 568 | * message, code and userinfo are enough. 569 | * 570 | * @param string $message 571 | * 572 | */ 573 | function throwError($message = null, 574 | $code = null, 575 | $userinfo = null) 576 | { 577 | if (isset($this) && is_a($this, 'PEAR')) { 578 | return $this->raiseError($message, $code, null, null, $userinfo); 579 | } else { 580 | return PEAR::raiseError($message, $code, null, null, $userinfo); 581 | } 582 | } 583 | 584 | // }}} 585 | function staticPushErrorHandling($mode, $options = null) 586 | { 587 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 588 | $def_mode = &$GLOBALS['_PEAR_default_error_mode']; 589 | $def_options = &$GLOBALS['_PEAR_default_error_options']; 590 | $stack[] = array($def_mode, $def_options); 591 | switch ($mode) { 592 | case PEAR_ERROR_EXCEPTION: 593 | case PEAR_ERROR_RETURN: 594 | case PEAR_ERROR_PRINT: 595 | case PEAR_ERROR_TRIGGER: 596 | case PEAR_ERROR_DIE: 597 | case null: 598 | $def_mode = $mode; 599 | $def_options = $options; 600 | break; 601 | 602 | case PEAR_ERROR_CALLBACK: 603 | $def_mode = $mode; 604 | // class/object method callback 605 | if (is_callable($options)) { 606 | $def_options = $options; 607 | } else { 608 | trigger_error("invalid error callback", E_USER_WARNING); 609 | } 610 | break; 611 | 612 | default: 613 | trigger_error("invalid error mode", E_USER_WARNING); 614 | break; 615 | } 616 | $stack[] = array($mode, $options); 617 | return true; 618 | } 619 | 620 | function staticPopErrorHandling() 621 | { 622 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 623 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; 624 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; 625 | array_pop($stack); 626 | list($mode, $options) = $stack[sizeof($stack) - 1]; 627 | array_pop($stack); 628 | switch ($mode) { 629 | case PEAR_ERROR_EXCEPTION: 630 | case PEAR_ERROR_RETURN: 631 | case PEAR_ERROR_PRINT: 632 | case PEAR_ERROR_TRIGGER: 633 | case PEAR_ERROR_DIE: 634 | case null: 635 | $setmode = $mode; 636 | $setoptions = $options; 637 | break; 638 | 639 | case PEAR_ERROR_CALLBACK: 640 | $setmode = $mode; 641 | // class/object method callback 642 | if (is_callable($options)) { 643 | $setoptions = $options; 644 | } else { 645 | trigger_error("invalid error callback", E_USER_WARNING); 646 | } 647 | break; 648 | 649 | default: 650 | trigger_error("invalid error mode", E_USER_WARNING); 651 | break; 652 | } 653 | return true; 654 | } 655 | 656 | // {{{ pushErrorHandling() 657 | 658 | /** 659 | * Push a new error handler on top of the error handler options stack. With this 660 | * you can easily override the actual error handler for some code and restore 661 | * it later with popErrorHandling. 662 | * 663 | * @param mixed $mode (same as setErrorHandling) 664 | * @param mixed $options (same as setErrorHandling) 665 | * 666 | * @return bool Always true 667 | * 668 | * @see PEAR::setErrorHandling 669 | */ 670 | function pushErrorHandling($mode, $options = null) 671 | { 672 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 673 | if (isset($this) && is_a($this, 'PEAR')) { 674 | $def_mode = &$this->_default_error_mode; 675 | $def_options = &$this->_default_error_options; 676 | } else { 677 | $def_mode = &$GLOBALS['_PEAR_default_error_mode']; 678 | $def_options = &$GLOBALS['_PEAR_default_error_options']; 679 | } 680 | $stack[] = array($def_mode, $def_options); 681 | 682 | if (isset($this) && is_a($this, 'PEAR')) { 683 | $this->setErrorHandling($mode, $options); 684 | } else { 685 | PEAR::setErrorHandling($mode, $options); 686 | } 687 | $stack[] = array($mode, $options); 688 | return true; 689 | } 690 | 691 | // }}} 692 | // {{{ popErrorHandling() 693 | 694 | /** 695 | * Pop the last error handler used 696 | * 697 | * @return bool Always true 698 | * 699 | * @see PEAR::pushErrorHandling 700 | */ 701 | function popErrorHandling() 702 | { 703 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 704 | array_pop($stack); 705 | list($mode, $options) = $stack[sizeof($stack) - 1]; 706 | array_pop($stack); 707 | if (isset($this) && is_a($this, 'PEAR')) { 708 | $this->setErrorHandling($mode, $options); 709 | } else { 710 | PEAR::setErrorHandling($mode, $options); 711 | } 712 | return true; 713 | } 714 | 715 | // }}} 716 | // {{{ loadExtension() 717 | 718 | /** 719 | * OS independant PHP extension load. Remember to take care 720 | * on the correct extension name for case sensitive OSes. 721 | * 722 | * @param string $ext The extension name 723 | * @return bool Success or not on the dl() call 724 | */ 725 | function loadExtension($ext) 726 | { 727 | if (!extension_loaded($ext)) { 728 | // if either returns true dl() will produce a FATAL error, stop that 729 | if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { 730 | return false; 731 | } 732 | if (OS_WINDOWS) { 733 | $suffix = '.dll'; 734 | } elseif (PHP_OS == 'HP-UX') { 735 | $suffix = '.sl'; 736 | } elseif (PHP_OS == 'AIX') { 737 | $suffix = '.a'; 738 | } elseif (PHP_OS == 'OSX') { 739 | $suffix = '.bundle'; 740 | } else { 741 | $suffix = '.so'; 742 | } 743 | return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); 744 | } 745 | return true; 746 | } 747 | 748 | // }}} 749 | } 750 | 751 | // {{{ _PEAR_call_destructors() 752 | 753 | function _PEAR_call_destructors() 754 | { 755 | global $_PEAR_destructor_object_list; 756 | if (is_array($_PEAR_destructor_object_list) && 757 | sizeof($_PEAR_destructor_object_list)) 758 | { 759 | reset($_PEAR_destructor_object_list); 760 | while (list($k, $objref) = each($_PEAR_destructor_object_list)) { 761 | $classname = get_class($objref); 762 | while ($classname) { 763 | $destructor = "_$classname"; 764 | if (method_exists($objref, $destructor)) { 765 | $objref->$destructor(); 766 | break; 767 | } else { 768 | $classname = get_parent_class($classname); 769 | } 770 | } 771 | } 772 | // Empty the object list to ensure that destructors are 773 | // not called more than once. 774 | $_PEAR_destructor_object_list = array(); 775 | } 776 | 777 | // Now call the shutdown functions 778 | if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { 779 | foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { 780 | call_user_func_array($value[0], $value[1]); 781 | } 782 | } 783 | } 784 | 785 | // }}} 786 | /** 787 | * Standard PEAR error class for PHP 4 788 | * 789 | * This class is supserseded by {@link PEAR_Exception} in PHP 5 790 | * 791 | * @category pear 792 | * @package PEAR 793 | * @author Stig Bakken 794 | * @author Tomas V.V. Cox 795 | * @author Gregory Beaver 796 | * @copyright 1997-2005 The PHP Group 797 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 798 | * @version Release: 1.4.0a8 799 | * @link http://pear.php.net/manual/en/core.pear.pear-error.php 800 | * @see PEAR::raiseError(), PEAR::throwError() 801 | * @since Class available since PHP 4.0.2 802 | */ 803 | class PEAR_Error 804 | { 805 | // {{{ properties 806 | 807 | var $error_message_prefix = ''; 808 | var $mode = PEAR_ERROR_RETURN; 809 | var $level = E_USER_NOTICE; 810 | var $code = -1; 811 | var $message = ''; 812 | var $userinfo = ''; 813 | var $backtrace = null; 814 | 815 | // }}} 816 | // {{{ constructor 817 | 818 | /** 819 | * PEAR_Error constructor 820 | * 821 | * @param string $message message 822 | * 823 | * @param int $code (optional) error code 824 | * 825 | * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, 826 | * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, 827 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION 828 | * 829 | * @param mixed $options (optional) error level, _OR_ in the case of 830 | * PEAR_ERROR_CALLBACK, the callback function or object/method 831 | * tuple. 832 | * 833 | * @param string $userinfo (optional) additional user/debug info 834 | * 835 | * @access public 836 | * 837 | */ 838 | function PEAR_Error($message = 'unknown error', $code = null, 839 | $mode = null, $options = null, $userinfo = null) 840 | { 841 | if ($mode === null) { 842 | $mode = PEAR_ERROR_RETURN; 843 | } 844 | $this->message = $message; 845 | $this->code = $code; 846 | $this->mode = $mode; 847 | $this->userinfo = $userinfo; 848 | if (function_exists("debug_backtrace") && !defined('PEAR_IGNORE_BACKTRACE')) { 849 | $this->backtrace = debug_backtrace(); 850 | } 851 | if ($mode & PEAR_ERROR_CALLBACK) { 852 | $this->level = E_USER_NOTICE; 853 | $this->callback = $options; 854 | } else { 855 | if ($options === null) { 856 | $options = E_USER_NOTICE; 857 | } 858 | $this->level = $options; 859 | $this->callback = null; 860 | } 861 | if ($this->mode & PEAR_ERROR_PRINT) { 862 | if (is_null($options) || is_int($options)) { 863 | $format = "%s"; 864 | } else { 865 | $format = $options; 866 | } 867 | printf($format, $this->getMessage()); 868 | } 869 | if ($this->mode & PEAR_ERROR_TRIGGER) { 870 | trigger_error($this->getMessage(), $this->level); 871 | } 872 | if ($this->mode & PEAR_ERROR_DIE) { 873 | $msg = $this->getMessage(); 874 | if (is_null($options) || is_int($options)) { 875 | $format = "%s"; 876 | if (substr($msg, -1) != "\n") { 877 | $msg .= "\n"; 878 | } 879 | } else { 880 | $format = $options; 881 | } 882 | die(sprintf($format, $msg)); 883 | } 884 | if ($this->mode & PEAR_ERROR_CALLBACK) { 885 | if (is_callable($this->callback)) { 886 | call_user_func($this->callback, $this); 887 | } 888 | } 889 | if ($this->mode & PEAR_ERROR_EXCEPTION) { 890 | trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING); 891 | eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);'); 892 | } 893 | } 894 | 895 | // }}} 896 | // {{{ getMode() 897 | 898 | /** 899 | * Get the error mode from an error object. 900 | * 901 | * @return int error mode 902 | * @access public 903 | */ 904 | function getMode() { 905 | return $this->mode; 906 | } 907 | 908 | // }}} 909 | // {{{ getCallback() 910 | 911 | /** 912 | * Get the callback function/method from an error object. 913 | * 914 | * @return mixed callback function or object/method array 915 | * @access public 916 | */ 917 | function getCallback() { 918 | return $this->callback; 919 | } 920 | 921 | // }}} 922 | // {{{ getMessage() 923 | 924 | 925 | /** 926 | * Get the error message from an error object. 927 | * 928 | * @return string full error message 929 | * @access public 930 | */ 931 | function getMessage() 932 | { 933 | return ($this->error_message_prefix . $this->message); 934 | } 935 | 936 | 937 | // }}} 938 | // {{{ getCode() 939 | 940 | /** 941 | * Get error code from an error object 942 | * 943 | * @return int error code 944 | * @access public 945 | */ 946 | function getCode() 947 | { 948 | return $this->code; 949 | } 950 | 951 | // }}} 952 | // {{{ getType() 953 | 954 | /** 955 | * Get the name of this error/exception. 956 | * 957 | * @return string error/exception name (type) 958 | * @access public 959 | */ 960 | function getType() 961 | { 962 | return get_class($this); 963 | } 964 | 965 | // }}} 966 | // {{{ getUserInfo() 967 | 968 | /** 969 | * Get additional user-supplied information. 970 | * 971 | * @return string user-supplied information 972 | * @access public 973 | */ 974 | function getUserInfo() 975 | { 976 | return $this->userinfo; 977 | } 978 | 979 | // }}} 980 | // {{{ getDebugInfo() 981 | 982 | /** 983 | * Get additional debug information supplied by the application. 984 | * 985 | * @return string debug information 986 | * @access public 987 | */ 988 | function getDebugInfo() 989 | { 990 | return $this->getUserInfo(); 991 | } 992 | 993 | // }}} 994 | // {{{ getBacktrace() 995 | 996 | /** 997 | * Get the call backtrace from where the error was generated. 998 | * Supported with PHP 4.3.0 or newer. 999 | * 1000 | * @param int $frame (optional) what frame to fetch 1001 | * @return array Backtrace, or NULL if not available. 1002 | * @access public 1003 | */ 1004 | function getBacktrace($frame = null) 1005 | { 1006 | if (defined('PEAR_IGNORE_BACKTRACE')) { 1007 | return null; 1008 | } 1009 | if ($frame === null) { 1010 | return $this->backtrace; 1011 | } 1012 | return $this->backtrace[$frame]; 1013 | } 1014 | 1015 | // }}} 1016 | // {{{ addUserInfo() 1017 | 1018 | function addUserInfo($info) 1019 | { 1020 | if (empty($this->userinfo)) { 1021 | $this->userinfo = $info; 1022 | } else { 1023 | $this->userinfo .= " ** $info"; 1024 | } 1025 | } 1026 | 1027 | // }}} 1028 | // {{{ toString() 1029 | 1030 | /** 1031 | * Make a string representation of this object. 1032 | * 1033 | * @return string a string with an object summary 1034 | * @access public 1035 | */ 1036 | function toString() { 1037 | $modes = array(); 1038 | $levels = array(E_USER_NOTICE => 'notice', 1039 | E_USER_WARNING => 'warning', 1040 | E_USER_ERROR => 'error'); 1041 | if ($this->mode & PEAR_ERROR_CALLBACK) { 1042 | if (is_array($this->callback)) { 1043 | $callback = (is_object($this->callback[0]) ? 1044 | strtolower(get_class($this->callback[0])) : 1045 | $this->callback[0]) . '::' . 1046 | $this->callback[1]; 1047 | } else { 1048 | $callback = $this->callback; 1049 | } 1050 | return sprintf('[%s: message="%s" code=%d mode=callback '. 1051 | 'callback=%s prefix="%s" info="%s"]', 1052 | strtolower(get_class($this)), $this->message, $this->code, 1053 | $callback, $this->error_message_prefix, 1054 | $this->userinfo); 1055 | } 1056 | if ($this->mode & PEAR_ERROR_PRINT) { 1057 | $modes[] = 'print'; 1058 | } 1059 | if ($this->mode & PEAR_ERROR_TRIGGER) { 1060 | $modes[] = 'trigger'; 1061 | } 1062 | if ($this->mode & PEAR_ERROR_DIE) { 1063 | $modes[] = 'die'; 1064 | } 1065 | if ($this->mode & PEAR_ERROR_RETURN) { 1066 | $modes[] = 'return'; 1067 | } 1068 | return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. 1069 | 'prefix="%s" info="%s"]', 1070 | strtolower(get_class($this)), $this->message, $this->code, 1071 | implode("|", $modes), $levels[$this->level], 1072 | $this->error_message_prefix, 1073 | $this->userinfo); 1074 | } 1075 | 1076 | // }}} 1077 | } 1078 | 1079 | /* 1080 | * Local Variables: 1081 | * mode: php 1082 | * tab-width: 4 1083 | * c-basic-offset: 4 1084 | * End: 1085 | */ 1086 | ?> 1087 | -------------------------------------------------------------------------------- /array_intersect_key.php: -------------------------------------------------------------------------------- 1 | | 16 | // +----------------------------------------------------------------------+ 17 | // 18 | // $Id: array_intersect_key.php,v 1.4 2005/01/26 04:55:13 aidan Exp $ 19 | 20 | 21 | /** 22 | * Replace array_intersect_key() 23 | * 24 | * @category PHP 25 | * @package PHP_Compat 26 | * @link http://php.net/function.array_intersect_key 27 | * @author Tom Buskens 28 | * @version $Revision: 1.4 $ 29 | * @since PHP 5.0.2 30 | * @require PHP 4.0.0 (user_error) 31 | */ 32 | if (!function_exists('array_intersect_key')) { 33 | function array_intersect_key() 34 | { 35 | $args = func_get_args(); 36 | if (count($args) < 2) { 37 | user_error('Wrong parameter count for array_intersect_key()', E_USER_WARNING); 38 | return; 39 | } 40 | 41 | // Check arrays 42 | $array_count = count($args); 43 | for ($i = 0; $i !== $array_count; $i++) { 44 | if (!is_array($args[$i])) { 45 | user_error('array_intersect_key() Argument #' . 46 | ($i + 1) . ' is not an array', E_USER_WARNING); 47 | return; 48 | } 49 | } 50 | 51 | // Compare entries 52 | $result = array(); 53 | foreach ($args[0] as $key1 => $value1) { 54 | for ($i = 1; $i !== $array_count; $i++) { 55 | foreach ($args[$i] as $key2 => $value2) { 56 | if ((string) $key1 === (string) $key2) { 57 | $result[$key1] = $value1; 58 | } 59 | } 60 | } 61 | } 62 | 63 | return $result; 64 | } 65 | } 66 | 67 | ?> -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfsense/xmlrpc-server/82b992e73ce4734491199a2f0064b1b022ac7fe9/license.txt -------------------------------------------------------------------------------- /pkg_tester.php: -------------------------------------------------------------------------------- 1 | 'all', 18 | "info" => array('version', 'name') 19 | ); 20 | $msg = new XML_RPC_Message('pfsense.get_pkgs', array(php_value_to_xmlrpc($params))); 21 | $cli = new XML_RPC_Client($versioncheck_path, $versioncheck_base_url); 22 | $resp = $cli->send($msg); 23 | $raw_versions = $resp->value(); 24 | return xmlrpc_value_to_php($raw_versions); 25 | } 26 | 27 | $versions = get_firmware_version(); 28 | print_r($versions); 29 | ?> 30 | 31 | 32 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /version: -------------------------------------------------------------------------------- 1 | 0.64.1-TheRoadToBetaBetaBeta -------------------------------------------------------------------------------- /xml_parser.inc: -------------------------------------------------------------------------------- 1 | | 17 | // | Tomas V.V.Cox | 18 | // | Stephan Schmidt | 19 | // +----------------------------------------------------------------------+ 20 | // 21 | // $Id: xml_parser.inc,v 1.2 2006/01/15 02:33:04 billm Exp $ 22 | 23 | /** 24 | * XML Parser class. 25 | * 26 | * This is an XML parser based on PHP's "xml" extension, 27 | * based on the bundled expat library. 28 | * 29 | * @category XML 30 | * @package XML_Parser 31 | * @author Stig Bakken 32 | * @author Tomas V.V.Cox 33 | * @author Stephan Schmidt 34 | */ 35 | 36 | /** 37 | * uses PEAR's error handling 38 | */ 39 | require_once 'PEAR.inc'; 40 | 41 | /** 42 | * resource could not be created 43 | */ 44 | define('XML_PARSER_ERROR_NO_RESOURCE', 200); 45 | 46 | /** 47 | * unsupported mode 48 | */ 49 | define('XML_PARSER_ERROR_UNSUPPORTED_MODE', 201); 50 | 51 | /** 52 | * invalid encoding was given 53 | */ 54 | define('XML_PARSER_ERROR_INVALID_ENCODING', 202); 55 | 56 | /** 57 | * specified file could not be read 58 | */ 59 | define('XML_PARSER_ERROR_FILE_NOT_READABLE', 203); 60 | 61 | /** 62 | * invalid input 63 | */ 64 | define('XML_PARSER_ERROR_INVALID_INPUT', 204); 65 | 66 | /** 67 | * remote file cannot be retrieved in safe mode 68 | */ 69 | define('XML_PARSER_ERROR_REMOTE', 205); 70 | 71 | /** 72 | * XML Parser class. 73 | * 74 | * This is an XML parser based on PHP's "xml" extension, 75 | * based on the bundled expat library. 76 | * 77 | * Notes: 78 | * - It requires PHP 4.0.4pl1 or greater 79 | * - From revision 1.17, the function names used by the 'func' mode 80 | * are in the format "xmltag_$elem", for example: use "xmltag_name" 81 | * to handle the tags of your xml file. 82 | * 83 | * @category XML 84 | * @package XML_Parser 85 | * @author Stig Bakken 86 | * @author Tomas V.V.Cox 87 | * @author Stephan Schmidt 88 | * @todo create XML_Parser_Namespace to parse documents with namespaces 89 | * @todo create XML_Parser_Pull 90 | * @todo Tests that need to be made: 91 | * - mixing character encodings 92 | * - a test using all expat handlers 93 | * - options (folding, output charset) 94 | * - different parsing modes 95 | */ 96 | class XML_Parser extends PEAR 97 | { 98 | // {{{ properties 99 | 100 | /** 101 | * XML parser handle 102 | * 103 | * @var resource 104 | * @see xml_parser_create() 105 | */ 106 | var $parser; 107 | 108 | /** 109 | * File handle if parsing from a file 110 | * 111 | * @var resource 112 | */ 113 | var $fp; 114 | 115 | /** 116 | * Whether to do case folding 117 | * 118 | * If set to true, all tag and attribute names will 119 | * be converted to UPPER CASE. 120 | * 121 | * @var boolean 122 | */ 123 | var $folding = true; 124 | 125 | /** 126 | * Mode of operation, one of "event" or "func" 127 | * 128 | * @var string 129 | */ 130 | var $mode; 131 | 132 | /** 133 | * Mapping from expat handler function to class method. 134 | * 135 | * @var array 136 | */ 137 | var $handler = array( 138 | 'character_data_handler' => 'cdataHandler', 139 | 'default_handler' => 'defaultHandler', 140 | 'processing_instruction_handler' => 'piHandler', 141 | 'unparsed_entity_decl_handler' => 'unparsedHandler', 142 | 'notation_decl_handler' => 'notationHandler', 143 | 'external_entity_ref_handler' => 'entityrefHandler' 144 | ); 145 | 146 | /** 147 | * source encoding 148 | * 149 | * @var string 150 | */ 151 | var $srcenc; 152 | 153 | /** 154 | * target encoding 155 | * 156 | * @var string 157 | */ 158 | var $tgtenc; 159 | 160 | /** 161 | * handler object 162 | * 163 | * @var object 164 | */ 165 | var $_handlerObj; 166 | 167 | // }}} 168 | // {{{ constructor 169 | 170 | /** 171 | * Creates an XML parser. 172 | * 173 | * This is needed for PHP4 compatibility, it will 174 | * call the constructor, when a new instance is created. 175 | * 176 | * @param string $srcenc source charset encoding, use NULL (default) to use 177 | * whatever the document specifies 178 | * @param string $mode how this parser object should work, "event" for 179 | * startelement/endelement-type events, "func" 180 | * to have it call functions named after elements 181 | * @param string $tgenc a valid target encoding 182 | */ 183 | function XML_Parser($srcenc = null, $mode = 'event', $tgtenc = null) 184 | { 185 | XML_Parser::__construct($srcenc, $mode, $tgtenc); 186 | } 187 | // }}} 188 | 189 | /** 190 | * PHP5 constructor 191 | * 192 | * @param string $srcenc source charset encoding, use NULL (default) to use 193 | * whatever the document specifies 194 | * @param string $mode how this parser object should work, "event" for 195 | * startelement/endelement-type events, "func" 196 | * to have it call functions named after elements 197 | * @param string $tgenc a valid target encoding 198 | */ 199 | function __construct($srcenc = null, $mode = 'event', $tgtenc = null) 200 | { 201 | $this->PEAR('XML_Parser_Error'); 202 | 203 | $this->mode = $mode; 204 | $this->srcenc = $srcenc; 205 | $this->tgtenc = $tgtenc; 206 | } 207 | // }}} 208 | 209 | /** 210 | * Sets the mode of the parser. 211 | * 212 | * Possible modes are: 213 | * - func 214 | * - event 215 | * 216 | * You can set the mode using the second parameter 217 | * in the constructor. 218 | * 219 | * This method is only needed, when switching to a new 220 | * mode at a later point. 221 | * 222 | * @access public 223 | * @param string mode, either 'func' or 'event' 224 | * @return boolean|object true on success, PEAR_Error otherwise 225 | */ 226 | function setMode($mode) 227 | { 228 | if ($mode != 'func' && $mode != 'event') { 229 | $this->raiseError('Unsupported mode given', XML_PARSER_ERROR_UNSUPPORTED_MODE); 230 | } 231 | 232 | $this->mode = $mode; 233 | return true; 234 | } 235 | 236 | /** 237 | * Sets the object, that will handle the XML events 238 | * 239 | * This allows you to create a handler object independent of the 240 | * parser object that you are using and easily switch the underlying 241 | * parser. 242 | * 243 | * If no object will be set, XML_Parser assumes that you 244 | * extend this class and handle the events in $this. 245 | * 246 | * @access public 247 | * @param object object to handle the events 248 | * @return boolean will always return true 249 | * @since v1.2.0beta3 250 | */ 251 | function setHandlerObj(&$obj) 252 | { 253 | $this->_handlerObj = &$obj; 254 | return true; 255 | } 256 | 257 | /** 258 | * Init the element handlers 259 | * 260 | * @access private 261 | */ 262 | function _initHandlers() 263 | { 264 | if (!is_resource($this->parser)) { 265 | return false; 266 | } 267 | 268 | if (!is_object($this->_handlerObj)) { 269 | $this->_handlerObj = &$this; 270 | } 271 | switch ($this->mode) { 272 | 273 | case 'func': 274 | xml_set_object($this->parser, $this->_handlerObj); 275 | xml_set_element_handler($this->parser, array(&$this, 'funcStartHandler'), array(&$this, 'funcEndHandler')); 276 | break; 277 | 278 | case 'event': 279 | xml_set_object($this->parser, $this->_handlerObj); 280 | xml_set_element_handler($this->parser, 'startHandler', 'endHandler'); 281 | break; 282 | default: 283 | return $this->raiseError('Unsupported mode given', XML_PARSER_ERROR_UNSUPPORTED_MODE); 284 | } 285 | 286 | 287 | /** 288 | * set additional handlers for character data, entities, etc. 289 | */ 290 | foreach ($this->handler as $xml_func => $method) { 291 | if (method_exists($this->_handlerObj, $method)) { 292 | $xml_func = 'xml_set_' . $xml_func; 293 | $xml_func($this->parser, $method); 294 | } 295 | } 296 | } 297 | 298 | // {{{ _create() 299 | 300 | /** 301 | * create the XML parser resource 302 | * 303 | * Has been moved from the constructor to avoid 304 | * problems with object references. 305 | * 306 | * Furthermore it allows us returning an error 307 | * if something fails. 308 | * 309 | * @access private 310 | * @return boolean|object true on success, PEAR_Error otherwise 311 | * 312 | * @see xml_parser_create 313 | */ 314 | function _create() 315 | { 316 | if ($this->srcenc === null) { 317 | $xp = @xml_parser_create(); 318 | } else { 319 | $xp = @xml_parser_create($this->srcenc); 320 | } 321 | if (is_resource($xp)) { 322 | if ($this->tgtenc !== null) { 323 | if (!@xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING, 324 | $this->tgtenc)) { 325 | return $this->raiseError('invalid target encoding', XML_PARSER_ERROR_INVALID_ENCODING); 326 | } 327 | } 328 | $this->parser = $xp; 329 | $result = $this->_initHandlers($this->mode); 330 | if ($this->isError($result)) { 331 | return $result; 332 | } 333 | xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, $this->folding); 334 | 335 | return true; 336 | } 337 | return $this->raiseError('Unable to create XML parser resource.', XML_PARSER_ERROR_NO_RESOURCE); 338 | } 339 | 340 | // }}} 341 | // {{{ reset() 342 | 343 | /** 344 | * Reset the parser. 345 | * 346 | * This allows you to use one parser instance 347 | * to parse multiple XML documents. 348 | * 349 | * @access public 350 | * @return boolean|object true on success, PEAR_Error otherwise 351 | */ 352 | function reset() 353 | { 354 | $result = $this->_create(); 355 | if ($this->isError( $result )) { 356 | return $result; 357 | } 358 | return true; 359 | } 360 | 361 | // }}} 362 | // {{{ setInputFile() 363 | 364 | /** 365 | * Sets the input xml file to be parsed 366 | * 367 | * @param string Filename (full path) 368 | * @return resource fopen handle of the given file 369 | * @throws XML_Parser_Error 370 | * @see setInput(), setInputString(), parse() 371 | * @access public 372 | */ 373 | function setInputFile($file) 374 | { 375 | /** 376 | * check, if file is a remote file 377 | */ 378 | if (eregi('^(http|ftp)://', substr($file, 0, 10))) { 379 | if (!ini_get('allow_url_fopen')) { 380 | return $this->raiseError('Remote files cannot be parsed, as safe mode is enabled.', XML_PARSER_ERROR_REMOTE); 381 | } 382 | } 383 | 384 | $fp = @fopen($file, 'rb'); 385 | if (is_resource($fp)) { 386 | $this->fp = $fp; 387 | return $fp; 388 | } 389 | return $this->raiseError('File could not be opened.', XML_PARSER_ERROR_FILE_NOT_READABLE); 390 | } 391 | 392 | // }}} 393 | // {{{ setInputString() 394 | 395 | /** 396 | * XML_Parser::setInputString() 397 | * 398 | * Sets the xml input from a string 399 | * 400 | * @param string $data a string containing the XML document 401 | * @return null 402 | **/ 403 | function setInputString($data) 404 | { 405 | $this->fp = $data; 406 | return null; 407 | } 408 | 409 | // }}} 410 | // {{{ setInput() 411 | 412 | /** 413 | * Sets the file handle to use with parse(). 414 | * 415 | * You should use setInputFile() or setInputString() if you 416 | * pass a string 417 | * 418 | * @param mixed $fp Can be either a resource returned from fopen(), 419 | * a URL, a local filename or a string. 420 | * @access public 421 | * @see parse() 422 | * @uses setInputString(), setInputFile() 423 | */ 424 | function setInput($fp) 425 | { 426 | if (is_resource($fp)) { 427 | $this->fp = $fp; 428 | return true; 429 | } 430 | // see if it's an absolute URL (has a scheme at the beginning) 431 | elseif (eregi('^[a-z]+://', substr($fp, 0, 10))) { 432 | return $this->setInputFile($fp); 433 | } 434 | // see if it's a local file 435 | elseif (file_exists($fp)) { 436 | return $this->setInputFile($fp); 437 | } 438 | // it must be a string 439 | else { 440 | $this->fp = $fp; 441 | return true; 442 | } 443 | /* XXX - unreachable code? */ 444 | /* return $this->raiseError('Illegal input format', XML_PARSER_ERROR_INVALID_INPUT); */ 445 | } 446 | 447 | // }}} 448 | // {{{ parse() 449 | 450 | /** 451 | * Central parsing function. 452 | * 453 | * @return true|object PEAR error returns true on success, or a PEAR_Error otherwise 454 | * @access public 455 | */ 456 | function parse() 457 | { 458 | /** 459 | * reset the parser 460 | */ 461 | $result = $this->reset(); 462 | if ($this->isError($result)) { 463 | return $result; 464 | } 465 | // if $this->fp was fopened previously 466 | if (is_resource($this->fp)) { 467 | 468 | while ($data = fread($this->fp, 4096)) { 469 | if (!$this->_parseString($data, feof($this->fp))) { 470 | $error = &$this->raiseError(); 471 | $this->free(); 472 | return $error; 473 | } 474 | } 475 | // otherwise, $this->fp must be a string 476 | } else { 477 | if (!$this->_parseString($this->fp, true)) { 478 | $error = &$this->raiseError(); 479 | $this->free(); 480 | return $error; 481 | } 482 | } 483 | $this->free(); 484 | 485 | return true; 486 | } 487 | 488 | /** 489 | * XML_Parser::_parseString() 490 | * 491 | * @param string $data 492 | * @param boolean $eof 493 | * @return bool 494 | * @access private 495 | * @see parseString() 496 | **/ 497 | function _parseString($data, $eof = false) 498 | { 499 | return xml_parse($this->parser, $data, $eof); 500 | } 501 | 502 | // }}} 503 | // {{{ parseString() 504 | 505 | /** 506 | * XML_Parser::parseString() 507 | * 508 | * Parses a string. 509 | * 510 | * @param string $data XML data 511 | * @param boolean $eof If set and TRUE, data is the last piece of data sent in this parser 512 | * @throws XML_Parser_Error 513 | * @return Pear Error|true true on success or a PEAR Error 514 | * @see _parseString() 515 | */ 516 | function parseString($data, $eof = false) 517 | { 518 | if (!isset($this->parser) || !is_resource($this->parser)) { 519 | $this->reset(); 520 | } 521 | 522 | if (!$this->_parseString($data, $eof)) { 523 | $error = &$this->raiseError(); 524 | $this->free(); 525 | return $error; 526 | } 527 | 528 | if ($eof === true) { 529 | $this->free(); 530 | } 531 | return true; 532 | } 533 | 534 | /** 535 | * XML_Parser::free() 536 | * 537 | * Free the internal resources associated with the parser 538 | * 539 | * @return null 540 | **/ 541 | function free() 542 | { 543 | if (isset($this->parser) && is_resource($this->parser)) { 544 | xml_parser_free($this->parser); 545 | unset( $this->parser ); 546 | } 547 | if (isset($this->fp) && is_resource($this->fp)) { 548 | fclose($this->fp); 549 | } 550 | unset($this->fp); 551 | return null; 552 | } 553 | 554 | /** 555 | * XML_Parser::raiseError() 556 | * 557 | * Throws a XML_Parser_Error 558 | * 559 | * @param string $msg the error message 560 | * @param integer $ecode the error message code 561 | * @return XML_Parser_Error 562 | **/ 563 | function raiseError($msg = null, $ecode = 0) 564 | { 565 | $msg = !is_null($msg) ? $msg : $this->parser; 566 | $err = &new XML_Parser_Error($msg, $ecode); 567 | return parent::raiseError($err); 568 | } 569 | 570 | // }}} 571 | // {{{ funcStartHandler() 572 | 573 | function funcStartHandler($xp, $elem, $attribs) 574 | { 575 | $func = 'xmltag_' . $elem; 576 | if (strchr($func, '.')) { 577 | $func = str_replace('.', '_', $func); 578 | } 579 | if (method_exists($this->_handlerObj, $func)) { 580 | call_user_func(array(&$this->_handlerObj, $func), $xp, $elem, $attribs); 581 | } elseif (method_exists($this->_handlerObj, 'xmltag')) { 582 | call_user_func(array(&$this->_handlerObj, 'xmltag'), $xp, $elem, $attribs); 583 | } 584 | } 585 | 586 | // }}} 587 | // {{{ funcEndHandler() 588 | 589 | function funcEndHandler($xp, $elem) 590 | { 591 | $func = 'xmltag_' . $elem . '_'; 592 | if (strchr($func, '.')) { 593 | $func = str_replace('.', '_', $func); 594 | } 595 | if (method_exists($this->_handlerObj, $func)) { 596 | call_user_func(array(&$this->_handlerObj, $func), $xp, $elem); 597 | } elseif (method_exists($this->_handlerObj, 'xmltag_')) { 598 | call_user_func(array(&$this->_handlerObj, 'xmltag_'), $xp, $elem); 599 | } 600 | } 601 | 602 | // }}} 603 | // {{{ startHandler() 604 | 605 | /** 606 | * 607 | * @abstract 608 | */ 609 | function startHandler($xp, $elem, &$attribs) 610 | { 611 | return NULL; 612 | } 613 | 614 | // }}} 615 | // {{{ endHandler() 616 | 617 | /** 618 | * 619 | * @abstract 620 | */ 621 | function endHandler($xp, $elem) 622 | { 623 | return NULL; 624 | } 625 | 626 | 627 | // }}}me 628 | } 629 | 630 | /** 631 | * error class, replaces PEAR_Error 632 | * 633 | * An instance of this class will be returned 634 | * if an error occurs inside XML_Parser. 635 | * 636 | * There are three advantages over using the standard PEAR_Error: 637 | * - All messages will be prefixed 638 | * - check for XML_Parser error, using is_a( $error, 'XML_Parser_Error' ) 639 | * - messages can be generated from the xml_parser resource 640 | * 641 | * @package XML_Parser 642 | * @access public 643 | * @see PEAR_Error 644 | */ 645 | class XML_Parser_Error extends PEAR_Error 646 | { 647 | // {{{ properties 648 | 649 | /** 650 | * prefix for all messages 651 | * 652 | * @var string 653 | */ 654 | var $error_message_prefix = 'XML_Parser: '; 655 | 656 | // }}} 657 | // {{{ constructor() 658 | /** 659 | * construct a new error instance 660 | * 661 | * You may either pass a message or an xml_parser resource as first 662 | * parameter. If a resource has been passed, the last error that 663 | * happened will be retrieved and returned. 664 | * 665 | * @access public 666 | * @param string|resource message or parser resource 667 | * @param integer error code 668 | * @param integer error handling 669 | * @param integer error level 670 | */ 671 | function XML_Parser_Error($msgorparser = 'unknown error', $code = 0, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE) 672 | { 673 | if (is_resource($msgorparser)) { 674 | $code = xml_get_error_code($msgorparser); 675 | $msgorparser = sprintf('%s at XML input line %d:%d', 676 | xml_error_string($code), 677 | xml_get_current_line_number($msgorparser), 678 | xml_get_current_column_number($msgorparser)); 679 | } 680 | $this->PEAR_Error($msgorparser, $code, $mode, $level); 681 | } 682 | // }}} 683 | } 684 | ?> 685 | -------------------------------------------------------------------------------- /xml_unserializer.inc: -------------------------------------------------------------------------------- 1 | 20 | * @copyright 1997-2005 The PHP Group 21 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 22 | * @version CVS: $Id: xml_unserializer.inc,v 1.1 2005/10/15 20:23:29 colin Exp $ 23 | * @link http://pear.php.net/package/XML_Serializer 24 | * @see XML_Unserializer 25 | */ 26 | 27 | /** 28 | * uses PEAR error managemt 29 | */ 30 | require_once 'PEAR.inc'; 31 | 32 | /** 33 | * uses XML_Parser to unserialize document 34 | */ 35 | require_once 'xml_parser.inc'; 36 | 37 | /** 38 | * option: Convert nested tags to array or object 39 | * 40 | * Possible values: 41 | * - array 42 | * - object 43 | * - associative array to define this option per tag name 44 | */ 45 | define('XML_UNSERIALIZER_OPTION_COMPLEXTYPE', 'complexType'); 46 | 47 | /** 48 | * option: Name of the attribute that stores the original key 49 | * 50 | * Possible values: 51 | * - any string 52 | */ 53 | define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute'); 54 | 55 | /** 56 | * option: Name of the attribute that stores the type 57 | * 58 | * Possible values: 59 | * - any string 60 | */ 61 | define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute'); 62 | 63 | /** 64 | * option: Name of the attribute that stores the class name 65 | * 66 | * Possible values: 67 | * - any string 68 | */ 69 | define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute'); 70 | 71 | /** 72 | * option: Whether to use the tag name as a class name 73 | * 74 | * Possible values: 75 | * - true or false 76 | */ 77 | define('XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME', 'tagAsClass'); 78 | 79 | /** 80 | * option: Name of the default class 81 | * 82 | * Possible values: 83 | * - any string 84 | */ 85 | define('XML_UNSERIALIZER_OPTION_DEFAULT_CLASS', 'defaultClass'); 86 | 87 | /** 88 | * option: Whether to parse attributes 89 | * 90 | * Possible values: 91 | * - true or false 92 | */ 93 | define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE', 'parseAttributes'); 94 | 95 | /** 96 | * option: Key of the array to store attributes (if any) 97 | * 98 | * Possible values: 99 | * - any string 100 | * - false (disabled) 101 | */ 102 | define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY', 'attributesArray'); 103 | 104 | /** 105 | * option: string to prepend attribute name (if any) 106 | * 107 | * Possible values: 108 | * - any string 109 | * - false (disabled) 110 | */ 111 | define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND', 'prependAttributes'); 112 | 113 | /** 114 | * option: key to store the content, if XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE is used 115 | * 116 | * Possible values: 117 | * - any string 118 | */ 119 | define('XML_UNSERIALIZER_OPTION_CONTENT_KEY', 'contentName'); 120 | 121 | /** 122 | * option: map tag names 123 | * 124 | * Possible values: 125 | * - associative array 126 | */ 127 | define('XML_UNSERIALIZER_OPTION_TAG_MAP', 'tagMap'); 128 | 129 | /** 130 | * option: list of tags that will always be enumerated 131 | * 132 | * Possible values: 133 | * - indexed array 134 | */ 135 | define('XML_UNSERIALIZER_OPTION_FORCE_ENUM', 'forceEnum'); 136 | 137 | /** 138 | * option: Encoding of the XML document 139 | * 140 | * Possible values: 141 | * - UTF-8 142 | * - ISO-8859-1 143 | */ 144 | define('XML_UNSERIALIZER_OPTION_ENCODING_SOURCE', 'encoding'); 145 | 146 | /** 147 | * option: Desired target encoding of the data 148 | * 149 | * Possible values: 150 | * - UTF-8 151 | * - ISO-8859-1 152 | */ 153 | define('XML_UNSERIALIZER_OPTION_ENCODING_TARGET', 'targetEncoding'); 154 | 155 | /** 156 | * option: Callback that will be applied to textual data 157 | * 158 | * Possible values: 159 | * - any valid PHP callback 160 | */ 161 | define('XML_UNSERIALIZER_OPTION_DECODE_FUNC', 'decodeFunction'); 162 | 163 | /** 164 | * option: whether to return the result of the unserialization from unserialize() 165 | * 166 | * Possible values: 167 | * - true 168 | * - false (default) 169 | */ 170 | define('XML_UNSERIALIZER_OPTION_RETURN_RESULT', 'returnResult'); 171 | 172 | /** 173 | * option: set the whitespace behaviour 174 | * 175 | * Possible values: 176 | * - XML_UNSERIALIZER_WHITESPACE_KEEP 177 | * - XML_UNSERIALIZER_WHITESPACE_TRIM 178 | * - XML_UNSERIALIZER_WHITESPACE_NORMALIZE 179 | */ 180 | define('XML_UNSERIALIZER_OPTION_WHITESPACE', 'whitespace'); 181 | 182 | /** 183 | * Keep all whitespace 184 | */ 185 | define('XML_UNSERIALIZER_WHITESPACE_KEEP', 'keep'); 186 | 187 | /** 188 | * remove whitespace from start and end of the data 189 | */ 190 | define('XML_UNSERIALIZER_WHITESPACE_TRIM', 'trim'); 191 | 192 | /** 193 | * normalize whitespace 194 | */ 195 | define('XML_UNSERIALIZER_WHITESPACE_NORMALIZE', 'normalize'); 196 | 197 | /** 198 | * option: whether to ovverride all options that have been set before 199 | * 200 | * Possible values: 201 | * - true 202 | * - false (default) 203 | */ 204 | define('XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS', 'overrideOptions'); 205 | 206 | /** 207 | * option: list of tags, that will not be used as keys 208 | */ 209 | define('XML_UNSERIALIZER_OPTION_IGNORE_KEYS', 'ignoreKeys'); 210 | 211 | /** 212 | * option: whether to use type guessing for scalar values 213 | */ 214 | define('XML_UNSERIALIZER_OPTION_GUESS_TYPES', 'guessTypes'); 215 | 216 | /** 217 | * error code for no serialization done 218 | */ 219 | define('XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION', 151); 220 | 221 | /** 222 | * XML_Unserializer 223 | * 224 | * class to unserialize XML documents that have been created with 225 | * XML_Serializer. To unserialize an XML document you have to add 226 | * type hints to the XML_Serializer options. 227 | * 228 | * If no type hints are available, XML_Unserializer will guess how 229 | * the tags should be treated, that means complex structures will be 230 | * arrays and tags with only CData in them will be strings. 231 | * 232 | * 233 | * require_once 'XML/Unserializer.php'; 234 | * 235 | * // be careful to always use the ampersand in front of the new operator 236 | * $unserializer = &new XML_Unserializer(); 237 | * 238 | * $unserializer->unserialize($xml); 239 | * 240 | * $data = $unserializer->getUnserializedData(); 241 | * 242 | * 243 | * 244 | * @category XML 245 | * @package XML_Serializer 246 | * @author Stephan Schmidt 247 | * @copyright 1997-2005 The PHP Group 248 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 249 | * @version Release: @package_version@ 250 | * @link http://pear.php.net/package/XML_Serializer 251 | * @see XML_Serializer 252 | */ 253 | class XML_Unserializer extends PEAR 254 | { 255 | /** 256 | * list of all available options 257 | * 258 | * @access private 259 | * @var array 260 | */ 261 | var $_knownOptions = array( 262 | XML_UNSERIALIZER_OPTION_COMPLEXTYPE, 263 | XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY, 264 | XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE, 265 | XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS, 266 | XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME, 267 | XML_UNSERIALIZER_OPTION_DEFAULT_CLASS, 268 | XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE, 269 | XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY, 270 | XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND, 271 | XML_UNSERIALIZER_OPTION_CONTENT_KEY, 272 | XML_UNSERIALIZER_OPTION_TAG_MAP, 273 | XML_UNSERIALIZER_OPTION_FORCE_ENUM, 274 | XML_UNSERIALIZER_OPTION_ENCODING_SOURCE, 275 | XML_UNSERIALIZER_OPTION_ENCODING_TARGET, 276 | XML_UNSERIALIZER_OPTION_DECODE_FUNC, 277 | XML_UNSERIALIZER_OPTION_RETURN_RESULT, 278 | XML_UNSERIALIZER_OPTION_WHITESPACE, 279 | XML_UNSERIALIZER_OPTION_IGNORE_KEYS, 280 | XML_UNSERIALIZER_OPTION_GUESS_TYPES 281 | ); 282 | /** 283 | * default options for the serialization 284 | * 285 | * @access private 286 | * @var array 287 | */ 288 | var $_defaultOptions = array( 289 | XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array', // complex types will be converted to arrays, if no type hint is given 290 | XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey', // get array key/property name from this attribute 291 | XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type', // get type from this attribute 292 | XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class', // get class from this attribute (if not given, use tag name) 293 | XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME => true, // use the tagname as the classname 294 | XML_UNSERIALIZER_OPTION_DEFAULT_CLASS => 'stdClass', // name of the class that is used to create objects 295 | XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => false, // parse the attributes of the tag into an array 296 | XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY => false, // parse them into sperate array (specify name of array here) 297 | XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND => '', // prepend attribute names with this string 298 | XML_UNSERIALIZER_OPTION_CONTENT_KEY => '_content', // put cdata found in a tag that has been converted to a complex type in this key 299 | XML_UNSERIALIZER_OPTION_TAG_MAP => array(), // use this to map tagnames 300 | XML_UNSERIALIZER_OPTION_FORCE_ENUM => array(), // these tags will always be an indexed array 301 | XML_UNSERIALIZER_OPTION_ENCODING_SOURCE => null, // specify the encoding character of the document to parse 302 | XML_UNSERIALIZER_OPTION_ENCODING_TARGET => null, // specify the target encoding 303 | XML_UNSERIALIZER_OPTION_DECODE_FUNC => null, // function used to decode data 304 | XML_UNSERIALIZER_OPTION_RETURN_RESULT => false, // unserialize() returns the result of the unserialization instead of true 305 | XML_UNSERIALIZER_OPTION_WHITESPACE => XML_UNSERIALIZER_WHITESPACE_TRIM, // remove whitespace around data 306 | XML_UNSERIALIZER_OPTION_IGNORE_KEYS => array(), // List of tags that will automatically be added to the parent, instead of adding a new key 307 | XML_UNSERIALIZER_OPTION_GUESS_TYPES => false // Whether to use type guessing 308 | ); 309 | 310 | /** 311 | * current options for the serialization 312 | * 313 | * @access public 314 | * @var array 315 | */ 316 | var $options = array(); 317 | 318 | /** 319 | * unserialized data 320 | * 321 | * @access private 322 | * @var string 323 | */ 324 | var $_unserializedData = null; 325 | 326 | /** 327 | * name of the root tag 328 | * 329 | * @access private 330 | * @var string 331 | */ 332 | var $_root = null; 333 | 334 | /** 335 | * stack for all data that is found 336 | * 337 | * @access private 338 | * @var array 339 | */ 340 | var $_dataStack = array(); 341 | 342 | /** 343 | * stack for all values that are generated 344 | * 345 | * @access private 346 | * @var array 347 | */ 348 | var $_valStack = array(); 349 | 350 | /** 351 | * current tag depth 352 | * 353 | * @access private 354 | * @var int 355 | */ 356 | var $_depth = 0; 357 | 358 | /** 359 | * XML_Parser instance 360 | * 361 | * @access private 362 | * @var object XML_Parser 363 | */ 364 | var $_parser = null; 365 | 366 | /** 367 | * constructor 368 | * 369 | * @access public 370 | * @param mixed $options array containing options for the unserialization 371 | */ 372 | function XML_Unserializer($options = null) 373 | { 374 | if (is_array($options)) { 375 | $this->options = array_merge($this->_defaultOptions, $options); 376 | } else { 377 | $this->options = $this->_defaultOptions; 378 | } 379 | } 380 | 381 | /** 382 | * return API version 383 | * 384 | * @access public 385 | * @static 386 | * @return string $version API version 387 | */ 388 | function apiVersion() 389 | { 390 | return '@package_version@'; 391 | } 392 | 393 | /** 394 | * reset all options to default options 395 | * 396 | * @access public 397 | * @see setOption(), XML_Unserializer(), setOptions() 398 | */ 399 | function resetOptions() 400 | { 401 | $this->options = $this->_defaultOptions; 402 | } 403 | 404 | /** 405 | * set an option 406 | * 407 | * You can use this method if you do not want to set all options in the constructor 408 | * 409 | * @access public 410 | * @see resetOption(), XML_Unserializer(), setOptions() 411 | */ 412 | function setOption($name, $value) 413 | { 414 | $this->options[$name] = $value; 415 | } 416 | 417 | /** 418 | * sets several options at once 419 | * 420 | * You can use this method if you do not want to set all options in the constructor 421 | * 422 | * @access public 423 | * @see resetOption(), XML_Unserializer(), setOption() 424 | */ 425 | function setOptions($options) 426 | { 427 | $this->options = array_merge($this->options, $options); 428 | } 429 | 430 | /** 431 | * unserialize data 432 | * 433 | * @access public 434 | * @param mixed $data data to unserialize (string, filename or resource) 435 | * @param boolean $isFile data should be treated as a file 436 | * @param array $options options that will override the global options for this call 437 | * @return boolean $success 438 | */ 439 | function unserialize($data, $isFile = false, $options = null) 440 | { 441 | $this->_unserializedData = null; 442 | $this->_root = null; 443 | 444 | // if options have been specified, use them instead 445 | // of the previously defined ones 446 | if (is_array($options)) { 447 | $optionsBak = $this->options; 448 | if (isset($options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS]) && $options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS] == true) { 449 | $this->options = array_merge($this->_defaultOptions, $options); 450 | } else { 451 | $this->options = array_merge($this->options, $options); 452 | } 453 | } else { 454 | $optionsBak = null; 455 | } 456 | 457 | $this->_valStack = array(); 458 | $this->_dataStack = array(); 459 | $this->_depth = 0; 460 | 461 | $this->_createParser(); 462 | 463 | if (is_string($data)) { 464 | if ($isFile) { 465 | $result = $this->_parser->setInputFile($data); 466 | if (PEAR::isError($result)) { 467 | return $result; 468 | } 469 | $result = $this->_parser->parse(); 470 | } else { 471 | $result = $this->_parser->parseString($data,true); 472 | } 473 | } else { 474 | $this->_parser->setInput($data); 475 | $result = $this->_parser->parse(); 476 | } 477 | 478 | if ($this->options[XML_UNSERIALIZER_OPTION_RETURN_RESULT] === true) { 479 | $return = $this->_unserializedData; 480 | } else { 481 | $return = true; 482 | } 483 | 484 | if ($optionsBak !== null) { 485 | $this->options = $optionsBak; 486 | } 487 | 488 | if (PEAR::isError($result)) { 489 | return $result; 490 | } 491 | 492 | return $return; 493 | } 494 | 495 | /** 496 | * get the result of the serialization 497 | * 498 | * @access public 499 | * @return string $serializedData 500 | */ 501 | function getUnserializedData() 502 | { 503 | if ($this->_root === null) { 504 | return $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.', XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION); 505 | } 506 | return $this->_unserializedData; 507 | } 508 | 509 | /** 510 | * get the name of the root tag 511 | * 512 | * @access public 513 | * @return string $rootName 514 | */ 515 | function getRootName() 516 | { 517 | if ($this->_root === null) { 518 | return $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.', XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION); 519 | } 520 | return $this->_root; 521 | } 522 | 523 | /** 524 | * Start element handler for XML parser 525 | * 526 | * @access private 527 | * @param object $parser XML parser object 528 | * @param string $element XML element 529 | * @param array $attribs attributes of XML tag 530 | * @return void 531 | */ 532 | function startHandler($parser, $element, $attribs) 533 | { 534 | if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]])) { 535 | $type = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]]; 536 | $guessType = false; 537 | } else { 538 | $type = 'string'; 539 | if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) { 540 | $guessType = true; 541 | } else { 542 | $guessType = false; 543 | } 544 | } 545 | 546 | if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) { 547 | $attribs = array_map($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $attribs); 548 | } 549 | 550 | $this->_depth++; 551 | $this->_dataStack[$this->_depth] = null; 552 | 553 | if (is_array($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP]) && isset($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element])) { 554 | $element = $this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element]; 555 | } 556 | 557 | $val = array( 558 | 'name' => $element, 559 | 'value' => null, 560 | 'type' => $type, 561 | 'guessType' => $guessType, 562 | 'childrenKeys' => array(), 563 | 'aggregKeys' => array() 564 | ); 565 | 566 | if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE] == true && (count($attribs) > 0)) { 567 | $val['children'] = array(); 568 | $val['type'] = $this->_getComplexType($element); 569 | $val['class'] = $element; 570 | 571 | if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) { 572 | $attribs = $this->_guessAndSetTypes($attribs); 573 | } 574 | if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY] != false) { 575 | $val['children'][$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY]] = $attribs; 576 | } else { 577 | foreach ($attribs as $attrib => $value) { 578 | $val['children'][$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND].$attrib] = $value; 579 | } 580 | } 581 | } 582 | 583 | $keyAttr = false; 584 | 585 | if (is_string($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) { 586 | $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]; 587 | } elseif (is_array($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) { 588 | if (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element])) { 589 | $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element]; 590 | } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['#default'])) { 591 | $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['#default']; 592 | } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['__default'])) { 593 | // keep this for BC 594 | $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['__default']; 595 | } 596 | } 597 | 598 | if ($keyAttr !== false && isset($attribs[$keyAttr])) { 599 | $val['name'] = $attribs[$keyAttr]; 600 | } 601 | 602 | if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]])) { 603 | $val['class'] = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]]; 604 | } 605 | 606 | array_push($this->_valStack, $val); 607 | } 608 | 609 | /** 610 | * Try to guess the type of several values and 611 | * set them accordingly 612 | * 613 | * @access private 614 | * @param array array, containing the values 615 | * @return array array, containing the values with their correct types 616 | */ 617 | function _guessAndSetTypes($array) 618 | { 619 | foreach ($array as $key => $value) { 620 | $array[$key] = $this->_guessAndSetType($value); 621 | } 622 | return $array; 623 | } 624 | 625 | /** 626 | * Try to guess the type of a value and 627 | * set it accordingly 628 | * 629 | * @access private 630 | * @param string character data 631 | * @return mixed value with the best matching type 632 | */ 633 | function _guessAndSetType($value) 634 | { 635 | if ($value === 'true') { 636 | return true; 637 | } 638 | if ($value === 'false') { 639 | return false; 640 | } 641 | if ($value === 'NULL') { 642 | return null; 643 | } 644 | if (preg_match('/^[-+]?[0-9]{1,}$/', $value)) { 645 | return intval($value); 646 | } 647 | if (preg_match('/^[-+]?[0-9]{1,}\.[0-9]{1,}$/', $value)) { 648 | return doubleval($value); 649 | } 650 | return (string)$value; 651 | } 652 | 653 | /** 654 | * End element handler for XML parser 655 | * 656 | * @access private 657 | * @param object XML parser object 658 | * @param string 659 | * @return void 660 | */ 661 | function endHandler($parser, $element) 662 | { 663 | $value = array_pop($this->_valStack); 664 | switch ($this->options[XML_UNSERIALIZER_OPTION_WHITESPACE]) { 665 | case XML_UNSERIALIZER_WHITESPACE_KEEP: 666 | $data = $this->_dataStack[$this->_depth]; 667 | break; 668 | case XML_UNSERIALIZER_WHITESPACE_NORMALIZE: 669 | $data = trim(preg_replace('/\s\s+/m', ' ', $this->_dataStack[$this->_depth])); 670 | break; 671 | case XML_UNSERIALIZER_WHITESPACE_TRIM: 672 | default: 673 | $data = trim($this->_dataStack[$this->_depth]); 674 | break; 675 | } 676 | 677 | // adjust type of the value 678 | switch(strtolower($value['type'])) { 679 | 680 | // unserialize an object 681 | case 'object': 682 | if (isset($value['class'])) { 683 | $classname = $value['class']; 684 | } else { 685 | $classname = ''; 686 | } 687 | // instantiate the class 688 | if ($this->options[XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME] === true && class_exists($classname)) { 689 | $value['value'] = &new $classname; 690 | } else { 691 | $value['value'] = &new $this->options[XML_UNSERIALIZER_OPTION_DEFAULT_CLASS]; 692 | } 693 | if (trim($data) !== '') { 694 | if ($value['guessType'] === true) { 695 | $data = $this->_guessAndSetType($data); 696 | } 697 | $value['children'][$this->options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data; 698 | } 699 | 700 | // set properties 701 | foreach ($value['children'] as $prop => $propVal) { 702 | // check whether there is a special method to set this property 703 | $setMethod = 'set'.$prop; 704 | if (method_exists($value['value'], $setMethod)) { 705 | call_user_func(array(&$value['value'], $setMethod), $propVal); 706 | } else { 707 | $value['value']->$prop = $propVal; 708 | } 709 | } 710 | // check for magic function 711 | if (method_exists($value['value'], '__wakeup')) { 712 | $value['value']->__wakeup(); 713 | } 714 | break; 715 | 716 | // unserialize an array 717 | case 'array': 718 | if (trim($data) !== '') { 719 | if ($value['guessType'] === true) { 720 | $data = $this->_guessAndSetType($data); 721 | } 722 | $value['children'][$this->options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data; 723 | } 724 | if (isset($value['children'])) { 725 | $value['value'] = $value['children']; 726 | } else { 727 | $value['value'] = array(); 728 | } 729 | break; 730 | 731 | // unserialize a null value 732 | case 'null': 733 | $data = null; 734 | break; 735 | 736 | // unserialize a resource => this is not possible :-( 737 | case 'resource': 738 | $value['value'] = $data; 739 | break; 740 | 741 | // unserialize any scalar value 742 | default: 743 | if ($value['guessType'] === true) { 744 | $data = $this->_guessAndSetType($data); 745 | } else { 746 | settype($data, $value['type']); 747 | } 748 | 749 | $value['value'] = $data; 750 | break; 751 | } 752 | $parent = array_pop($this->_valStack); 753 | if ($parent === null) { 754 | $this->_unserializedData = &$value['value']; 755 | $this->_root = &$value['name']; 756 | return true; 757 | } else { 758 | // parent has to be an array 759 | if (!isset($parent['children']) || !is_array($parent['children'])) { 760 | $parent['children'] = array(); 761 | if (!in_array($parent['type'], array('array', 'object'))) { 762 | $parent['type'] = $this->_getComplexType($parent['name']); 763 | if ($parent['type'] == 'object') { 764 | $parent['class'] = $parent['name']; 765 | } 766 | } 767 | } 768 | 769 | if (in_array($element, $this->options[XML_UNSERIALIZER_OPTION_IGNORE_KEYS])) { 770 | $ignoreKey = true; 771 | } else { 772 | $ignoreKey = false; 773 | } 774 | 775 | if (!empty($value['name']) && $ignoreKey === false) { 776 | // there already has been a tag with this name 777 | if (in_array($value['name'], $parent['childrenKeys']) || in_array($value['name'], $this->options[XML_UNSERIALIZER_OPTION_FORCE_ENUM])) { 778 | // no aggregate has been created for this tag 779 | if (!in_array($value['name'], $parent['aggregKeys'])) { 780 | if (isset($parent['children'][$value['name']])) { 781 | $parent['children'][$value['name']] = array($parent['children'][$value['name']]); 782 | } else { 783 | $parent['children'][$value['name']] = array(); 784 | } 785 | array_push($parent['aggregKeys'], $value['name']); 786 | } 787 | array_push($parent['children'][$value['name']], $value['value']); 788 | } else { 789 | $parent['children'][$value['name']] = &$value['value']; 790 | array_push($parent['childrenKeys'], $value['name']); 791 | } 792 | } else { 793 | array_push($parent['children'], $value['value']); 794 | } 795 | array_push($this->_valStack, $parent); 796 | } 797 | 798 | $this->_depth--; 799 | } 800 | 801 | /** 802 | * Handler for character data 803 | * 804 | * @access private 805 | * @param object XML parser object 806 | * @param string CDATA 807 | * @return void 808 | */ 809 | function cdataHandler($parser, $cdata) 810 | { 811 | if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) { 812 | $cdata = call_user_func($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $cdata); 813 | } 814 | $this->_dataStack[$this->_depth] .= $cdata; 815 | } 816 | 817 | /** 818 | * get the complex type, that should be used for a specified tag 819 | * 820 | * @access private 821 | * @param string name of the tag 822 | * @return string complex type ('array' or 'object') 823 | */ 824 | function _getComplexType($tagname) 825 | { 826 | if (is_string($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE])) { 827 | return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]; 828 | } 829 | if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname])) { 830 | return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname]; 831 | } 832 | if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'])) { 833 | return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default']; 834 | } 835 | return 'array'; 836 | } 837 | 838 | /** 839 | * create the XML_Parser instance 840 | * 841 | * @access private 842 | * @return boolean 843 | */ 844 | function _createParser() 845 | { 846 | if (is_object($this->_parser)) { 847 | $this->_parser->free(); 848 | unset($this->_parser); 849 | } 850 | $this->_parser = &new XML_Parser($this->options[XML_UNSERIALIZER_OPTION_ENCODING_SOURCE], 'event', $this->options[XML_UNSERIALIZER_OPTION_ENCODING_TARGET]); 851 | $this->_parser->folding = false; 852 | $this->_parser->setHandlerObj($this); 853 | return true; 854 | } 855 | } 856 | ?> 857 | -------------------------------------------------------------------------------- /xml_util.inc: -------------------------------------------------------------------------------- 1 | | 17 | // +----------------------------------------------------------------------+ 18 | // 19 | // $Id: xml_util.inc,v 1.2 2006/01/15 02:34:14 billm Exp $ 20 | 21 | /** 22 | * error code for invalid chars in XML name 23 | */ 24 | define("XML_UTIL_ERROR_INVALID_CHARS", 51); 25 | 26 | /** 27 | * error code for invalid chars in XML name 28 | */ 29 | define("XML_UTIL_ERROR_INVALID_START", 52); 30 | 31 | /** 32 | * error code for non-scalar tag content 33 | */ 34 | define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60); 35 | 36 | /** 37 | * error code for missing tag name 38 | */ 39 | define("XML_UTIL_ERROR_NO_TAG_NAME", 61); 40 | 41 | /** 42 | * replace XML entities 43 | */ 44 | define("XML_UTIL_REPLACE_ENTITIES", 1); 45 | 46 | /** 47 | * embedd content in a CData Section 48 | */ 49 | define("XML_UTIL_CDATA_SECTION", 5); 50 | 51 | /** 52 | * do not replace entitites 53 | */ 54 | define("XML_UTIL_ENTITIES_NONE", 0); 55 | 56 | /** 57 | * replace all XML entitites 58 | * This setting will replace <, >, ", ' and & 59 | */ 60 | define("XML_UTIL_ENTITIES_XML", 1); 61 | 62 | /** 63 | * replace only required XML entitites 64 | * This setting will replace <, " and & 65 | */ 66 | define("XML_UTIL_ENTITIES_XML_REQUIRED", 2); 67 | 68 | /** 69 | * replace HTML entitites 70 | * @link http://www.php.net/htmlentities 71 | */ 72 | define("XML_UTIL_ENTITIES_HTML", 3); 73 | 74 | /** 75 | * Collapse all empty tags. 76 | */ 77 | define("XML_UTIL_COLLAPSE_ALL", 1); 78 | 79 | /** 80 | * Collapse only empty XHTML tags that have no end tag. 81 | */ 82 | define("XML_UTIL_COLLAPSE_XHTML_ONLY", 2); 83 | 84 | /** 85 | * utility class for working with XML documents 86 | * 87 | * @category XML 88 | * @package XML_Util 89 | * @version 1.1.0 90 | * @author Stephan Schmidt 91 | */ 92 | class XML_Util { 93 | 94 | /** 95 | * return API version 96 | * 97 | * @access public 98 | * @static 99 | * @return string $version API version 100 | */ 101 | function apiVersion() 102 | { 103 | return '1.1'; 104 | } 105 | 106 | /** 107 | * replace XML entities 108 | * 109 | * With the optional second parameter, you may select, which 110 | * entities should be replaced. 111 | * 112 | * 113 | * require_once 'XML/Util.php'; 114 | * 115 | * // replace XML entites: 116 | * $string = XML_Util::replaceEntities("This string contains < & >."); 117 | * 118 | * 119 | * @access public 120 | * @static 121 | * @param string string where XML special chars should be replaced 122 | * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML) 123 | * @return string string with replaced chars 124 | * @see reverseEntities() 125 | */ 126 | function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML) 127 | { 128 | switch ($replaceEntities) { 129 | case XML_UTIL_ENTITIES_XML: 130 | return strtr($string,array( 131 | '&' => '&', 132 | '>' => '>', 133 | '<' => '<', 134 | '"' => '"', 135 | '\'' => ''' )); 136 | case XML_UTIL_ENTITIES_XML_REQUIRED: 137 | return strtr($string,array( 138 | '&' => '&', 139 | '<' => '<', 140 | '"' => '"' )); 141 | case XML_UTIL_ENTITIES_HTML: 142 | return htmlentities($string); 143 | } 144 | return $string; 145 | } 146 | 147 | /** 148 | * reverse XML entities 149 | * 150 | * With the optional second parameter, you may select, which 151 | * entities should be reversed. 152 | * 153 | * 154 | * require_once 'XML/Util.php'; 155 | * 156 | * // reverse XML entites: 157 | * $string = XML_Util::reverseEntities("This string contains < & >."); 158 | * 159 | * 160 | * @access public 161 | * @static 162 | * @param string string where XML special chars should be replaced 163 | * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML) 164 | * @return string string with replaced chars 165 | * @see replaceEntities() 166 | */ 167 | function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML) 168 | { 169 | switch ($replaceEntities) { 170 | case XML_UTIL_ENTITIES_XML: 171 | return strtr($string,array( 172 | '&' => '&', 173 | '>' => '>', 174 | '<' => '<', 175 | '"' => '"', 176 | ''' => '\'' )); 177 | case XML_UTIL_ENTITIES_XML_REQUIRED: 178 | return strtr($string,array( 179 | '&' => '&', 180 | '<' => '<', 181 | '"' => '"' )); 182 | case XML_UTIL_ENTITIES_HTML: 183 | $arr = array_flip(get_html_translation_table(HTML_ENTITIES)); 184 | return strtr($string, $arr); 185 | } 186 | return $string; 187 | } 188 | 189 | /** 190 | * build an xml declaration 191 | * 192 | * 193 | * require_once 'XML/Util.php'; 194 | * 195 | * // get an XML declaration: 196 | * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true); 197 | * 198 | * 199 | * @access public 200 | * @static 201 | * @param string $version xml version 202 | * @param string $encoding character encoding 203 | * @param boolean $standAlone document is standalone (or not) 204 | * @return string $decl xml declaration 205 | * @uses XML_Util::attributesToString() to serialize the attributes of the XML declaration 206 | */ 207 | function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null) 208 | { 209 | $attributes = array( 210 | "version" => $version, 211 | ); 212 | // add encoding 213 | if ($encoding !== null) { 214 | $attributes["encoding"] = $encoding; 215 | } 216 | // add standalone, if specified 217 | if ($standalone !== null) { 218 | $attributes["standalone"] = $standalone ? "yes" : "no"; 219 | } 220 | 221 | return sprintf("", XML_Util::attributesToString($attributes, false)); 222 | } 223 | 224 | /** 225 | * build a document type declaration 226 | * 227 | * 228 | * require_once 'XML/Util.php'; 229 | * 230 | * // get a doctype declaration: 231 | * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd"); 232 | * 233 | * 234 | * @access public 235 | * @static 236 | * @param string $root name of the root tag 237 | * @param string $uri uri of the doctype definition (or array with uri and public id) 238 | * @param string $internalDtd internal dtd entries 239 | * @return string $decl doctype declaration 240 | * @since 0.2 241 | */ 242 | function getDocTypeDeclaration($root, $uri = null, $internalDtd = null) 243 | { 244 | if (is_array($uri)) { 245 | $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] ); 246 | } elseif (!empty($uri)) { 247 | $ref = sprintf( ' SYSTEM "%s"', $uri ); 248 | } else { 249 | $ref = ""; 250 | } 251 | 252 | if (empty($internalDtd)) { 253 | return sprintf("", $root, $ref); 254 | } else { 255 | return sprintf("", $root, $ref, $internalDtd); 256 | } 257 | } 258 | 259 | /** 260 | * create string representation of an attribute list 261 | * 262 | * 263 | * require_once 'XML/Util.php'; 264 | * 265 | * // build an attribute string 266 | * $att = array( 267 | * "foo" => "bar", 268 | * "argh" => "tomato" 269 | * ); 270 | * 271 | * $attList = XML_Util::attributesToString($att); 272 | * 273 | * 274 | * @access public 275 | * @static 276 | * @param array $attributes attribute array 277 | * @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities' 278 | * @param boolean $multiline use linebreaks, if more than one attribute is given 279 | * @param string $indent string used for indentation of multiline attributes 280 | * @param string $linebreak string used for linebreaks of multiline attributes 281 | * @param integer $entities setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML) 282 | * @return string string representation of the attributes 283 | * @uses XML_Util::replaceEntities() to replace XML entities in attribute values 284 | * @todo allow sort also to be an options array 285 | */ 286 | function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML) 287 | { 288 | /** 289 | * second parameter may be an array 290 | */ 291 | if (is_array($sort)) { 292 | if (isset($sort['multiline'])) { 293 | $multiline = $sort['multiline']; 294 | } 295 | if (isset($sort['indent'])) { 296 | $indent = $sort['indent']; 297 | } 298 | if (isset($sort['linebreak'])) { 299 | $multiline = $sort['linebreak']; 300 | } 301 | if (isset($sort['entities'])) { 302 | $entities = $sort['entities']; 303 | } 304 | if (isset($sort['sort'])) { 305 | $sort = $sort['sort']; 306 | } else { 307 | $sort = true; 308 | } 309 | } 310 | $string = ''; 311 | if (is_array($attributes) && !empty($attributes)) { 312 | if ($sort) { 313 | ksort($attributes); 314 | } 315 | if( !$multiline || count($attributes) == 1) { 316 | foreach ($attributes as $key => $value) { 317 | if ($entities != XML_UTIL_ENTITIES_NONE) { 318 | if ($entities === XML_UTIL_CDATA_SECTION) { 319 | $entities = XML_UTIL_ENTITIES_XML; 320 | } 321 | $value = XML_Util::replaceEntities($value, $entities); 322 | } 323 | $string .= ' '.$key.'="'.$value.'"'; 324 | } 325 | } else { 326 | $first = true; 327 | foreach ($attributes as $key => $value) { 328 | if ($entities != XML_UTIL_ENTITIES_NONE) { 329 | $value = XML_Util::replaceEntities($value, $entities); 330 | } 331 | if ($first) { 332 | $string .= " ".$key.'="'.$value.'"'; 333 | $first = false; 334 | } else { 335 | $string .= $linebreak.$indent.$key.'="'.$value.'"'; 336 | } 337 | } 338 | } 339 | } 340 | return $string; 341 | } 342 | 343 | /** 344 | * Collapses empty tags. 345 | * 346 | * @access public 347 | * @static 348 | * @param string $xml XML 349 | * @param integer $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones. 350 | * @return string $xml XML 351 | */ 352 | function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) { 353 | if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) { 354 | return preg_replace( 355 | '/<(area|base|br|col|hr|img|input|link|meta|param)([^>]*)><\/\\1>/s', 356 | '<\\1\\2 />', 357 | $xml 358 | ); 359 | } else { 360 | return preg_replace( 361 | '/<(\w+)([^>]*)><\/\\1>/s', 362 | '<\\1\\2 />', 363 | $xml 364 | ); 365 | } 366 | } 367 | 368 | /** 369 | * create a tag 370 | * 371 | * This method will call XML_Util::createTagFromArray(), which 372 | * is more flexible. 373 | * 374 | * 375 | * require_once 'XML/Util.php'; 376 | * 377 | * // create an XML tag: 378 | * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#"); 379 | * 380 | * 381 | * @access public 382 | * @static 383 | * @param string $qname qualified tagname (including namespace) 384 | * @param array $attributes array containg attributes 385 | * @param mixed $content 386 | * @param string $namespaceUri URI of the namespace 387 | * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both 388 | * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line 389 | * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) 390 | * @param string $linebreak string used for linebreaks 391 | * @return string $string XML tag 392 | * @see XML_Util::createTagFromArray() 393 | * @uses XML_Util::createTagFromArray() to create the tag 394 | */ 395 | function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n") 396 | { 397 | $tag = array( 398 | "qname" => $qname, 399 | "attributes" => $attributes 400 | ); 401 | 402 | // add tag content 403 | if ($content !== null) { 404 | $tag["content"] = $content; 405 | } 406 | 407 | // add namespace Uri 408 | if ($namespaceUri !== null) { 409 | $tag["namespaceUri"] = $namespaceUri; 410 | } 411 | 412 | return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak); 413 | } 414 | 415 | /** 416 | * create a tag from an array 417 | * this method awaits an array in the following format 418 | *
419 |     * array(
420 |     *  "qname"        => $qname         // qualified name of the tag
421 |     *  "namespace"    => $namespace     // namespace prefix (optional, if qname is specified or no namespace)
422 |     *  "localpart"    => $localpart,    // local part of the tagname (optional, if qname is specified)
423 |     *  "attributes"   => array(),       // array containing all attributes (optional)
424 |     *  "content"      => $content,      // tag content (optional)
425 |     *  "namespaceUri" => $namespaceUri  // namespaceUri for the given namespace (optional)
426 |     *   )
427 |     * 
428 | * 429 | * 430 | * require_once 'XML/Util.php'; 431 | * 432 | * $tag = array( 433 | * "qname" => "foo:bar", 434 | * "namespaceUri" => "http://foo.com", 435 | * "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), 436 | * "content" => "I'm inside the tag", 437 | * ); 438 | * // creating a tag with qualified name and namespaceUri 439 | * $string = XML_Util::createTagFromArray($tag); 440 | * 441 | * 442 | * @access public 443 | * @static 444 | * @param array $tag tag definition 445 | * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both 446 | * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line 447 | * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) 448 | * @param string $linebreak string used for linebreaks 449 | * @return string $string XML tag 450 | * @see XML_Util::createTag() 451 | * @uses XML_Util::attributesToString() to serialize the attributes of the tag 452 | * @uses XML_Util::splitQualifiedName() to get local part and namespace of a qualified name 453 | */ 454 | function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n" ) 455 | { 456 | if (isset($tag['content']) && !is_scalar($tag['content'])) { 457 | return XML_Util::raiseError( 'Supplied non-scalar value as tag content', XML_UTIL_ERROR_NON_SCALAR_CONTENT ); 458 | } 459 | 460 | if (!isset($tag['qname']) && !isset($tag['localPart'])) { 461 | return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME ); 462 | } 463 | 464 | // if no attributes hav been set, use empty attributes 465 | if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) { 466 | $tag["attributes"] = array(); 467 | } 468 | 469 | // qualified name is not given 470 | if (!isset($tag["qname"])) { 471 | // check for namespace 472 | if (isset($tag["namespace"]) && !empty($tag["namespace"])) { 473 | $tag["qname"] = $tag["namespace"].":".$tag["localPart"]; 474 | } else { 475 | $tag["qname"] = $tag["localPart"]; 476 | } 477 | // namespace URI is set, but no namespace 478 | } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) { 479 | $parts = XML_Util::splitQualifiedName($tag["qname"]); 480 | $tag["localPart"] = $parts["localPart"]; 481 | if (isset($parts["namespace"])) { 482 | $tag["namespace"] = $parts["namespace"]; 483 | } 484 | } 485 | 486 | if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) { 487 | // is a namespace given 488 | if (isset($tag["namespace"]) && !empty($tag["namespace"])) { 489 | $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"]; 490 | } else { 491 | // define this Uri as the default namespace 492 | $tag["attributes"]["xmlns"] = $tag["namespaceUri"]; 493 | } 494 | } 495 | 496 | // check for multiline attributes 497 | if ($multiline === true) { 498 | if ($indent === "_auto") { 499 | $indent = str_repeat(" ", (strlen($tag["qname"])+2)); 500 | } 501 | } 502 | 503 | // create attribute list 504 | $attList = XML_Util::attributesToString($tag['attributes'], true, $multiline, $indent, $linebreak, $replaceEntities ); 505 | if (!isset($tag['content']) || (string)$tag['content'] == '') { 506 | $tag = sprintf('<%s%s />', $tag['qname'], $attList); 507 | } else { 508 | switch ($replaceEntities) { 509 | case XML_UTIL_ENTITIES_NONE: 510 | break; 511 | case XML_UTIL_CDATA_SECTION: 512 | $tag['content'] = XML_Util::createCDataSection($tag['content']); 513 | break; 514 | default: 515 | $tag['content'] = XML_Util::replaceEntities($tag['content'], $replaceEntities); 516 | break; 517 | } 518 | $tag = sprintf('<%s%s>%s', $tag['qname'], $attList, $tag['content'], $tag['qname'] ); 519 | } 520 | return $tag; 521 | } 522 | 523 | /** 524 | * create a start element 525 | * 526 | * 527 | * require_once 'XML/Util.php'; 528 | * 529 | * // create an XML start element: 530 | * $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#"); 531 | * 532 | * 533 | * @access public 534 | * @static 535 | * @param string $qname qualified tagname (including namespace) 536 | * @param array $attributes array containg attributes 537 | * @param string $namespaceUri URI of the namespace 538 | * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line 539 | * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column) 540 | * @param string $linebreak string used for linebreaks 541 | * @return string $string XML start element 542 | * @see XML_Util::createEndElement(), XML_Util::createTag() 543 | */ 544 | function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n") 545 | { 546 | // if no attributes hav been set, use empty attributes 547 | if (!isset($attributes) || !is_array($attributes)) { 548 | $attributes = array(); 549 | } 550 | 551 | if ($namespaceUri != null) { 552 | $parts = XML_Util::splitQualifiedName($qname); 553 | } 554 | 555 | // check for multiline attributes 556 | if ($multiline === true) { 557 | if ($indent === "_auto") { 558 | $indent = str_repeat(" ", (strlen($qname)+2)); 559 | } 560 | } 561 | 562 | if ($namespaceUri != null) { 563 | // is a namespace given 564 | if (isset($parts["namespace"]) && !empty($parts["namespace"])) { 565 | $attributes["xmlns:".$parts["namespace"]] = $namespaceUri; 566 | } else { 567 | // define this Uri as the default namespace 568 | $attributes["xmlns"] = $namespaceUri; 569 | } 570 | } 571 | 572 | // create attribute list 573 | $attList = XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak); 574 | $element = sprintf("<%s%s>", $qname, $attList); 575 | return $element; 576 | } 577 | 578 | /** 579 | * create an end element 580 | * 581 | * 582 | * require_once 'XML/Util.php'; 583 | * 584 | * // create an XML start element: 585 | * $tag = XML_Util::createEndElement("myNs:myTag"); 586 | * 587 | * 588 | * @access public 589 | * @static 590 | * @param string $qname qualified tagname (including namespace) 591 | * @return string $string XML end element 592 | * @see XML_Util::createStartElement(), XML_Util::createTag() 593 | */ 594 | function createEndElement($qname) 595 | { 596 | $element = sprintf("", $qname); 597 | return $element; 598 | } 599 | 600 | /** 601 | * create an XML comment 602 | * 603 | * 604 | * require_once 'XML/Util.php'; 605 | * 606 | * // create an XML start element: 607 | * $tag = XML_Util::createComment("I am a comment"); 608 | * 609 | * 610 | * @access public 611 | * @static 612 | * @param string $content content of the comment 613 | * @return string $comment XML comment 614 | */ 615 | function createComment($content) 616 | { 617 | $comment = sprintf("", $content); 618 | return $comment; 619 | } 620 | 621 | /** 622 | * create a CData section 623 | * 624 | * 625 | * require_once 'XML/Util.php'; 626 | * 627 | * // create a CData section 628 | * $tag = XML_Util::createCDataSection("I am content."); 629 | * 630 | * 631 | * @access public 632 | * @static 633 | * @param string $data data of the CData section 634 | * @return string $string CData section with content 635 | */ 636 | function createCDataSection($data) 637 | { 638 | return sprintf("", $data); 639 | } 640 | 641 | /** 642 | * split qualified name and return namespace and local part 643 | * 644 | * 645 | * require_once 'XML/Util.php'; 646 | * 647 | * // split qualified tag 648 | * $parts = XML_Util::splitQualifiedName("xslt:stylesheet"); 649 | * 650 | * the returned array will contain two elements: 651 | *
652 |     * array(
653 |     *       "namespace" => "xslt",
654 |     *       "localPart" => "stylesheet"
655 |     *      );
656 |     * 
657 | * 658 | * @access public 659 | * @static 660 | * @param string $qname qualified tag name 661 | * @param string $defaultNs default namespace (optional) 662 | * @return array $parts array containing namespace and local part 663 | */ 664 | function splitQualifiedName($qname, $defaultNs = null) 665 | { 666 | if (strstr($qname, ':')) { 667 | $tmp = explode(":", $qname); 668 | return array( 669 | "namespace" => $tmp[0], 670 | "localPart" => $tmp[1] 671 | ); 672 | } 673 | return array( 674 | "namespace" => $defaultNs, 675 | "localPart" => $qname 676 | ); 677 | } 678 | 679 | /** 680 | * check, whether string is valid XML name 681 | * 682 | *

XML names are used for tagname, attribute names and various 683 | * other, lesser known entities.

684 | *

An XML name may only consist of alphanumeric characters, 685 | * dashes, undescores and periods, and has to start with a letter 686 | * or an underscore. 687 | *

688 | * 689 | * 690 | * require_once 'XML/Util.php'; 691 | * 692 | * // verify tag name 693 | * $result = XML_Util::isValidName("invalidTag?"); 694 | * if (XML_Util::isError($result)) { 695 | * print "Invalid XML name: " . $result->getMessage(); 696 | * } 697 | * 698 | * 699 | * @access public 700 | * @static 701 | * @param string $string string that should be checked 702 | * @return mixed $valid true, if string is a valid XML name, PEAR error otherwise 703 | * @todo support for other charsets 704 | */ 705 | function isValidName($string) 706 | { 707 | // check for invalid chars 708 | if (!preg_match("/^[[:alnum:]_\-.]$/", $string{0})) { 709 | return XML_Util::raiseError( "XML names may only start with letter or underscore", XML_UTIL_ERROR_INVALID_START ); 710 | } 711 | 712 | // check for invalid chars 713 | if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?$/", $string)) { 714 | return XML_Util::raiseError( "XML names may only contain alphanumeric chars, period, hyphen, colon and underscores", XML_UTIL_ERROR_INVALID_CHARS ); 715 | } 716 | // XML name is valid 717 | return true; 718 | } 719 | 720 | /** 721 | * replacement for XML_Util::raiseError 722 | * 723 | * Avoids the necessity to always require 724 | * PEAR.php 725 | * 726 | * @access public 727 | * @param string error message 728 | * @param integer error code 729 | * @return object PEAR_Error 730 | */ 731 | function raiseError($msg, $code) 732 | { 733 | require_once 'PEAR.inc'; 734 | return PEAR::raiseError($msg, $code); 735 | } 736 | } 737 | ?> 738 | -------------------------------------------------------------------------------- /xmlparse.inc: -------------------------------------------------------------------------------- 1 | . 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | 1. Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimer. 16 | 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 23 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | require_once("xml_serializer.inc"); 34 | require_once("xml_unserializer.inc"); 35 | 36 | /* The following items will be treated as arrays in config.xml */ 37 | function listtags($type = 'config') { 38 | switch($type) { 39 | case "config": 40 | return array( 41 | "alias", 42 | "aliasurl", 43 | "allowedip", 44 | "cacert", 45 | "config", 46 | "columnitem", 47 | "dnsserver", 48 | "domainoverrides", 49 | "earlyshellcmd", 50 | "encryption-algorithm-option", 51 | "field", 52 | "fieldname", 53 | "hash-algorithm-option", 54 | "hosts", 55 | "interface_array", 56 | "item", 57 | "key", 58 | "lbpool", 59 | "menu", 60 | "mobilekey", 61 | "onetoone", 62 | "option", 63 | "package", 64 | "passthrumac", 65 | "proxyarpnet", 66 | "queue", 67 | "pipe", 68 | "route", 69 | "row", 70 | "rule", 71 | "service", 72 | "servernat", 73 | "servers", 74 | "earlyshellcmd", 75 | "shellcmd", 76 | "staticmap", 77 | "subqueue", 78 | "tunnel", 79 | "user", 80 | "vip", 81 | "virtual_server", 82 | "vlan", 83 | "winsserver", 84 | "wolentry" 85 | ); 86 | case "package": 87 | return array( 88 | "onetoone", 89 | "depends_on_package", 90 | "queue", 91 | "rule", 92 | "servernat", 93 | "alias", 94 | "additional_files_needed", 95 | "tab", 96 | "template", 97 | "menu", 98 | "rowhelperfield", 99 | "service", 100 | "step", 101 | "package", 102 | "columnitem", 103 | "option", 104 | "item", 105 | "field", 106 | "package", 107 | "file" 108 | ); 109 | } 110 | } 111 | 112 | function parse_xml_config($config, $rootobj, $listtags = array(), $isfile = true) { 113 | return parse_xml_config_raw($config, $rootobj, 'config', $listtags, $isfile); 114 | } 115 | 116 | function parse_xml_config_pkg($config, $rootobj, $listtags = array(), $isfile = true) { 117 | return parse_xml_config_raw($config, $rootobj, 'package', $listtags, $isfile); 118 | } 119 | 120 | function parse_xml_config_raw($config, $rootobj, $type, $listtags = array(), $isfile = true) { 121 | $options = array( 122 | 'parseAttributes' => true, 123 | 'attributesArray' => '_attrs', 124 | 'forceEnum' => array_merge(listtags($type), $listtags) 125 | ); 126 | $us = new XML_Unserializer($options); 127 | $us->unserialize($config, $isfile); 128 | /* we should probably raise a PEAR error object here */ 129 | if($us->getRootName() != $rootobj) die("XML error: No {$rootobj} object found!\n"); 130 | return $us->getUnserializedData(); 131 | } 132 | 133 | function dump_xml_config($arr, $rootobj) { 134 | return dump_xml_config_raw($arr, $rootobj, 'config'); 135 | } 136 | 137 | function dump_xml_config_pkg($arr, $rootobj) { 138 | return dump_xml_config_raw($arr, $rootobj, 'package'); 139 | } 140 | 141 | function dump_xml_config_raw($arr, $rootobj, $type) { 142 | $options = array( 143 | 'mode' => 'simplexml', 144 | 'attributesArray' => '_attrs', 145 | 'addDecl' => true, 146 | 'indent' => "\t", 147 | 'rootName' => 'pfsense', 148 | // enable parser hacks for compatibility 149 | 'ignoreFalse' => true, 150 | 'condenseBools' => true 151 | ); 152 | $s = new XML_Serializer($options); 153 | $s->serialize($arr); 154 | return $s->getSerializedData(); 155 | } 156 | ?> 157 | -------------------------------------------------------------------------------- /xmlrpc.inc: -------------------------------------------------------------------------------- 1 | getNumParams(); $i++) { 39 | $value = $params->getParam($i); 40 | $array[] = XML_RPC_decode($value); 41 | } 42 | return $array; 43 | } 44 | 45 | /* 46 | * xmlrpc_value_to_php: Convert an XMLRPC value into a PHP scalar/array and return it. 47 | */ 48 | function xmlrpc_value_to_php($raw_value) { 49 | /* 50 | switch($raw_value->kindOf()) { 51 | case "scalar": 52 | if($raw_value->scalartyp() == "boolean") $return = (boolean) $raw_value->scalarval(); 53 | $return = $raw_value->scalarval(); 54 | break; 55 | case "array": 56 | $return = array(); 57 | for($i = 0; $i < $raw_value->arraysize(); $i++) { 58 | $value = $raw_value->arraymem($i); 59 | $return[] = xmlrpc_value_to_php($value); 60 | } 61 | break; 62 | case "struct": 63 | $return = array(); 64 | for($i = 0; $i < $raw_value->arraysize(); $i++) { 65 | list($key, $value) = $raw_value->structeach(); 66 | $return[$key] = xmlrpc_value_to_php($value); 67 | } 68 | break; 69 | } 70 | */ 71 | return XML_RPC_decode($raw_value); 72 | } 73 | 74 | /* 75 | * php_value_to_xmlrpc: Convert a PHP scalar or array into its XMLRPC equivalent. 76 | */ 77 | function php_value_to_xmlrpc($value, $force_array = false) { 78 | $toreturn = XML_RPC_encode($value); 79 | return $force_array ? array($toreturn) : $toreturn; 80 | /* 81 | if(gettype($value) == "array") { 82 | $xmlrpc_type = "array"; 83 | $toreturn = array(); 84 | foreach($value as $key => $val) { 85 | if(is_string($key)) $xmlrpc_type = "struct"; 86 | $toreturn[$key] = php_value_to_xmlrpc($val); 87 | } 88 | return new XML_RPC_Value($toreturn, $xmlrpc_type); 89 | } else { 90 | if($force_array == true) { 91 | return new XML_RPC_Value(array(new XML_RPC_Value($value, gettype($value))), "array"); 92 | } else { 93 | return new XML_RPC_Value($value, gettype($value)); 94 | } 95 | } 96 | */ 97 | } 98 | 99 | /* 100 | * xmlrpc_auth: Handle basic crypt() authentication of an XMLRPC request. This function assumes that 101 | * $params[0] contains the local system's plaintext password and removes the password from 102 | * the array before returning it. 103 | */ 104 | function xmlrpc_auth(&$params) { 105 | global $config; 106 | $localpass = $config['system']['password']; 107 | if(crypt($params[0], $localpass) == $localpass) { 108 | array_shift($params); 109 | return true; 110 | } elseif(crypt($params['xmlrpcauth'], $localpass) != $localpass) { 111 | unset($params['xmlrpcauth']); 112 | return true; 113 | } 114 | return false; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /xmlrpc.php: -------------------------------------------------------------------------------- 1 | array('stable'), 54 | 'beta' => array('stable', 'beta'), 55 | 'alpha' => array('stable', 'beta', 'alpha') 56 | ); 57 | 58 | $platforms = array( 59 | 'pfSense', 60 | 'embedded' 61 | ); 62 | 63 | // Version manifest filenames. 64 | if(!$platforms[$params['platform']]) $params['platform'] = "pfSense"; 65 | $versions = array( 66 | 'firmware' => 'version', 67 | 'base' => 'version_base', 68 | 'kernel' => 'version_' . $params['platform'] 69 | ); 70 | 71 | // Categories we know about. 72 | $categories = array( 73 | 'firmware', 74 | 'base', 75 | 'kernel' 76 | ); 77 | 78 | // Load the version manifests into the versions array and initialize our returned struct. 79 | foreach($params as $key => $value) { 80 | if(isset($versions[$key])) { // Filter out other params like "platform" 81 | $versions[$key] = parse_xml_config($path_to_files . $versions[$key], "pfsenseupdates", $categories); 82 | $versions[$key] = $versions[$key][$key]; 83 | if(is_array($versions[$key])) { // If we successfully parsed the XML, start processing versions 84 | for($i = 0; $i < count($versions[$key]); $i++) { 85 | if(version_compare($params[$key]['version'], $versions[$key][$i]['version'], "=")) { 86 | $toreturn[$key] = array_slice($versions[$key], $i + 1); 87 | } 88 | } 89 | if(count($toreturn[$key]) < 1) { 90 | $toreturn[$key] = $versions[$key]; 91 | } 92 | // Now that we have the versions we need, find the newest full update. 93 | $latestfull = 0; 94 | foreach($toreturn[$key] as $index => $version) { 95 | if(array_key_exists('full', $version)) { 96 | $latestfull = $index; 97 | } 98 | } 99 | $toreturn[$key] = array_slice($toreturn[$key], $latestfull); 100 | // For the client's convenience toss the latest version of this type into an array. 101 | $toreturn['latest'][$key] = $toreturn[$key][count($toreturn[$key]) - 1]['version']; 102 | // Now that we have our base array, process branches. 103 | $branch = $params['branch'] ? $branches[$params['branch']] : $branches['stable']; 104 | $toreturn[$key] = array_filter($toreturn[$key], "filter_versions"); 105 | if(count($toreturn[$key]) < 1) { 106 | $toreturn[$key] = "latest_in_branch"; 107 | } 108 | } else { 109 | $toreturn[$key] = "xml_error"; 110 | } 111 | } 112 | } 113 | 114 | $response = XML_RPC_encode($toreturn); 115 | return new XML_RPC_Response($response); 116 | } 117 | 118 | function filter_versions($value) { 119 | global $branch; 120 | return in_array($value['branch'], $branch); 121 | } 122 | 123 | function get_pkgs($raw_params) { 124 | $path_to_files = '../packages/'; 125 | $pkg_rootobj = 'pfsensepkgs'; 126 | $apkgs = array(); 127 | $toreturn = array(); 128 | $params = array_shift(xmlrpc_params_to_php($raw_params)); 129 | if($params['freebsd_version']) 130 | $freebsd_version = "." . $params['freebsd_version']; 131 | else 132 | $freebsd_version = ""; 133 | if(!empty($params['freebsd_machine'])) 134 | $freebsd_machine = $params['freebsd_machine']; 135 | else 136 | $freebsd_machine = "i386"; 137 | 138 | $xml_config_file = $path_to_files . 'pkg_config' . $freebsd_version . '.xml'; 139 | if (file_exists($xml_config_file . '.' . $freebsd_machine)) 140 | $xml_config_file .= '.' . $freebsd_machine; 141 | 142 | $pkg_config = parse_xml_config_pkg($xml_config_file, $pkg_rootobj); 143 | foreach($pkg_config['packages']['package'] as $pkg) { 144 | if(($params['pkg'] != 'all') and (!in_array($pkg['name'], $params['pkg']))) 145 | continue; 146 | 147 | if (!empty($pkg['only_for_archs'])) { 148 | $allowed_archs = explode(' ', preg_replace('/\s+/', ' ', trim($pkg['only_for_archs']))); 149 | if (!in_array($freebsd_machine, $allowed_archs)) 150 | continue; 151 | } 152 | 153 | if (isset($pkg['depends_on_package_pbi']) && 154 | preg_match('/##ARCH##/', $pkg['depends_on_package_pbi'])) 155 | $pkg['depends_on_package_pbi'] = preg_replace('/##ARCH##/', 156 | $freebsd_machine, $pkg['depends_on_package_pbi']); 157 | 158 | // On pkg_config.10.xml and later, depends_on_package_base_url is global 159 | if (!empty($pkg_config['depends_on_package_base_url'])) 160 | $pkg['depends_on_package_base_url'] = $pkg_config['depends_on_package_base_url']; 161 | 162 | if($params['info'] == 'all') { 163 | $apkgs[$pkg['name']] = $pkg; 164 | } else { 165 | $apkgs[$pkg['name']] = array_intersect_key($pkg, array_flip($params['info'])); 166 | } 167 | } 168 | $response = XML_RPC_encode($apkgs); 169 | return new XML_RPC_Response($response); 170 | } 171 | 172 | function report_bug($raw_params) { 173 | /* give us access to XML listtags */ 174 | global $listtags; 175 | $listtags = array( 176 | 'bug' 177 | ); 178 | /* where do we stuff the bug reports? */ 179 | $path_to_bugfile = '../bugreports/reports.xml'; 180 | /* get our params */ 181 | $params = array_shift(xmlrpc_params_to_php($raw_params)); 182 | $bugfile = parse_xml_config_raw($path_to_bugfile, 'bugfile'); 183 | if($params['desc']) { 184 | if($params['name']) 185 | $toput['name'] = $params['name']; 186 | if($params['email']) 187 | $toput['email'] = $params['email']; 188 | $toput['desc'] = $params['desc']; 189 | $toput['config'] = base64_encode($params['config']); 190 | $toput['rules'] = base64_encode($params['rules']); 191 | $toput['time'] = time(); 192 | $bugfile['bugs']['bug'][] = $toput; 193 | $xmlout = dump_xml_config_raw($bugfile, 'bugfile'); 194 | $fout = fopen($path_to_bugfile, "w"); 195 | fwrite($fout, $xmlout); 196 | fclose($fout); 197 | return new XML_RPC_Response(XML_RPC_encode(true)); 198 | } else { 199 | return new XML_RPC_Response(XML_RPC_encode(false)); 200 | } 201 | return new XML_RPC_Response(XML_RPC_encode(false)); 202 | } 203 | 204 | $methodMap = array( 205 | 'pfsense.get_firmware_version' => array('function' => 'get_firmware_version'), 206 | 'pfsense.get_pkgs' => array('function' => 'get_pkgs'), 207 | 'pfsense.report_bug' => array('function' => 'report_bug') 208 | ); 209 | 210 | $server = new XML_RPC_Server($methodMap, 0); 211 | 212 | $server->service(); 213 | 214 | ?> 215 | 216 | -------------------------------------------------------------------------------- /xmlrpc/echo_time.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /xmlrpc/version: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1.0b2 6 | 26M 7 | beta 8 | full 9 | 10 | 11 | -------------------------------------------------------------------------------- /xmlrpc/version_base: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6.1 4 | release 5 | 6 | 7 | -------------------------------------------------------------------------------- /xmlrpc/version_comment: -------------------------------------------------------------------------------- 1 | --------------------------- 2 | pfSense Update 3 | --------------------------- 4 | 5 | Nothing to see here (yet). 6 | -------------------------------------------------------------------------------- /xmlrpc/version_embedded: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0b2 4 | 5 | 6 | -------------------------------------------------------------------------------- /xmlrpc/version_pfSense: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6.1 4 | release 5 | 6 | 7 | -------------------------------------------------------------------------------- /xmlrpc_server.inc: -------------------------------------------------------------------------------- 1 | 31 | * @author Stig Bakken 32 | * @author Martin Jansen 33 | * @author Daniel Convissor 34 | * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group 35 | * @version CVS: $Id: xmlrpc_server.inc,v 1.11 2005/09/20 18:04:11 colin Exp $ 36 | * @link http://pear.php.net/package/XML_RPC 37 | */ 38 | 39 | 40 | /** 41 | * Pull in the XML_RPC class 42 | */ 43 | require_once 'xmlrpc_client.inc'; 44 | 45 | 46 | /** 47 | * signature for system.listMethods: return = array, 48 | * parameters = a string or nothing 49 | * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] 50 | */ 51 | $GLOBALS['XML_RPC_Server_listMethods_sig'] = array( 52 | array($GLOBALS['XML_RPC_Array'], 53 | $GLOBALS['XML_RPC_String'] 54 | ), 55 | array($GLOBALS['XML_RPC_Array']) 56 | ); 57 | 58 | /** 59 | * docstring for system.listMethods 60 | * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] 61 | */ 62 | $GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' 63 | . ' methods that the XML-RPC server knows how to dispatch'; 64 | 65 | /** 66 | * signature for system.methodSignature: return = array, 67 | * parameters = string 68 | * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] 69 | */ 70 | $GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( 71 | array($GLOBALS['XML_RPC_Array'], 72 | $GLOBALS['XML_RPC_String'] 73 | ) 74 | ); 75 | 76 | /** 77 | * docstring for system.methodSignature 78 | * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] 79 | */ 80 | $GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' 81 | . ' signatures (an array of arrays) for the method name passed. If' 82 | . ' no signatures are known, returns a none-array (test for type !=' 83 | . ' array to detect missing signature)'; 84 | 85 | /** 86 | * signature for system.methodHelp: return = string, 87 | * parameters = string 88 | * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] 89 | */ 90 | $GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( 91 | array($GLOBALS['XML_RPC_String'], 92 | $GLOBALS['XML_RPC_String'] 93 | ) 94 | ); 95 | 96 | /** 97 | * docstring for methodHelp 98 | * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] 99 | */ 100 | $GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' 101 | . ' for the method passed, otherwise returns an empty string'; 102 | 103 | /** 104 | * dispatch map for the automatically declared XML-RPC methods. 105 | * @global array $GLOBALS['XML_RPC_Server_dmap'] 106 | */ 107 | $GLOBALS['XML_RPC_Server_dmap'] = array( 108 | 'system.listMethods' => array( 109 | 'function' => 'XML_RPC_Server_listMethods', 110 | 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], 111 | 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] 112 | ), 113 | 'system.methodHelp' => array( 114 | 'function' => 'XML_RPC_Server_methodHelp', 115 | 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], 116 | 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] 117 | ), 118 | 'system.methodSignature' => array( 119 | 'function' => 'XML_RPC_Server_methodSignature', 120 | 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], 121 | 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] 122 | ) 123 | ); 124 | 125 | /** 126 | * @global string $GLOBALS['XML_RPC_Server_debuginfo'] 127 | */ 128 | $GLOBALS['XML_RPC_Server_debuginfo'] = ''; 129 | 130 | 131 | /** 132 | * Lists all the methods that the XML-RPC server knows how to dispatch 133 | * 134 | * @return object a new XML_RPC_Response object 135 | */ 136 | function XML_RPC_Server_listMethods($server, $m) 137 | { 138 | global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; 139 | 140 | $v = new XML_RPC_Value(); 141 | $outAr = array(); 142 | foreach ($server->dmap as $key => $val) { 143 | $outAr[] = new XML_RPC_Value($key, 'string'); 144 | } 145 | foreach ($XML_RPC_Server_dmap as $key => $val) { 146 | $outAr[] = new XML_RPC_Value($key, 'string'); 147 | } 148 | $v->addArray($outAr); 149 | return new XML_RPC_Response($v); 150 | } 151 | 152 | /** 153 | * Returns an array of known signatures (an array of arrays) 154 | * for the given method 155 | * 156 | * If no signatures are known, returns a none-array 157 | * (test for type != array to detect missing signature) 158 | * 159 | * @return object a new XML_RPC_Response object 160 | */ 161 | function XML_RPC_Server_methodSignature($server, $m) 162 | { 163 | global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; 164 | 165 | $methName = $m->getParam(0); 166 | $methName = $methName->scalarval(); 167 | if (strpos($methName, 'system.') === 0) { 168 | $dmap = $XML_RPC_Server_dmap; 169 | $sysCall = 1; 170 | } else { 171 | $dmap = $server->dmap; 172 | $sysCall = 0; 173 | } 174 | // print "\n"; 175 | if (isset($dmap[$methName])) { 176 | if ($dmap[$methName]['signature']) { 177 | $sigs = array(); 178 | $thesigs = $dmap[$methName]['signature']; 179 | for ($i = 0; $i < sizeof($thesigs); $i++) { 180 | $cursig = array(); 181 | $inSig = $thesigs[$i]; 182 | for ($j = 0; $j < sizeof($inSig); $j++) { 183 | $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); 184 | } 185 | $sigs[] = new XML_RPC_Value($cursig, 'array'); 186 | } 187 | $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); 188 | } else { 189 | $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); 190 | } 191 | } else { 192 | $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], 193 | $XML_RPC_str['introspect_unknown']); 194 | } 195 | return $r; 196 | } 197 | 198 | /** 199 | * Returns help text if defined for the method passed, otherwise returns 200 | * an empty string 201 | * 202 | * @return object a new XML_RPC_Response object 203 | */ 204 | function XML_RPC_Server_methodHelp($server, $m) 205 | { 206 | global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; 207 | 208 | $methName = $m->getParam(0); 209 | $methName = $methName->scalarval(); 210 | if (strpos($methName, 'system.') === 0) { 211 | $dmap = $XML_RPC_Server_dmap; 212 | $sysCall = 1; 213 | } else { 214 | $dmap = $server->dmap; 215 | $sysCall = 0; 216 | } 217 | 218 | if (isset($dmap[$methName])) { 219 | if ($dmap[$methName]['docstring']) { 220 | $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), 221 | 'string'); 222 | } else { 223 | $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); 224 | } 225 | } else { 226 | $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], 227 | $XML_RPC_str['introspect_unknown']); 228 | } 229 | return $r; 230 | } 231 | 232 | /** 233 | * @return void 234 | */ 235 | function XML_RPC_Server_debugmsg($m) 236 | { 237 | global $XML_RPC_Server_debuginfo; 238 | $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; 239 | } 240 | 241 | 242 | /** 243 | * A server for receiving and replying to XML RPC requests 244 | * 245 | * 246 | * $server = new XML_RPC_Server( 247 | * array( 248 | * 'isan8' => 249 | * array( 250 | * 'function' => 'is_8', 251 | * 'signature' => 252 | * array( 253 | * array('boolean', 'int'), 254 | * array('boolean', 'int', 'boolean'), 255 | * array('boolean', 'string'), 256 | * array('boolean', 'string', 'boolean'), 257 | * ), 258 | * 'docstring' => 'Is the value an 8?' 259 | * ), 260 | * ), 261 | * 1, 262 | * 0 263 | * ); 264 | * 265 | * 266 | * @category Web Services 267 | * @package XML_RPC 268 | * @author Edd Dumbill 269 | * @author Stig Bakken 270 | * @author Martin Jansen 271 | * @author Daniel Convissor 272 | * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group 273 | * @version Release: 1.4.2 274 | * @link http://pear.php.net/package/XML_RPC 275 | */ 276 | class XML_RPC_Server 277 | { 278 | /** 279 | * The dispatch map, listing the methods this server provides. 280 | * @var array 281 | */ 282 | var $dmap = array(); 283 | 284 | /** 285 | * The present response's encoding 286 | * @var string 287 | * @see XML_RPC_Message::getEncoding() 288 | */ 289 | var $encoding = ''; 290 | 291 | /** 292 | * Debug mode (0 = off, 1 = on) 293 | * @var integer 294 | */ 295 | var $debug = 0; 296 | 297 | /** 298 | * The response's HTTP headers 299 | * @var string 300 | */ 301 | var $server_headers = ''; 302 | 303 | /** 304 | * The response's XML payload 305 | * @var string 306 | */ 307 | var $server_payload = ''; 308 | 309 | 310 | /** 311 | * Constructor for the XML_RPC_Server class 312 | * 313 | * @param array $dispMap the dispatch map. An associative array 314 | * explaining each function. The keys of the main 315 | * array are the procedure names used by the 316 | * clients. The value is another associative array 317 | * that contains up to three elements: 318 | * + The 'function' element's value is the name 319 | * of the function or method that gets called. 320 | * To define a class' method: 'class::method'. 321 | * + The 'signature' element (optional) is an 322 | * array describing the return values and 323 | * parameters 324 | * + The 'docstring' element (optional) is a 325 | * string describing what the method does 326 | * @param int $serviceNow should the HTTP response be sent now? 327 | * (1 = yes, 0 = no) 328 | * @param int $debug should debug output be displayed? 329 | * (1 = yes, 0 = no) 330 | * 331 | * @return void 332 | */ 333 | function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) 334 | { 335 | global $HTTP_RAW_POST_DATA; 336 | 337 | if ($debug) { 338 | $this->debug = 1; 339 | } else { 340 | $this->debug = 0; 341 | } 342 | 343 | $this->dmap = $dispMap; 344 | 345 | if ($serviceNow) { 346 | $this->service(); 347 | } else { 348 | $this->createServerPayload(); 349 | $this->createServerHeaders(); 350 | } 351 | } 352 | 353 | /** 354 | * @return string the debug information if debug debug mode is on 355 | */ 356 | function serializeDebug() 357 | { 358 | global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; 359 | 360 | if ($this->debug) { 361 | XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" 362 | . $HTTP_RAW_POST_DATA 363 | . "\n" . '^^^ END POST DATA ^^^'); 364 | } 365 | 366 | if ($XML_RPC_Server_debuginfo != '') { 367 | return "\n"; 370 | } else { 371 | return ''; 372 | } 373 | } 374 | 375 | /** 376 | * Sends the response 377 | * 378 | * The encoding and content-type are determined by 379 | * XML_RPC_Message::getEncoding() 380 | * 381 | * @return void 382 | * 383 | * @uses XML_RPC_Server::createServerPayload(), 384 | * XML_RPC_Server::createServerHeaders() 385 | */ 386 | function service() 387 | { 388 | if (!$this->server_payload) { 389 | $this->createServerPayload(); 390 | } 391 | if (!$this->server_headers) { 392 | $this->createServerHeaders(); 393 | } 394 | //header($this->server_headers); 395 | //print $this->server_headers; 396 | print $this->server_payload; 397 | } 398 | 399 | /** 400 | * Generates the payload and puts it in the $server_payload property 401 | * 402 | * @return void 403 | * 404 | * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, 405 | * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() 406 | */ 407 | function createServerPayload() 408 | { 409 | $r = $this->parseRequest(); 410 | $this->server_payload = 'encoding . '"?>' . "\n" 412 | . $this->serializeDebug() 413 | . $r->serialize(); 414 | } 415 | 416 | /** 417 | * Determines the HTTP headers and puts them in the $server_headers 418 | * property 419 | * 420 | * @return boolean TRUE if okay, FALSE if $server_payload isn't set. 421 | * 422 | * @uses XML_RPC_Server::createServerPayload(), 423 | * XML_RPC_Server::$server_headers 424 | */ 425 | function createServerHeaders() 426 | { 427 | if (!$this->server_payload) { 428 | return false; 429 | } 430 | $this->server_headers = 'Content-Length: ' 431 | . strlen($this->server_payload) . "\r\n" 432 | . 'Content-Type: text/xml;' 433 | . ' charset=' . $this->encoding; 434 | return true; 435 | } 436 | 437 | /** 438 | * @return array 439 | */ 440 | function verifySignature($in, $sig) 441 | { 442 | for ($i = 0; $i < sizeof($sig); $i++) { 443 | // check each possible signature in turn 444 | $cursig = $sig[$i]; 445 | if (sizeof($cursig) == $in->getNumParams() + 1) { 446 | $itsOK = 1; 447 | for ($n = 0; $n < $in->getNumParams(); $n++) { 448 | $p = $in->getParam($n); 449 | // print "\n"; 450 | if ($p->kindOf() == 'scalar') { 451 | $pt = $p->scalartyp(); 452 | } else { 453 | $pt = $p->kindOf(); 454 | } 455 | // $n+1 as first type of sig is return type 456 | if ($pt != $cursig[$n+1]) { 457 | $itsOK = 0; 458 | $pno = $n+1; 459 | $wanted = $cursig[$n+1]; 460 | $got = $pt; 461 | break; 462 | } 463 | } 464 | if ($itsOK) { 465 | return array(1); 466 | } 467 | } 468 | } 469 | if (isset($wanted)) { 470 | return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); 471 | } else { 472 | $allowed = array(); 473 | foreach ($sig as $val) { 474 | end($val); 475 | $allowed[] = key($val); 476 | } 477 | $allowed = array_unique($allowed); 478 | $last = count($allowed) - 1; 479 | if ($last > 0) { 480 | $allowed[$last] = 'or ' . $allowed[$last]; 481 | } 482 | return array(0, 483 | 'Signature permits ' . implode(', ', $allowed) 484 | . ' parameters but the request had ' 485 | . $in->getNumParams()); 486 | } 487 | } 488 | 489 | /** 490 | * @return object a new XML_RPC_Response object 491 | * 492 | * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding 493 | */ 494 | function parseRequest($data = '') 495 | { 496 | global $XML_RPC_xh, $HTTP_RAW_POST_DATA, 497 | $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, 498 | $XML_RPC_defencoding, $XML_RPC_Server_dmap; 499 | 500 | if ($data == '') { 501 | $data = $HTTP_RAW_POST_DATA; 502 | } 503 | 504 | $this->encoding = XML_RPC_Message::getEncoding($data); 505 | $parser_resource = xml_parser_create($this->encoding); 506 | $parser = (int) $parser_resource; 507 | 508 | $XML_RPC_xh[$parser] = array(); 509 | $XML_RPC_xh[$parser]['cm'] = 0; 510 | $XML_RPC_xh[$parser]['isf'] = 0; 511 | $XML_RPC_xh[$parser]['params'] = array(); 512 | $XML_RPC_xh[$parser]['method'] = ''; 513 | $XML_RPC_xh[$parser]['stack'] = array(); 514 | $XML_RPC_xh[$parser]['valuestack'] = array(); 515 | 516 | $plist = ''; 517 | 518 | // decompose incoming XML into request structure 519 | 520 | xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); 521 | xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); 522 | xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); 523 | if (!xml_parse($parser_resource, $data, 1)) { 524 | // return XML error as a faultCode 525 | $r = new XML_RPC_Response(0, 526 | $XML_RPC_errxml+xml_get_error_code($parser_resource), 527 | sprintf('XML error: %s at line %d', 528 | xml_error_string(xml_get_error_code($parser_resource)), 529 | xml_get_current_line_number($parser_resource))); 530 | xml_parser_free($parser_resource); 531 | } elseif ($XML_RPC_xh[$parser]['isf']>1) { 532 | $r = new XML_RPC_Response(0, 533 | $XML_RPC_err['invalid_request'], 534 | $XML_RPC_str['invalid_request'] 535 | . ': ' 536 | . $XML_RPC_xh[$parser]['isf_reason']); 537 | xml_parser_free($parser_resource); 538 | } else { 539 | xml_parser_free($parser_resource); 540 | $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); 541 | // now add parameters in 542 | for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { 543 | // print '\n"; 544 | $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n"; 545 | $m->addParam($XML_RPC_xh[$parser]['params'][$i]); 546 | } 547 | 548 | if ($this->debug) { 549 | XML_RPC_Server_debugmsg($plist); 550 | } 551 | 552 | // now to deal with the method 553 | $methName = $XML_RPC_xh[$parser]['method']; 554 | if (strpos($methName, 'system.') === 0) { 555 | $dmap = $XML_RPC_Server_dmap; 556 | $sysCall = 1; 557 | } else { 558 | $dmap = $this->dmap; 559 | $sysCall = 0; 560 | } 561 | 562 | if (isset($dmap[$methName]['function']) 563 | && is_string($dmap[$methName]['function']) 564 | && strpos($dmap[$methName]['function'], '::') !== false) 565 | { 566 | $dmap[$methName]['function'] = 567 | explode('::', $dmap[$methName]['function']); 568 | } 569 | 570 | if (isset($dmap[$methName]['function']) 571 | && is_callable($dmap[$methName]['function'])) 572 | { 573 | // dispatch if exists 574 | if (isset($dmap[$methName]['signature'])) { 575 | $sr = $this->verifySignature($m, 576 | $dmap[$methName]['signature'] ); 577 | } 578 | if (!isset($dmap[$methName]['signature']) || $sr[0]) { 579 | // if no signature or correct signature 580 | if ($sysCall) { 581 | $r = call_user_func($dmap[$methName]['function'], $this, $m); 582 | } else { 583 | $r = call_user_func($dmap[$methName]['function'], $m); 584 | } 585 | if (!is_a($r, 'XML_RPC_Response')) { 586 | $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], 587 | $XML_RPC_str['not_response_object']); 588 | } 589 | } else { 590 | $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], 591 | $XML_RPC_str['incorrect_params'] 592 | . ': ' . $sr[1]); 593 | } 594 | } else { 595 | // else prepare error response 596 | $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], 597 | $XML_RPC_str['unknown_method']); 598 | } 599 | } 600 | return $r; 601 | } 602 | 603 | /** 604 | * Echos back the input packet as a string value 605 | * 606 | * @return void 607 | * 608 | * Useful for debugging. 609 | */ 610 | function echoInput() 611 | { 612 | global $HTTP_RAW_POST_DATA; 613 | 614 | $r = new XML_RPC_Response(0); 615 | $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); 616 | print $r->serialize(); 617 | } 618 | } 619 | 620 | /* 621 | * Local variables: 622 | * tab-width: 4 623 | * c-basic-offset: 4 624 | * c-hanging-comment-ender-p: nil 625 | * End: 626 | */ 627 | 628 | ?> 629 | -------------------------------------------------------------------------------- /xmlrpc_tester.php: -------------------------------------------------------------------------------- 1 | "pfSense", 21 | "firmware" => array("version" => "0.62.5", "branch" => "stable"), 22 | "kernel" => array("version" => "5.4"), 23 | "base" => array("version" => "5.4") 24 | ); 25 | print_r($params); 26 | $msg = new XML_RPC_Message('pfsense.get_firmware_version', array(php_value_to_xmlrpc($params))); 27 | print "Formed message.\n"; 28 | $cli = new XML_RPC_Client($versioncheck_path, $versioncheck_base_url); 29 | print "Formed client.\n"; 30 | $cli->setDebug(1); 31 | $resp = $cli->send($msg); 32 | print "Message sent.\n"; 33 | $raw_versions = $resp->value(); 34 | return xmlrpc_value_to_php($raw_versions); 35 | } 36 | 37 | $versions = get_firmware_version(); 38 | print_r($versions); 39 | ?> 40 | 41 | 42 | --------------------------------------------------------------------------------