Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

MDL-16780 Adding missing file

  • Loading branch information...
commit 8a30c5bec21dfd738e02157c1ece0df62cb930cd 1 parent e073353
nicolasconnault authored

Showing 1 changed file with 1,076 additions and 0 deletions. Show diff stats Hide diff stats

  1. +1,076 0 lib/pear/HTML/AJAX.php
1,076 lib/pear/HTML/AJAX.php
... ... @@ -0,0 +1,1076 @@
  1 +<?php
  2 +/**
  3 + * OO AJAX Implementation for PHP
  4 + *
  5 + * SVN Rev: $Id$
  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 +?>

0 comments on commit 8a30c5b

Please sign in to comment.
Something went wrong with that request. Please try again.