~ubuntu-branches/ubuntu/jaunty/moodle/jaunty

« back to all changes in this revision

Viewing changes to lib/pear/HTML/AJAX.php

  • Committer: Bazaar Package Importer
  • Author(s): Jordan Mantha, Matt Oquist
  • Date: 2009-02-25 15:16:22 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20090225151622-0ekt1liwhv2obfza
Tags: 1.9.4.dfsg-0ubuntu1
* Merge with Debian git (Closes LP: #322961, #239481, #334611):
  - use Ubuntu's smarty lib directory for linking
  - use internal yui library 
  - add update-notifier support back in

[Matt Oquist]
  * renamed prerm script
  * significantly rewrote postinst and other maintainer scripts to improve
    user experience and package maintainability
    (Closes LP: #225662, #325450, #327843, #303078, #234609)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
?>