Project

General

Profile

Download (21.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2

    
3
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4

    
5
/**
6
 * Server commands for our PHP implementation of the XML-RPC protocol
7
 *
8
 * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
9
 * It has support for HTTP transport, proxies and authentication.
10
 *
11
 * PHP versions 4 and 5
12
 *
13
 * @category   Web Services
14
 * @package    XML_RPC
15
 * @author     Edd Dumbill <edd@usefulinc.com>
16
 * @author     Stig Bakken <stig@php.net>
17
 * @author     Martin Jansen <mj@php.net>
18
 * @author     Daniel Convissor <danielc@php.net>
19
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
20
 * @license    http://www.php.net/license/3_01.txt  PHP License
21
 * @version    SVN: $Id: Server.php 300961 2010-07-03 02:17:34Z danielc $
22
 * @link       http://pear.php.net/package/XML_RPC
23
 */
24

    
25

    
26
/**
27
 * Pull in the XML_RPC class
28
 */
29
require_once 'xmlrpc_client.inc';
30

    
31

    
32
/**
33
 * signature for system.listMethods: return = array,
34
 * parameters = a string or nothing
35
 * @global array $GLOBALS['XML_RPC_Server_listMethods_sig']
36
 */
37
$GLOBALS['XML_RPC_Server_listMethods_sig'] = array(
38
    array($GLOBALS['XML_RPC_Array'],
39
          $GLOBALS['XML_RPC_String']
40
    ),
41
    array($GLOBALS['XML_RPC_Array'])
42
);
43

    
44
/**
45
 * docstring for system.listMethods
46
 * @global string $GLOBALS['XML_RPC_Server_listMethods_doc']
47
 */
48
$GLOBALS['XML_RPC_Server_listMethods_doc'] = gettext('This method lists all the'
49
        . ' methods that the XML-RPC server knows how to dispatch');
50

    
51
/**
52
 * signature for system.methodSignature: return = array,
53
 * parameters = string
54
 * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig']
55
 */
56
$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array(
57
    array($GLOBALS['XML_RPC_Array'],
58
          $GLOBALS['XML_RPC_String']
59
    )
60
);
61

    
62
/**
63
 * docstring for system.methodSignature
64
 * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc']
65
 */
66
$GLOBALS['XML_RPC_Server_methodSignature_doc'] = gettext('Returns an array of known'
67
        . ' signatures (an array of arrays) for the method name passed. If'
68
        . ' no signatures are known, returns a none-array (test for type !='
69
        . ' array to detect missing signature)');
70

    
71
/**
72
 * signature for system.methodHelp: return = string,
73
 * parameters = string
74
 * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig']
75
 */
76
$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array(
77
    array($GLOBALS['XML_RPC_String'],
78
          $GLOBALS['XML_RPC_String']
79
    )
80
);
81

    
82
/**
83
 * docstring for methodHelp
84
 * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc']
85
 */
86
$GLOBALS['XML_RPC_Server_methodHelp_doc'] = gettext('Returns help text if defined'
87
        . ' for the method passed, otherwise returns an empty string');
88

    
89
/**
90
 * dispatch map for the automatically declared XML-RPC methods.
91
 * @global array $GLOBALS['XML_RPC_Server_dmap']
92
 */
93
$GLOBALS['XML_RPC_Server_dmap'] = array(
94
    'system.listMethods' => array(
95
        'function'  => 'XML_RPC_Server_listMethods',
96
        'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'],
97
        'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc']
98
    ),
99
    'system.methodHelp' => array(
100
        'function'  => 'XML_RPC_Server_methodHelp',
101
        'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'],
102
        'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc']
103
    ),
104
    'system.methodSignature' => array(
105
        'function'  => 'XML_RPC_Server_methodSignature',
106
        'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'],
107
        'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc']
108
    )
109
);
110

    
111
/**
112
 * @global string $GLOBALS['XML_RPC_Server_debuginfo']
113
 */
114
$GLOBALS['XML_RPC_Server_debuginfo'] = '';
115

    
116

    
117
/**
118
 * Lists all the methods that the XML-RPC server knows how to dispatch
119
 *
120
 * @return object  a new XML_RPC_Response object
121
 */
122
function XML_RPC_Server_listMethods($server, $m)
123
{
124
    global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
125

    
126
    $v = new XML_RPC_Value();
127
    $outAr = array();
128
    foreach ($server->dmap as $key => $val) {
129
        $outAr[] = new XML_RPC_Value($key, 'string');
130
    }
131
    foreach ($XML_RPC_Server_dmap as $key => $val) {
132
        $outAr[] = new XML_RPC_Value($key, 'string');
133
    }
134
    $v->addArray($outAr);
135
    return new XML_RPC_Response($v);
136
}
137

    
138
/**
139
 * Returns an array of known signatures (an array of arrays)
140
 * for the given method
141
 *
142
 * If no signatures are known, returns a none-array
143
 * (test for type != array to detect missing signature)
144
 *
145
 * @return object  a new XML_RPC_Response object
146
 */
147
function XML_RPC_Server_methodSignature($server, $m)
148
{
149
    global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
150

    
151
    $methName = $m->getParam(0);
152
    $methName = $methName->scalarval();
153
    if (strpos($methName, 'system.') === 0) {
154
        $dmap = $XML_RPC_Server_dmap;
155
        $sysCall = 1;
156
    } else {
157
        $dmap = $server->dmap;
158
        $sysCall = 0;
159
    }
160
    //  print "<!-- ${methName} -->\n";
161
    if (isset($dmap[$methName])) {
162
        if ($dmap[$methName]['signature']) {
163
            $sigs = array();
164
            $thesigs = $dmap[$methName]['signature'];
165
            for ($i = 0; $i < sizeof($thesigs); $i++) {
166
                $cursig = array();
167
                $inSig = $thesigs[$i];
168
                for ($j = 0; $j < sizeof($inSig); $j++) {
169
                    $cursig[] = new XML_RPC_Value($inSig[$j], 'string');
170
                }
171
                $sigs[] = new XML_RPC_Value($cursig, 'array');
172
            }
173
            $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array'));
174
        } else {
175
            $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string'));
176
        }
177
    } else {
178
        $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'],
179
                                  $XML_RPC_str['introspect_unknown']);
180
    }
181
    return $r;
182
}
183

    
184
/**
185
 * Returns help text if defined for the method passed, otherwise returns
186
 * an empty string
187
 *
188
 * @return object  a new XML_RPC_Response object
189
 */
190
function XML_RPC_Server_methodHelp($server, $m)
191
{
192
    global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
193

    
194
    $methName = $m->getParam(0);
195
    $methName = $methName->scalarval();
196
    if (strpos($methName, 'system.') === 0) {
197
        $dmap = $XML_RPC_Server_dmap;
198
        $sysCall = 1;
199
    } else {
200
        $dmap = $server->dmap;
201
        $sysCall = 0;
202
    }
203

    
204
    if (isset($dmap[$methName])) {
205
        if ($dmap[$methName]['docstring']) {
206
            $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']),
207
                                                        'string');
208
        } else {
209
            $r = new XML_RPC_Response(new XML_RPC_Value('', 'string'));
210
        }
211
    } else {
212
        $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'],
213
                                     $XML_RPC_str['introspect_unknown']);
214
    }
215
    return $r;
216
}
217

    
218
/**
219
 * @return void
220
 */
221
function XML_RPC_Server_debugmsg($m)
222
{
223
    global $XML_RPC_Server_debuginfo;
224
    $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n";
225
}
226

    
227

    
228
/**
229
 * A server for receiving and replying to XML RPC requests
230
 *
231
 * <code>
232
 * $server = new XML_RPC_Server(
233
 *     array(
234
 *         'isan8' =>
235
 *             array(
236
 *                 'function' => 'is_8',
237
 *                 'signature' =>
238
 *                      array(
239
 *                          array('boolean', 'int'),
240
 *                          array('boolean', 'int', 'boolean'),
241
 *                          array('boolean', 'string'),
242
 *                          array('boolean', 'string', 'boolean'),
243
 *                      ),
244
 *                 'docstring' => 'Is the value an 8?'
245
 *             ),
246
 *     ),
247
 *     1,
248
 *     0
249
 * ); 
250
 * </code>
251
 *
252
 * @category   Web Services
253
 * @package    XML_RPC
254
 * @author     Edd Dumbill <edd@usefulinc.com>
255
 * @author     Stig Bakken <stig@php.net>
256
 * @author     Martin Jansen <mj@php.net>
257
 * @author     Daniel Convissor <danielc@php.net>
258
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
259
 * @license    http://www.php.net/license/3_01.txt  PHP License
260
 * @version    Release: @package_version@
261
 * @link       http://pear.php.net/package/XML_RPC
262
 */
263
class XML_RPC_Server
264
{
265
    /**
266
     * Should the payload's content be passed through mb_convert_encoding()?
267
     *
268
     * @see XML_RPC_Server::setConvertPayloadEncoding()
269
     * @since Property available since Release 1.5.1
270
     * @var boolean
271
     */
272
    var $convert_payload_encoding = false;
273

    
274
    /**
275
     * The dispatch map, listing the methods this server provides.
276
     * @var array
277
     */
278
    var $dmap = array();
279

    
280
    /**
281
     * The present response's encoding
282
     * @var string
283
     * @see XML_RPC_Message::getEncoding()
284
     */
285
    var $encoding = '';
286

    
287
    /**
288
     * Debug mode (0 = off, 1 = on)
289
     * @var integer
290
     */
291
    var $debug = 0;
292

    
293
    /**
294
     * The response's HTTP headers
295
     * @var string
296
     */
297
    var $server_headers = '';
298

    
299
    /**
300
     * The response's XML payload
301
     * @var string
302
     */
303
    var $server_payload = '';
304

    
305

    
306
    /**
307
     * Constructor for the XML_RPC_Server class
308
     *
309
     * @param array $dispMap   the dispatch map. An associative array
310
     *                          explaining each function. The keys of the main
311
     *                          array are the procedure names used by the
312
     *                          clients. The value is another associative array
313
     *                          that contains up to three elements:
314
     *                            + The 'function' element's value is the name
315
     *                              of the function or method that gets called.
316
     *                              To define a class' method: 'class::method'.
317
     *                            + The 'signature' element (optional) is an
318
     *                              array describing the return values and
319
     *                              parameters
320
     *                            + The 'docstring' element (optional) is a
321
     *                              string describing what the method does
322
     * @param int $serviceNow  should the HTTP response be sent now?
323
     *                          (1 = yes, 0 = no)
324
     * @param int $debug       should debug output be displayed?
325
     *                          (1 = yes, 0 = no)
326
     *
327
     * @return void
328
     */
329
    function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0)
330
    {
331
        global $HTTP_RAW_POST_DATA;
332

    
333
        if ($debug) {
334
            $this->debug = 1;
335
        } else {
336
            $this->debug = 0;
337
        }
338

    
339
        $this->dmap = $dispMap;
340

    
341
        if ($serviceNow) {
342
            $this->service();
343
        } else {
344
            $this->createServerPayload();
345
            $this->createServerHeaders();
346
        }
347
    }
348

    
349
    /**
350
     * @return string  the debug information if debug debug mode is on
351
     */
352
    function serializeDebug()
353
    {
354
        global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA;
355

    
356
        if ($this->debug) {
357
            XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n"
358
                                    . $HTTP_RAW_POST_DATA
359
                                    . "\n" . '^^^ END POST DATA ^^^');
360
        }
361

    
362
        if ($XML_RPC_Server_debuginfo != '') {
363
            return "<!-- PEAR XML_RPC SERVER DEBUG INFO:\n\n"
364
                   . str_replace('--', '- - ', $XML_RPC_Server_debuginfo)
365
                   . "-->\n";
366
        } else {
367
            return '';
368
        }
369
    }
370

    
371
    /**
372
     * Sets whether the payload's content gets passed through
373
     * mb_convert_encoding()
374
     *
375
     * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
376
     *
377
     * @param int $in  where 1 = on, 0 = off
378
     *
379
     * @return void
380
     *
381
     * @see XML_RPC_Message::getEncoding()
382
     * @since Method available since Release 1.5.1
383
     */
384
    function setConvertPayloadEncoding($in)
385
    {
386
        if ($in && !function_exists('mb_convert_encoding')) {
387
            return $this->raiseError('mb_convert_encoding() is not available',
388
                              XML_RPC_ERROR_PROGRAMMING);
389
        }
390
        $this->convert_payload_encoding = $in;
391
    }
392

    
393
    /**
394
     * Sends the response
395
     *
396
     * The encoding and content-type are determined by
397
     * XML_RPC_Message::getEncoding()
398
     *
399
     * @return void
400
     *
401
     * @uses XML_RPC_Server::createServerPayload(),
402
     *       XML_RPC_Server::createServerHeaders()
403
     */
404
    function service()
405
    {
406
        if (!$this->server_payload) {
407
            $this->createServerPayload();
408
        }
409
        if (!$this->server_headers) {
410
            $this->createServerHeaders();
411
        }
412

    
413
        /*
414
         * $server_headers needs to remain a string for compatibility with
415
         * old scripts using this package, but PHP 4.4.2 no longer allows
416
         * line breaks in header() calls.  So, we split each header into
417
         * an individual call.  The initial replace handles the off chance
418
         * that someone composed a single header with multiple lines, which
419
         * the RFCs allow.
420
         */
421
        $this->server_headers = preg_replace("@[\r\n]+[ \t]+@",
422
                                ' ', trim($this->server_headers));
423
        $headers = preg_split("@[\r\n]+@", $this->server_headers);
424
        foreach ($headers as $header)
425
        {
426
            header($header);
427
        }
428

    
429
        print $this->server_payload;
430
    }
431

    
432
    /**
433
     * Generates the payload and puts it in the $server_payload property
434
     *
435
     * If XML_RPC_Server::setConvertPayloadEncoding() was set to true,
436
     * the payload gets passed through mb_convert_encoding()
437
     * to ensure the payload matches the encoding set in the
438
     * XML declaration.  The encoding type can be manually set via
439
     * XML_RPC_Message::setSendEncoding().
440
     *
441
     * @return void
442
     *
443
     * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding,
444
     *       XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug()
445
     * @see  XML_RPC_Server::setConvertPayloadEncoding()
446
     */
447
    function createServerPayload()
448
    {
449
        $r = $this->parseRequest();
450
        $this->server_payload = '<?xml version="1.0" encoding="'
451
                              . $this->encoding . '"?>' . "\n"
452
                              . $this->serializeDebug()
453
                              . $r->serialize();
454
        if ($this->convert_payload_encoding) {
455
            $this->server_payload = mb_convert_encoding($this->server_payload,
456
                                                        $this->encoding);
457
        }
458
    }
459

    
460
    /**
461
     * Determines the HTTP headers and puts them in the $server_headers
462
     * property
463
     *
464
     * @return boolean  TRUE if okay, FALSE if $server_payload isn't set.
465
     *
466
     * @uses XML_RPC_Server::createServerPayload(),
467
     *       XML_RPC_Server::$server_headers
468
     */
469
    function createServerHeaders()
470
    {
471
        if (!$this->server_payload) {
472
            return false;
473
        }
474
        $this->server_headers = 'Content-Length: '
475
                              . strlen($this->server_payload) . "\r\n"
476
                              . 'Content-Type: text/xml;'
477
                              . ' charset=' . $this->encoding;
478
        return true;
479
    }
480

    
481
    /**
482
     * @return array
483
     */
484
    function verifySignature($in, $sig)
485
    {
486
        for ($i = 0; $i < sizeof($sig); $i++) {
487
            // check each possible signature in turn
488
            $cursig = $sig[$i];
489
            if (sizeof($cursig) == $in->getNumParams() + 1) {
490
                $itsOK = 1;
491
                for ($n = 0; $n < $in->getNumParams(); $n++) {
492
                    $p = $in->getParam($n);
493
                    // print "<!-- $p -->\n";
494
                    if ($p->kindOf() == 'scalar') {
495
                        $pt = $p->scalartyp();
496
                    } else {
497
                        $pt = $p->kindOf();
498
                    }
499
                    // $n+1 as first type of sig is return type
500
                    if ($pt != $cursig[$n+1]) {
501
                        $itsOK = 0;
502
                        $pno = $n+1;
503
                        $wanted = $cursig[$n+1];
504
                        $got = $pt;
505
                        break;
506
                    }
507
                }
508
                if ($itsOK) {
509
                    return array(1);
510
                }
511
            }
512
        }
513
        if (isset($wanted)) {
514
            return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
515
        } else {
516
            $allowed = array();
517
            foreach ($sig as $val) {
518
                end($val);
519
                $allowed[] = key($val);
520
            }
521
            $allowed = array_unique($allowed);
522
            $last = count($allowed) - 1;
523
            if ($last > 0) {
524
                $allowed[$last] = 'or ' . $allowed[$last];
525
            }
526
            return array(0,
527
                         'Signature permits ' . implode(', ', $allowed)
528
                                . ' parameters but the request had '
529
                                . $in->getNumParams());
530
        }
531
    }
532

    
533
    /**
534
     * @return object  a new XML_RPC_Response object
535
     *
536
     * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding
537
     */
538
    function parseRequest($data = '')
539
    {
540
        global $XML_RPC_xh, $HTTP_RAW_POST_DATA,
541
                $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml,
542
                $XML_RPC_defencoding, $XML_RPC_Server_dmap;
543

    
544
        if ($data == '') {
545
            $data = $HTTP_RAW_POST_DATA;
546
        }
547

    
548
        $this->encoding = XML_RPC_Message::getEncoding($data);
549
        $parser_resource = xml_parser_create($this->encoding);
550
        $parser = (int) $parser_resource;
551

    
552
        $XML_RPC_xh[$parser] = array();
553
        $XML_RPC_xh[$parser]['cm']     = 0;
554
        $XML_RPC_xh[$parser]['isf']    = 0;
555
        $XML_RPC_xh[$parser]['params'] = array();
556
        $XML_RPC_xh[$parser]['method'] = '';
557
        $XML_RPC_xh[$parser]['stack'] = array();	
558
        $XML_RPC_xh[$parser]['valuestack'] = array();	
559

    
560
        $plist = '';
561

    
562
        // decompose incoming XML into request structure
563

    
564
        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
565
        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
566
        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
567
        if (!xml_parse($parser_resource, $data, 1)) {
568
            // return XML error as a faultCode
569
            $r = new XML_RPC_Response(0,
570
                                      $XML_RPC_errxml+xml_get_error_code($parser_resource),
571
                                      sprintf('XML error: %s at line %d',
572
                                              xml_error_string(xml_get_error_code($parser_resource)),
573
                                              xml_get_current_line_number($parser_resource)));
574
            xml_parser_free($parser_resource);
575
        } elseif ($XML_RPC_xh[$parser]['isf']>1) {
576
            $r = new XML_RPC_Response(0,
577
                                      $XML_RPC_err['invalid_request'],
578
                                      $XML_RPC_str['invalid_request']
579
                                      . ': '
580
                                      . $XML_RPC_xh[$parser]['isf_reason']);
581
            xml_parser_free($parser_resource);
582
        } else {
583
            xml_parser_free($parser_resource);
584
            $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']);
585
            // now add parameters in
586
            for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) {
587
                // print '<!-- ' . $XML_RPC_xh[$parser]['params'][$i]. "-->\n";
588
                $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n";
589
                $m->addParam($XML_RPC_xh[$parser]['params'][$i]);
590
            }
591

    
592
            if ($this->debug) {
593
                XML_RPC_Server_debugmsg($plist);
594
            }
595

    
596
            // now to deal with the method
597
            $methName = $XML_RPC_xh[$parser]['method'];
598
            if (strpos($methName, 'system.') === 0) {
599
                $dmap = $XML_RPC_Server_dmap;
600
                $sysCall = 1;
601
            } else {
602
                $dmap = $this->dmap;
603
                $sysCall = 0;
604
            }
605

    
606
            if (isset($dmap[$methName]['function'])
607
                && is_string($dmap[$methName]['function'])
608
                && strpos($dmap[$methName]['function'], '::') !== false)
609
            {
610
                $dmap[$methName]['function'] =
611
                        explode('::', $dmap[$methName]['function']);
612
            }
613

    
614
            if (isset($dmap[$methName]['function'])
615
                && is_callable($dmap[$methName]['function']))
616
            {
617
                // dispatch if exists
618
                if (isset($dmap[$methName]['signature'])) {
619
                    $sr = $this->verifySignature($m,
620
                                                 $dmap[$methName]['signature'] );
621
                }
622
                if (!isset($dmap[$methName]['signature']) || $sr[0]) {
623
                    // if no signature or correct signature
624
                    if ($sysCall) {
625
                        $r = call_user_func($dmap[$methName]['function'], $this, $m);
626
                    } else {
627
                        $r = call_user_func($dmap[$methName]['function'], $m);
628
                    }
629
                    if (!is_a($r, 'XML_RPC_Response')) {
630
                        $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'],
631
                                                  $XML_RPC_str['not_response_object']);
632
                    }
633
                } else {
634
                    $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
635
                                              $XML_RPC_str['incorrect_params']
636
                                              . ': ' . $sr[1]);
637
                }
638
            } else {
639
                // else prepare error response
640
                $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'],
641
                                          $XML_RPC_str['unknown_method']);
642
            }
643
        }
644
        return $r;
645
    }
646

    
647
    /**
648
     * Echos back the input packet as a string value
649
     *
650
     * @return void
651
     *
652
     * Useful for debugging.
653
     */
654
    function echoInput()
655
    {
656
        global $HTTP_RAW_POST_DATA;
657

    
658
        $r = new XML_RPC_Response(0);
659
        $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string');
660
        print $r->serialize();
661
    }
662
}
663

    
664
/*
665
 * Local variables:
666
 * tab-width: 4
667
 * c-basic-offset: 4
668
 * c-hanging-comment-ender-p: nil
669
 * End:
670
 */
671

    
672
?>
(65-65/66)