| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * OO AJAX Implementation for PHP 4 * 5 * SVN Rev: $Id: AJAX.php,v 1.1.2.1 2008/10/03 07:09:50 nicolasconnault Exp $ 6 * 7 * @category HTML 8 * @package AJAX 9 * @author Joshua Eichorn <josh@bluga.net> 10 * @author Arpad Ray <arpad@php.net> 11 * @author David Coallier <davidc@php.net> 12 * @author Elizabeth Smith <auroraeosrose@gmail.com> 13 * @copyright 2005-2008 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith 14 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 15 * @version Release: 0.5.6 16 * @link http://pear.php.net/package/HTML_AJAX 17 */ 18 19 /** 20 * This is a quick hack, loading serializers as needed doesn't work in php5 21 */ 22 require_once "HTML/AJAX/Serializer/JSON.php"; 23 require_once "HTML/AJAX/Serializer/Null.php"; 24 require_once "HTML/AJAX/Serializer/Error.php"; 25 require_once "HTML/AJAX/Serializer/XML.php"; 26 require_once "HTML/AJAX/Serializer/PHP.php"; 27 require_once 'HTML/AJAX/Debug.php'; 28 29 /** 30 * OO AJAX Implementation for PHP 31 * 32 * @category HTML 33 * @package AJAX 34 * @author Joshua Eichorn <josh@bluga.net> 35 * @author Arpad Ray <arpad@php.net> 36 * @author David Coallier <davidc@php.net> 37 * @author Elizabeth Smith <auroraeosrose@gmail.com> 38 * @copyright 2005-2008 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith 39 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 40 * @version Release: 0.5.6 41 * @link http://pear.php.net/package/HTML_AJAX 42 */ 43 class HTML_AJAX 44 { 45 /** 46 * An array holding the instances were exporting 47 * 48 * key is the exported name 49 * 50 * row format is 51 * <code> 52 * array('className'=>'','exportedName'=>'','instance'=>'','exportedMethods=>'') 53 * </code> 54 * 55 * @var object 56 * @access private 57 */ 58 var $_exportedInstances = array(); 59 60 /** 61 * Set the server url in the generated stubs to this value 62 * If set to false, serverUrl will not be set 63 * @var false|string 64 */ 65 var $serverUrl = false; 66 67 /** 68 * What encoding your going to use for serializing data 69 * from php being sent to javascript. 70 * 71 * @var string JSON|PHP|Null 72 */ 73 var $serializer = 'JSON'; 74 75 /** 76 * What encoding your going to use for unserializing data sent from javascript 77 * @var string JSON|PHP|Null 78 */ 79 var $unserializer = 'JSON'; 80 81 /** 82 * Option to use loose typing for JSON encoding 83 * @var bool 84 * @access public 85 */ 86 var $jsonLooseType = true; 87 88 /** 89 * Content-type map 90 * 91 * Used in to automatically choose serializers as needed 92 */ 93 var $contentTypeMap = array( 94 'JSON' => 'application/json', 95 'XML' => 'application/xml', 96 'Null' => 'text/plain', 97 'Error' => 'application/error', 98 'PHP' => 'application/php-serialized', 99 'Urlencoded' => 'application/x-www-form-urlencoded' 100 ); 101 102 /** 103 * This is the debug variable that we will be passing the 104 * HTML_AJAX_Debug instance to. 105 * 106 * @param object HTML_AJAX_Debug 107 */ 108 var $debug; 109 110 /** 111 * This is to tell if debug is enabled or not. If so, then 112 * debug is called, instantiated then saves the file and such. 113 */ 114 var $debugEnabled = false; 115 116 /** 117 * This puts the error into a session variable is set to true. 118 * set to false by default. 119 * 120 * @access public 121 */ 122 var $debugSession = false; 123 124 /** 125 * Boolean telling if the Content-Length header should be sent. 126 * 127 * If your using a gzip handler on an output buffer, or run into 128 * any compatability problems, try disabling this. 129 * 130 * @access public 131 * @var boolean 132 */ 133 var $sendContentLength = true; 134 135 /** 136 * Make Generated code compatible with php4 by lowercasing all 137 * class/method names before exporting to JavaScript. 138 * 139 * If you have code that works on php4 but not on php5 then setting 140 * this flag can fix the problem. The recommended solution is too 141 * specify the class and method names when registering the class 142 * letting you have function case in php4 as well 143 * 144 * @access public 145 * @var boolean 146 */ 147 var $php4CompatCase = false; 148 149 /** 150 * Automatically pack all generated JavaScript making it smaller 151 * 152 * If your using output compression this might not make sense 153 */ 154 var $packJavaScript = false; 155 156 /** 157 * Holds current payload info 158 * 159 * @access private 160 * @var string 161 */ 162 var $_payload; 163 164 /** 165 * Holds iframe id IF this is an iframe xmlhttprequest 166 * 167 * @access private 168 * @var string 169 */ 170 var $_iframe; 171 172 /** 173 * Holds the list of classes permitted to be unserialized 174 * 175 * @access private 176 * @var array 177 */ 178 var $_allowedClasses = array(); 179 180 /** 181 * Holds serializer instances 182 */ 183 var $_serializers = array(); 184 185 /** 186 * PHP callbacks we're exporting 187 */ 188 var $_validCallbacks = array(); 189 190 /** 191 * Interceptor instance 192 */ 193 var $_interceptor = false; 194 195 /** 196 * Set a class to handle requests 197 * 198 * @param object &$instance An instance to export 199 * @param mixed $exportedName Name used for the javascript class, 200 * if false the name of the php class is used 201 * @param mixed $exportedMethods If false all functions without a _ prefix 202 * are exported, if an array only the methods 203 * listed in the array are exported 204 * 205 * @return void 206 */ 207 function registerClass(&$instance, $exportedName = false, 208 $exportedMethods = false) 209 { 210 $className = strtolower(get_class($instance)); 211 212 if ($exportedName === false) { 213 $exportedName = get_class($instance); 214 if ($this->php4CompatCase) { 215 $exportedName = strtolower($exportedName); 216 } 217 } 218 219 if ($exportedMethods === false) { 220 $exportedMethods = $this->_getMethodsToExport($className); 221 } 222 223 224 $index = strtolower($exportedName); 225 $this->_exportedInstances[$index] = array(); 226 $this->_exportedInstances[$index]['className'] = $className; 227 $this->_exportedInstances[$index]['exportedName'] = $exportedName; 228 $this->_exportedInstances[$index]['instance'] =& $instance; 229 $this->_exportedInstances[$index]['exportedMethods'] = $exportedMethods; 230 } 231 232 /** 233 * Get a list of methods in a class to export 234 * 235 * This function uses get_class_methods to get a list of callable methods, 236 * so if you're on PHP5 extending this class with a class you want to export 237 * should export its protected methods, while normally only its public methods 238 * would be exported. All methods starting with _ are removed from the export list. 239 * This covers PHP4 style private by naming as well as magic methods in either PHP4 or PHP5 240 * 241 * @param string $className Name of the class 242 * 243 * @return array all methods of the class that are public 244 * @access private 245 */ 246 function _getMethodsToExport($className) 247 { 248 $funcs = get_class_methods($className); 249 250 foreach ($funcs as $key => $func) { 251 if (strtolower($func) === $className || substr($func, 0, 1) === '_') { 252 unset($funcs[$key]); 253 } else if ($this->php4CompatCase) { 254 $funcs[$key] = strtolower($func); 255 } 256 } 257 return $funcs; 258 } 259 260 /** 261 * Generate the client Javascript code 262 * 263 * @return string generated javascript client code 264 */ 265 function generateJavaScriptClient() 266 { 267 $client = ''; 268 269 $names = array_keys($this->_exportedInstances); 270 foreach ($names as $name) { 271 $client .= $this->generateClassStub($name); 272 } 273 return $client; 274 } 275 276 /** 277 * Return the stub for a class 278 * 279 * @param string $name name of the class to generated the stub for, 280 * note that this is the exported name not the php class name 281 * 282 * @return string javascript proxy stub code for a single class 283 */ 284 function generateClassStub($name) 285 { 286 if (!isset($this->_exportedInstances[$name])) { 287 return ''; 288 } 289 290 $client = "// Client stub for the {$this->_exportedInstances[$name]['exportedName']} PHP Class\n"; 291 $client .= "function {$this->_exportedInstances[$name]['exportedName']}(callback) {\n"; 292 $client .= "\tmode = 'sync';\n"; 293 $client .= "\tif (callback) { mode = 'async'; }\n"; 294 $client .= "\tthis.className = '{$this->_exportedInstances[$name]['exportedName']}';\n"; 295 if ($this->serverUrl) { 296 $client .= "\tthis.dispatcher = new HTML_AJAX_Dispatcher(this.className,mode,callback,'{$this->serverUrl}','{$this->unserializer}');\n}\n"; 297 } else { 298 $client .= "\tthis.dispatcher = new HTML_AJAX_Dispatcher(this.className,mode,callback,false,'{$this->unserializer}');\n}\n"; 299 } 300 $client .= "{$this->_exportedInstances[$name]['exportedName']}.prototype = {\n"; 301 $client .= "\tSync: function() { this.dispatcher.Sync(); }, \n"; 302 $client .= "\tAsync: function(callback) { this.dispatcher.Async(callback); },\n"; 303 foreach ($this->_exportedInstances[$name]['exportedMethods'] as $method) { 304 $client .= $this->_generateMethodStub($method); 305 } 306 $client = substr($client, 0, (strlen($client)-2))."\n"; 307 $client .= "}\n\n"; 308 309 if ($this->packJavaScript) { 310 $client = $this->packJavaScript($client); 311 } 312 return $client; 313 } 314 315 /** 316 * Returns a methods stub 317 * 318 * @param string $method the method name 319 * 320 * @return string the js code 321 * @access private 322 */ 323 function _generateMethodStub($method) 324 { 325 $stub = "\t{$method}: function() { return ". 326 "this.dispatcher.doCall('{$method}',arguments); },\n"; 327 return $stub; 328 } 329 330 /** 331 * Populates the current payload 332 * 333 * @return string the js code 334 * @access private 335 */ 336 function populatePayload() 337 { 338 if (isset($_REQUEST['Iframe_XHR'])) { 339 $this->_iframe = $_REQUEST['Iframe_XHR_id']; 340 if (isset($_REQUEST['Iframe_XHR_headers']) && 341 is_array($_REQUEST['Iframe_XHR_headers'])) { 342 foreach ($_REQUEST['Iframe_XHR_headers'] as $header) { 343 344 $array = explode(':', $header); 345 $array[0] = strip_tags(strtoupper(str_replace('-', '_', $array[0]))); 346 //only content-length and content-type can go in without an 347 //http_ prefix - security 348 if (strpos($array[0], 'HTTP_') !== 0 349 && strcmp('CONTENT_TYPE', $array[0]) 350 && strcmp('CONTENT_LENGTH', $array[0])) { 351 $array[0] = 'HTTP_' . $array[0]; 352 } 353 $_SERVER[$array[0]] = strip_tags($array[1]); 354 } 355 } 356 $this->_payload = (isset($_REQUEST['Iframe_XHR_data']) 357 ? $_REQUEST['Iframe_XHR_data'] : ''); 358 359 if (isset($_REQUEST['Iframe_XHR_method'])) { 360 $_GET['m'] = $_REQUEST['Iframe_XHR_method']; 361 } 362 if (isset($_REQUEST['Iframe_XHR_class'])) { 363 $_GET['c'] = $_REQUEST['Iframe_XHR_class']; 364 } 365 } 366 } 367 368 /** 369 * Handle a ajax request if needed 370 * 371 * The current check is if GET variables c (class) and m (method) are set, 372 * more options may be available in the future 373 * 374 * @return boolean true if an ajax call was handled, false otherwise 375 */ 376 function handleRequest() 377 { 378 set_error_handler(array(&$this,'_errorHandler')); 379 if (function_exists('set_exception_handler')) { 380 set_exception_handler(array(&$this,'_exceptionHandler')); 381 } 382 if (isset($_GET['px'])) { 383 if ($this->_iframeGrabProxy()) { 384 restore_error_handler(); 385 if (function_exists('restore_exception_handler')) { 386 restore_exception_handler(); 387 } 388 return true; 389 } 390 } 391 392 $class = strtolower($this->_getVar('c')); 393 $method = $this->_getVar('m'); 394 $phpCallback = $this->_getVar('cb'); 395 396 397 if (!empty($class) && !empty($method)) { 398 if (!isset($this->_exportedInstances[$class])) { 399 // handle error 400 trigger_error('Unknown class: '. $class); 401 } 402 if (!in_array(($this->php4CompatCase ? strtolower($method) : $method), 403 $this->_exportedInstances[$class]['exportedMethods'])) { 404 // handle error 405 trigger_error('Unknown method: ' . $method); 406 } 407 } else if (!empty($phpCallback)) { 408 if (strpos($phpCallback, '.') !== false) { 409 $phpCallback = explode('.', $phpCallback); 410 } 411 if (!$this->_validatePhpCallback($phpCallback)) { 412 restore_error_handler(); 413 if (function_exists('restore_exception_handler')) { 414 restore_exception_handler(); 415 } 416 return false; 417 } 418 } else { 419 restore_error_handler(); 420 if (function_exists('restore_exception_handler')) { 421 restore_exception_handler(); 422 } 423 return false; 424 } 425 426 // auto-detect serializer to use from content-type 427 $type = $this->unserializer; 428 $key = array_search($this->_getClientPayloadContentType(), 429 $this->contentTypeMap); 430 if ($key) { 431 $type = $key; 432 } 433 $unserializer = $this->_getSerializer($type); 434 435 $args = $unserializer->unserialize($this->_getClientPayload(), $this->_allowedClasses); 436 if (!is_array($args)) { 437 $args = array($args); 438 } 439 440 if ($this->_interceptor !== false) { 441 $args = $this->_processInterceptor($class, $method, $phpCallback, $args); 442 } 443 444 if (empty($phpCallback)) { 445 $ret = call_user_func_array(array(&$this->_exportedInstances[$class]['instance'], $method), $args); 446 } else { 447 $ret = call_user_func_array($phpCallback, $args); 448 } 449 450 restore_error_handler(); 451 $this->_sendResponse($ret); 452 return true; 453 } 454 455 /** 456 * Determines the content type of the client payload 457 * 458 * @return string 459 * a MIME content type 460 */ 461 function _getClientPayloadContentType() 462 { 463 //OPERA IS STUPID FIX 464 if (isset($_SERVER['HTTP_X_CONTENT_TYPE'])) { 465 $type = $this->_getServer('HTTP_X_CONTENT_TYPE'); 466 $pos = strpos($type, ';'); 467 468 return strtolower($pos ? substr($type, 0, $pos) : $type); 469 } else if (isset($_SERVER['CONTENT_TYPE'])) { 470 $type = $this->_getServer('CONTENT_TYPE'); 471 $pos = strpos($type, ';'); 472 473 return strtolower($pos ? substr($type, 0, $pos) : $type); 474 } 475 return 'text/plain'; 476 } 477 478 /** 479 * Send a reponse adding needed headers and serializing content 480 * 481 * Note: this method echo's output as well as setting headers to prevent caching 482 * Iframe Detection: if this has been detected as an iframe response, it has to 483 * be wrapped in different code and headers changed (quite a mess) 484 * 485 * @param mixed $response content to serialize and send 486 * 487 * @access private 488 * @return void 489 */ 490 function _sendResponse($response) 491 { 492 if (is_object($response) && is_a($response, 'HTML_AJAX_Response')) { 493 $output = $response->getPayload(); 494 $content = $response->getContentType(); 495 496 } elseif (is_a($response, 'PEAR_Error')) { 497 $serializer = $this->_getSerializer('Error'); 498 $output = $serializer->serialize(array( 499 'message' => $response->getMessage(), 500 'userinfo' => $response->getUserInfo(), 501 'code' => $response->getCode(), 502 'mode' => $response->getMode() 503 )); 504 $content = $this->contentTypeMap['Error']; 505 506 } else { 507 $serializer = $this->_getSerializer($this->serializer); 508 $output = $serializer->serialize($response); 509 510 $serializerType = $this->serializer; 511 // let a serializer change its output type 512 if (isset($serializer->serializerNewType)) { 513 $serializerType = $serializer->serializerNewType; 514 } 515 516 if (isset($this->contentTypeMap[$serializerType])) { 517 $content = $this->contentTypeMap[$serializerType]; 518 } 519 } 520 // headers to force things not to be cached: 521 $headers = array(); 522 //OPERA IS STUPID FIX 523 if (isset($_SERVER['HTTP_X_CONTENT_TYPE'])) { 524 $headers['X-Content-Type'] = $content; 525 $content = 'text/plain'; 526 } 527 528 if ($this->_sendContentLength()) { 529 $headers['Content-Length'] = strlen($output); 530 } 531 532 $headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; 533 $headers['Last-Modified'] = gmdate("D, d M Y H:i:s").'GMT'; 534 $headers['Cache-Control'] = 'no-cache, must-revalidate'; 535 $headers['Pragma'] = 'no-cache'; 536 $headers['Content-Type'] = $content.'; charset=utf-8'; 537 538 //intercept to wrap iframe return data 539 if ($this->_iframe) { 540 $output = $this->_iframeWrapper($this->_iframe, 541 $output, $headers); 542 $headers['Content-Type'] = 'text/html; charset=utf-8'; 543 } 544 545 $this->_sendHeaders($headers); 546 echo $output; 547 } 548 549 /** 550 * Decide if we should send a Content-length header 551 * 552 * @return bool true if it's ok to send the header, false otherwise 553 * @access private 554 */ 555 function _sendContentLength() 556 { 557 if (!$this->sendContentLength) { 558 return false; 559 } 560 $ini_tests = array( "output_handler", 561 "zlib.output_compression", 562 "zlib.output_handler"); 563 foreach ($ini_tests as $test) { 564 if (ini_get($test)) { 565 return false; 566 } 567 } 568 return (ob_get_level() <= 0); 569 } 570 571 /** 572 * Actually send a list of headers 573 * 574 * @param array $array list of headers to send 575 * 576 * @access private 577 * @return void 578 */ 579 function _sendHeaders($array) 580 { 581 foreach ($array as $header => $value) { 582 header($header . ': ' . $value); 583 } 584 } 585 586 /** 587 * Get an instance of a serializer class 588 * 589 * @param string $type Last part of the class name 590 * 591 * @access private 592 * @return HTML_AJAX_Serializer 593 */ 594 function _getSerializer($type) 595 { 596 if (isset($this->_serializers[$type])) { 597 return $this->_serializers[$type]; 598 } 599 600 $class = 'HTML_AJAX_Serializer_'.$type; 601 602 if ( (version_compare(phpversion(), 5, '>') && !class_exists($class, false)) 603 || (version_compare(phpversion(), 5, '<') && !class_exists($class)) ) { 604 // include the class only if it isn't defined 605 include_once "HTML/AJAX/Serializer/{$type}.php"; 606 } 607 608 //handle JSON loose typing option for associative arrays 609 if ($type == 'JSON') { 610 $this->_serializers[$type] = new $class($this->jsonLooseType); 611 } else { 612 $this->_serializers[$type] = new $class(); 613 } 614 return $this->_serializers[$type]; 615 } 616 617 /** 618 * Get payload in its submitted form, currently only supports raw post 619 * 620 * @access private 621 * @return string raw post data 622 */ 623 function _getClientPayload() 624 { 625 if (empty($this->_payload)) { 626 if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) { 627 $this->_payload = $GLOBALS['HTTP_RAW_POST_DATA']; 628 } else if (function_exists('file_get_contents')) { 629 // both file_get_contents() and php://input require PHP >= 4.3.0 630 $this->_payload = file_get_contents('php://input'); 631 } else { 632 $this->_payload = ''; 633 } 634 } 635 return $this->_payload; 636 } 637 638 /** 639 * stub for getting get vars - applies strip_tags 640 * 641 * @param string $var variable to get 642 * 643 * @access private 644 * @return string filtered _GET value 645 */ 646 function _getVar($var) 647 { 648 if (!isset($_GET[$var])) { 649 return null; 650 } else { 651 return strip_tags($_GET[$var]); 652 } 653 } 654 655 /** 656 * stub for getting server vars - applies strip_tags 657 * 658 * @param string $var variable to get 659 * 660 * @access private 661 * @return string filtered _GET value 662 */ 663 function _getServer($var) 664 { 665 if (!isset($_SERVER[$var])) { 666 return null; 667 } else { 668 return strip_tags($_SERVER[$var]); 669 } 670 } 671 672 /** 673 * Exception handler, passes them to _errorHandler to do the actual work 674 * 675 * @param Exception $ex Exception to be handled 676 * 677 * @access private 678 * @return void 679 */ 680 function _exceptionHandler($ex) 681 { 682 $this->_errorHandler($ex->getCode(), $ex->getMessage(), $ex->getFile(), $ex->getLine()); 683 } 684 685 686 /** 687 * Error handler that sends it errors to the client side 688 * 689 * @param int $errno Error number 690 * @param string $errstr Error string 691 * @param string $errfile Error file 692 * @param string $errline Error line 693 * 694 * @access private 695 * @return void 696 */ 697 function _errorHandler($errno, $errstr, $errfile, $errline) 698 { 699 if ($errno & error_reporting()) { 700 $e = new stdClass(); 701 $e->errNo = $errno; 702 $e->errStr = $errstr; 703 $e->errFile = $errfile; 704 $e->errLine = $errline; 705 706 707 $this->serializer = 'Error'; 708 $this->_sendResponse($e); 709 if ($this->debugEnabled) { 710 $this->debug = new HTML_AJAX_Debug($errstr, $errline, $errno, $errfile); 711 if ($this->debugSession) { 712 $this->debug->sessionError(); 713 } 714 $this->debug->_saveError(); 715 } 716 die(); 717 } 718 } 719 720 /** 721 * Creates html to wrap serialized info for iframe xmlhttprequest fakeout 722 * 723 * @param string $id iframe instance id 724 * @param string $data data to pass 725 * @param string $headers headers to pass 726 * 727 * @access private 728 * @return string html page with iframe passing code 729 */ 730 function _iframeWrapper($id, $data, $headers = array()) 731 { 732 $string = '<html><script type="text/javascript">'."\n". 733 'var Iframe_XHR_headers = new Object();'; 734 735 foreach ($headers as $label => $value) { 736 $string .= 'Iframe_XHR_headers["'.preg_replace("/\r?\n/", "\\n", 737 addslashes($label)).'"] = "'.preg_replace("/\r?\n/", "\\n", 738 addslashes($value))."\";\n"; 739 } 740 $string .= 'var Iframe_XHR_data = "' . preg_replace("/\r?\n/", "\\n", 741 addslashes($data)) . '";</script>' 742 . '<body onload="parent.HTML_AJAX_IframeXHR_instances[\''.$id.'\']' 743 . '.isLoaded(Iframe_XHR_headers, Iframe_XHR_data);"></body></html>'; 744 return $string; 745 } 746 747 /** 748 * Handles a proxied grab request 749 * 750 * @return bool true to end the response, false to continue trying to handle it 751 * @access private 752 */ 753 function _iframeGrabProxy() 754 { 755 if (!isset($_REQUEST['Iframe_XHR_id'])) { 756 trigger_error('Invalid iframe ID'); 757 return false; 758 } 759 $this->_iframe = $_REQUEST['Iframe_XHR_id']; 760 $this->_payload = (isset($_REQUEST['Iframe_XHR_data']) ? $_REQUEST['Iframe_XHR_data'] : ''); 761 $url = urldecode($_GET['px']); 762 $url_parts = parse_url($url); 763 $urlregex = '#^https?://#i'; 764 765 if (!preg_match($urlregex, $url) || $url_parts['host'] != $_SERVER['HTTP_HOST']) { 766 trigger_error('Invalid URL for grab proxy'); 767 return true; 768 } 769 $method = (isset($_REQUEST['Iframe_XHR_HTTP_method']) 770 ? strtoupper($_REQUEST['Iframe_XHR_HTTP_method']) 771 : 'GET'); 772 // validate method 773 if ($method != 'GET' && $method != 'POST') { 774 trigger_error('Invalid grab URL'); 775 return true; 776 } 777 // validate headers 778 $headers = ''; 779 if (isset($_REQUEST['Iframe_XHR_headers'])) { 780 foreach ($_REQUEST['Iframe_XHR_headers'] as $header) { 781 if (strpos($header, "\r") !== false 782 || strpos($header, "\n") !== false) { 783 trigger_error('Invalid grab header'); 784 return true; 785 } 786 $headers .= $header . "\r\n"; 787 } 788 } 789 // tries to make request with file_get_contents() 790 if (ini_get('allow_url_fopen') && version_compare(phpversion(), '5.0.0'. '>=')) { 791 $opts = array( 792 $url_parts['scheme'] => array( 793 'method' => $method, 794 'headers' => $headers, 795 'content' => $this->_payload 796 ) 797 ); 798 $ret = @file_get_contents($url, false, stream_context_create($opts)); 799 if (!empty($ret)) { 800 $this->_sendResponse($ret); 801 return true; 802 } 803 } 804 // tries to make request using the curl extension 805 if (function_exists('curl_setopt')) { 806 $ch = curl_init(); 807 curl_setopt($ch, CURLOPT_URL, $url); 808 curl_setopt($ch, CURLOPT_HEADER, $headers); 809 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 810 $ret = curl_exec($ch); 811 if ($ret !== false) { 812 curl_close($ch); 813 $this->_sendResponse($ret); 814 return true; 815 } 816 } 817 if (isset($url_parts['port'])) { 818 $port = $url_parts['port']; 819 } else { 820 $port = getservbyname(strtolower($url_parts['scheme']), 'tcp'); 821 if ($port === false) { 822 trigger_error('Grab proxy: Unknown port or service, defaulting to 80', E_USER_WARNING); 823 $port = 80; 824 } 825 } 826 if (!isset($url_parts['path'])) { 827 $url_parts['path'] = '/'; 828 } 829 if (!empty($url_parts['query'])) { 830 $url_parts['path'] .= '?' . $url_parts['query']; 831 } 832 $request = "$method {$url_parts['path']} HTTP/1.0\r\n" 833 . "Host: {$url['host']}\r\n" 834 . "Connection: close\r\n" 835 . "$headers\r\n"; 836 // tries to make request using the socket functions 837 $fp = fsockopen($_SERVER['HTTP_HOST'], $port, $errno, $errstr, 4); 838 if ($fp) { 839 fputs($fp, $request); 840 841 $ret = ''; 842 $done_headers = false; 843 844 while (!feof($fp)) { 845 $ret .= fgets($fp, 2048); 846 if ($done_headers || ($contentpos = strpos($ret, "\r\n\r\n")) === false) { 847 continue; 848 } 849 $done_headers = true; 850 $ret = substr($ret, $contentpos + 4); 851 } 852 fclose($fp); 853 $this->_sendResponse($ret); 854 return true; 855 } 856 // tries to make the request using the socket extension 857 $host = gethostbyname($url['host']); 858 if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0 859 || ($connected = socket_connect($socket, $host, $port)) < 0 860 || ($written = socket_write($socket, $request)) < strlen($request)) { 861 trigger_error('Grab proxy failed: ' . socket_strerror($socket)); 862 return true; 863 } 864 865 $ret = ''; 866 $done_headers = false; 867 868 while ($out = socket_read($socket, 2048)) { 869 $ret .= $out; 870 if ($done_headers || ($contentpos = strpos($ret, "\r\n\r\n")) === false) { 871 continue; 872 } 873 $done_headers = true; 874 $ret = substr($ret, $contentpos + 4); 875 } 876 socket_close($socket); 877 $this->_sendResponse($ret); 878 return true; 879 } 880 881 /** 882 * Add a class or classes to those allowed to be unserialized 883 * 884 * @param mixed $classes the class or array of classes to add 885 * 886 * @access public 887 * @return void 888 */ 889 function addAllowedClasses($classes) 890 { 891 if (!is_array($classes)) { 892 $this->_allowedClasses[] = $classes; 893 } else { 894 $this->_allowedClasses = array_merge($this->_allowedClasses, $classes); 895 } 896 $this->_allowedClasses = array_unique($this->_allowedClasses); 897 } 898 899 /** 900 * Checks that the given callback is callable and allowed to be called 901 * 902 * @param callback $callback the callback to check 903 * 904 * @return bool true if the callback is valid, false otherwise 905 * @access private 906 */ 907 function _validatePhpCallback($callback) 908 { 909 if (!is_callable($callback)) { 910 return false; 911 } 912 $sig = md5(serialize($callback)); 913 return isset($this->_validCallbacks[$sig]); 914 } 915 916 /** 917 * Register a callback so it may be called from JS 918 * 919 * @param callback $callback the callback to register 920 * 921 * @access public 922 * @return void 923 */ 924 function registerPhpCallback($callback) 925 { 926 $this->_validCallbacks[md5(serialize($callback))] = 1; 927 } 928 929 /** 930 * Make JavaScript code smaller 931 * 932 * Currently just strips whitespace and comments, needs to remain fast 933 * Strips comments only if they are not preceeded by code 934 * Strips /*-style comments only if they span over more than one line 935 * Since strings cannot span over multiple lines, it cannot be defeated by a 936 * string containing /* 937 * 938 * @param string $input Javascript to pack 939 * 940 * @access public 941 * @return string packed javascript 942 */ 943 function packJavaScript($input) 944 { 945 $stripPregs = array( 946 '/^\s*$/', 947 '/^\s*\/\/.*$/' 948 ); 949 $blockStart = '/^\s*\/\/\*/'; 950 $blockEnd = '/\*\/\s*(.*)$/'; 951 $inlineComment = '/\/\*.*\*\//'; 952 $out = ''; 953 954 $lines = explode("\n", $input); 955 $inblock = false; 956 foreach ($lines as $line) { 957 $keep = true; 958 if ($inblock) { 959 if (preg_match($blockEnd, $line)) { 960 $inblock = false; 961 $line = preg_match($blockEnd, '$1', $line); 962 $keep = strlen($line) > 0; 963 } 964 } elseif (preg_match($inlineComment, $line)) { 965 $keep = true; 966 } elseif (preg_match($blockStart, $line)) { 967 $inblock = true; 968 $keep = false; 969 } 970 971 if (!$inblock) { 972 foreach ($stripPregs as $preg) { 973 if (preg_match($preg, $line)) { 974 $keep = false; 975 break; 976 } 977 } 978 } 979 980 if ($keep && !$inblock) { 981 $out .= trim($line)."\n"; 982 } 983 /* Enable to see what your striping out 984 else { 985 echo $line."<br>"; 986 }//*/ 987 } 988 $out .= "\n"; 989 return $out; 990 } 991 992 /** 993 * Set an interceptor class 994 * 995 * An interceptor class runs during the process of handling a request, 996 * it allows you to run security checks globally. It also allows you to 997 * rewrite parameters 998 * 999 * You can throw errors and exceptions in your intercptor methods and 1000 * they will be passed to javascript 1001 * 1002 * You can add interceptors are 3 levels 1003 * For a particular class/method, this is done by add a method to you class 1004 * named ClassName_MethodName($params) 1005 * For a particular class, method ClassName($methodName,$params) 1006 * Globally, method intercept($className,$methodName,$params) 1007 * 1008 * Only one match is done, using the most specific interceptor 1009 * 1010 * All methods have to return $params, if you want to empty all of the 1011 * parameters return an empty array 1012 * 1013 * @param Object $instance an instance of you interceptor class 1014 * 1015 * @todo handle php callbacks 1016 * @access public 1017 * @return void 1018 */ 1019 function setInterceptor($instance) 1020 { 1021 $this->_interceptor = $instance; 1022 } 1023 1024 /** 1025 * Attempt to intercept a call 1026 * 1027 * @param string $className Class Name 1028 * @param string $methodName Method Name 1029 * @param string $callback Not implemented 1030 * @param array $params Array of parameters to pass to the interceptor 1031 * 1032 * @todo handle php callbacks 1033 * @access private 1034 * @return array Updated params 1035 */ 1036 function _processInterceptor($className,$methodName,$callback,$params) 1037 { 1038 1039 $m = $className.'_'.$methodName; 1040 if (method_exists($this->_interceptor, $m)) { 1041 return $this->_interceptor->$m($params); 1042 } 1043 1044 $m = $className; 1045 if (method_exists($this->_interceptor, $m)) { 1046 return $this->_interceptor->$m($methodName, $params); 1047 } 1048 1049 $m = 'intercept'; 1050 if (method_exists($this->_interceptor, $m)) { 1051 return $this->_interceptor->$m($className, $methodName, $params); 1052 } 1053 1054 return $params; 1055 } 1056 } 1057 1058 /** 1059 * PHP 4 compat function for interface/class exists 1060 * 1061 * @param string $class Class name 1062 * @param bool $autoload Should the autoloader be called 1063 * 1064 * @access public 1065 * @return bool 1066 */ 1067 function HTML_AJAX_Class_exists($class, $autoload) 1068 { 1069 if (function_exists('interface_exists')) { 1070 return class_exists($class, $autoload); 1071 } else { 1072 return class_exists($class); 1073 } 1074 } 1075 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 1076 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |