~technofluid-team/openobject-addons/technofluid_multiple_installations

« back to all changes in this revision

Viewing changes to esale_joomla/connector/xmlrpcs.inc

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-dedd7f8a42bd4557112a0513082691b8590ad6cc
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
// by Edd Dumbill (C) 1999-2002
 
3
// <edd@usefulinc.com>
 
4
// $Id: xmlrpcs.inc,v 1.52 2006/01/19 23:48:58 ggiunta Exp $
 
5
 
 
6
// Copyright (c) 1999,2000,2002 Edd Dumbill.
 
7
// All rights reserved.
 
8
//
 
9
// Redistribution and use in source and binary forms, with or without
 
10
// modification, are permitted provided that the following conditions
 
11
// are met:
 
12
//
 
13
//              * Redistributions of source code must retain the above copyright
 
14
//                      notice, this list of conditions and the following disclaimer.
 
15
//
 
16
//              * Redistributions in binary form must reproduce the above
 
17
//                      copyright notice, this list of conditions and the following
 
18
//                      disclaimer in the documentation and/or other materials provided
 
19
//                      with the distribution.
 
20
//
 
21
//              * Neither the name of the "XML-RPC for PHP" nor the names of its
 
22
//                      contributors may be used to endorse or promote products derived
 
23
//                      from this software without specific prior written permission.
 
24
//
 
25
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
26
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
27
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 
28
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 
29
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 
30
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
31
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
32
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
33
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
34
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
35
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 
36
// OF THE POSSIBILITY OF SUCH DAMAGE.
 
37
 
 
38
        // XML RPC Server class
 
39
        // requires: xmlrpc.inc
 
40
 
 
41
        // listMethods: signature was either a string, or nothing.
 
42
        // The useless string variant has been removed
 
43
        $_xmlrpcs_listMethods_sig=array(array($GLOBALS['xmlrpcArray']));
 
44
        $_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch';
 
45
        function _xmlrpcs_listMethods($server, $m=null) // if called in plain php values mode, second param is missing
 
46
        {
 
47
 
 
48
                $outAr=array();
 
49
                foreach($server->dmap as $key => $val)
 
50
                {
 
51
                        $outAr[]=&new xmlrpcval($key, 'string');
 
52
                }
 
53
                if($server->allow_system_funcs)
 
54
                {
 
55
                        foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val)
 
56
                        {
 
57
                                $outAr[]=&new xmlrpcval($key, 'string');
 
58
                        }
 
59
                }
 
60
                $v=&new xmlrpcval($outAr, 'array');
 
61
                return new xmlrpcresp($v);
 
62
        }
 
63
 
 
64
        $_xmlrpcs_methodSignature_sig=array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcString']));
 
65
        $_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
 
66
        function _xmlrpcs_methodSignature($server, $m)
 
67
        {
 
68
                // let accept as parameter both an xmlrpcval or string
 
69
                if (is_object($m))
 
70
                {
 
71
                        $methName=$m->getParam(0);
 
72
                        $methName=$methName->scalarval();
 
73
                }
 
74
                else
 
75
                {
 
76
                        $methName=$m;
 
77
                }
 
78
                if(ereg("^system\.", $methName))
 
79
                {
 
80
                        $dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
 
81
                }
 
82
                else
 
83
                {
 
84
                        $dmap=$server->dmap; $sysCall=0;
 
85
                }
 
86
                //      print "<!-- ${methName} -->\n";
 
87
                if(isset($dmap[$methName]))
 
88
                {
 
89
                        if(isset($dmap[$methName]['signature']))
 
90
                        {
 
91
                                $sigs=array();
 
92
                                foreach($dmap[$methName]['signature'] as $inSig)
 
93
                                {
 
94
                                        $cursig=array();
 
95
                                        foreach($inSig as $sig)
 
96
                                        {
 
97
                                                $cursig[]=&new xmlrpcval($sig, 'string');
 
98
                                        }
 
99
                                        $sigs[]=&new xmlrpcval($cursig, 'array');
 
100
                                }
 
101
                                $r=&new xmlrpcresp(new xmlrpcval($sigs, 'array'));
 
102
                        }
 
103
                        else
 
104
                        {
 
105
                                // NB: according to the official docs, we should be returning a
 
106
                                // "none-array" here, which means not-an-array
 
107
                                $r=&new xmlrpcresp(new xmlrpcval('undef', 'string'));
 
108
                        }
 
109
                }
 
110
                else
 
111
                {
 
112
                        $r=&new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
 
113
                }
 
114
                return $r;
 
115
        }
 
116
 
 
117
        $_xmlrpcs_methodHelp_sig=array(array($GLOBALS['xmlrpcString'], $GLOBALS['xmlrpcString']));
 
118
        $_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string';
 
119
        function _xmlrpcs_methodHelp($server, $m)
 
120
        {
 
121
                // let accept as parameter both an xmlrpcval or string
 
122
                if (is_object($m))
 
123
                {
 
124
                        $methName=$m->getParam(0);
 
125
                        $methName=$methName->scalarval();
 
126
                }
 
127
                else
 
128
                {
 
129
                        $methName=$m;
 
130
                }
 
131
                if(ereg("^system\.", $methName))
 
132
                {
 
133
                        $dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
 
134
                }
 
135
                else
 
136
                {
 
137
                        $dmap=$server->dmap; $sysCall=0;
 
138
                }
 
139
                // print "<!-- ${methName} -->\n";
 
140
                if(isset($dmap[$methName]))
 
141
                {
 
142
                        if(isset($dmap[$methName]['docstring']))
 
143
                        {
 
144
                                $r=&new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
 
145
                        }
 
146
                        else
 
147
                        {
 
148
                                $r=&new xmlrpcresp(new xmlrpcval('', 'string'));
 
149
                        }
 
150
                }
 
151
                else
 
152
                {
 
153
                        $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
 
154
                }
 
155
                return $r;
 
156
        }
 
157
 
 
158
        $_xmlrpcs_multicall_sig = array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcArray']));
 
159
        $_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details';
 
160
 
 
161
        function _xmlrpcs_multicall_error($err)
 
162
        {
 
163
                if(is_string($err))
 
164
                {
 
165
                        $str = $GLOBALS['xmlrpcstr']["multicall_${err}"];
 
166
                        $code = $GLOBALS['xmlrpcerr']["multicall_${err}"];
 
167
                }
 
168
                else
 
169
                {
 
170
                        $code = $err->faultCode();
 
171
                        $str = $err->faultString();
 
172
                }
 
173
                $struct = array();
 
174
                $struct['faultCode'] =& new xmlrpcval($code, 'int');
 
175
                $struct['faultString'] =& new xmlrpcval($str, 'string');
 
176
                return new xmlrpcval($struct, 'struct');
 
177
        }
 
178
 
 
179
        function _xmlrpcs_multicall_do_call($server, $call)
 
180
        {
 
181
                if($call->kindOf() != 'struct')
 
182
                {
 
183
                        return _xmlrpcs_multicall_error('notstruct');
 
184
                }
 
185
                $methName = @$call->structmem('methodName');
 
186
                if(!$methName)
 
187
                {
 
188
                        return _xmlrpcs_multicall_error('nomethod');
 
189
                }
 
190
                if($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
 
191
                {
 
192
                        return _xmlrpcs_multicall_error('notstring');
 
193
                }
 
194
                if($methName->scalarval() == 'system.multicall')
 
195
                {
 
196
                        return _xmlrpcs_multicall_error('recursion');
 
197
                }
 
198
 
 
199
                $params = @$call->structmem('params');
 
200
                if(!$params)
 
201
                {
 
202
                        return _xmlrpcs_multicall_error('noparams');
 
203
                }
 
204
                if($params->kindOf() != 'array')
 
205
                {
 
206
                        return _xmlrpcs_multicall_error('notarray');
 
207
                }
 
208
                $numParams = $params->arraysize();
 
209
 
 
210
                $msg =& new xmlrpcmsg($methName->scalarval());
 
211
                for($i = 0; $i < $numParams; $i++)
 
212
                {
 
213
                        if(!$msg->addParam($params->arraymem($i)))
 
214
                        {
 
215
                                $i++;
 
216
                                return _xmlrpcs_multicall_error(new xmlrpcresp(0,
 
217
                                        $GLOBALS['xmlrpcerr']['incorrect_params'],
 
218
                                        $GLOBALS['xmlrpcstr']['incorrect_params'] . ": probable xml error in param " . $i));
 
219
                        }
 
220
                }
 
221
 
 
222
                $result = $server->execute($msg);
 
223
 
 
224
                if($result->faultCode() != 0)
 
225
                {
 
226
                        return _xmlrpcs_multicall_error($result);               // Method returned fault.
 
227
                }
 
228
 
 
229
                return new xmlrpcval(array($result->value()), 'array');
 
230
        }
 
231
 
 
232
        function _xmlrpcs_multicall_do_call_phpvals($server, $call)
 
233
        {
 
234
                if(!is_array($call))
 
235
                {
 
236
                        return _xmlrpcs_multicall_error('notstruct');
 
237
                }
 
238
                if(!array_key_exists('methodName', $call))
 
239
                {
 
240
                        return _xmlrpcs_multicall_error('nomethod');
 
241
                }
 
242
                if (!is_string($call['methodName']))
 
243
                {
 
244
                        return _xmlrpcs_multicall_error('notstring');
 
245
                }
 
246
                if($call['methodName'] == 'system.multicall')
 
247
                {
 
248
                        return _xmlrpcs_multicall_error('recursion');
 
249
                }
 
250
                if(!array_key_exists('params', $call))
 
251
                {
 
252
                        return _xmlrpcs_multicall_error('noparams');
 
253
                }
 
254
                if(!is_array($call['params']))
 
255
                {
 
256
                        return _xmlrpcs_multicall_error('notarray');
 
257
                }
 
258
 
 
259
                // this is a real dirty and simplistic hack, since we might have received a
 
260
                // base64 or datetime values, but they will be listed as strings here...
 
261
                $numParams = count($call['params']);
 
262
                $pt = array();
 
263
                foreach($call['params'] as $val)
 
264
                        $pt[] = php_2_xmlrpc_type(gettype($val));
 
265
 
 
266
                $result = $server->execute($call['methodName'], $call['params'], $pt);
 
267
 
 
268
                if($result->faultCode() != 0)
 
269
                {
 
270
                        return _xmlrpcs_multicall_error($result);               // Method returned fault.
 
271
                }
 
272
 
 
273
                return new xmlrpcval(array($result->value()), 'array');
 
274
        }
 
275
 
 
276
        function _xmlrpcs_multicall($server, $m)
 
277
        {
 
278
                $result = array();
 
279
                // let accept a plain list of php parameters, beside a single xmlrpc msg object
 
280
                if (is_object($m))
 
281
                {
 
282
                        $calls = $m->getParam(0);
 
283
                        $numCalls = $calls->arraysize();
 
284
                        for($i = 0; $i < $numCalls; $i++)
 
285
                        {
 
286
                                $call = $calls->arraymem($i);
 
287
                                $result[$i] = _xmlrpcs_multicall_do_call($server, $call);
 
288
                        }
 
289
                }
 
290
                else
 
291
                {
 
292
                        //$calls = func_get_args();
 
293
                        $numCalls=count($m);
 
294
                        for($i = 0; $i < $numCalls; $i++)
 
295
                        {
 
296
                                $result[$i] = _xmlrpcs_multicall_do_call_phpvals($server, $m[$i]);
 
297
                        }
 
298
                }
 
299
 
 
300
                return new xmlrpcresp(new xmlrpcval($result, 'array'));
 
301
        }
 
302
 
 
303
        $GLOBALS['_xmlrpcs_dmap']=array(
 
304
                'system.listMethods' => array(
 
305
                        'function' => '_xmlrpcs_listMethods',
 
306
                        'signature' => $_xmlrpcs_listMethods_sig,
 
307
                        'docstring' => $_xmlrpcs_listMethods_doc),
 
308
                'system.methodHelp' => array(
 
309
                        'function' => '_xmlrpcs_methodHelp',
 
310
                        'signature' => $_xmlrpcs_methodHelp_sig,
 
311
                        'docstring' => $_xmlrpcs_methodHelp_doc),
 
312
                'system.methodSignature' => array(
 
313
                        'function' => '_xmlrpcs_methodSignature',
 
314
                        'signature' => $_xmlrpcs_methodSignature_sig,
 
315
                        'docstring' => $_xmlrpcs_methodSignature_doc),
 
316
                'system.multicall' => array(
 
317
                        'function' => '_xmlrpcs_multicall',
 
318
                        'signature' => $_xmlrpcs_multicall_sig,
 
319
                        'docstring' => $_xmlrpcs_multicall_doc
 
320
                )
 
321
        );
 
322
 
 
323
        $GLOBALS['_xmlrpcs_occurred_errors'] = '';
 
324
        $GLOBALS['_xmlrpcs_prev_ehandler'] = '';
 
325
        /**
 
326
        * Error handler used to track errors that occur during server-side execution of PHP code.
 
327
        * This allows to report back to the client whether an internal error has occurred or not
 
328
        * using an xmlrpc response object, instead of letting the client deal with the html junk
 
329
        * that a PHP execution error on the server generally entails.
 
330
        *
 
331
        * NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors.
 
332
        *
 
333
        */
 
334
        function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null)
 
335
        {
 
336
                //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING)
 
337
                if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined
 
338
                {
 
339
                        $GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n";
 
340
                }
 
341
                // Try to avoid as much as possible disruption to the previous error handling
 
342
                // mechanism in place
 
343
                if($GLOBALS['_xmlrpcs_prev_ehandler'] == '')
 
344
                {
 
345
                        // The previous error handler was the default: all we should do is log error
 
346
                        // to teh default error log (if level high enough)
 
347
                        if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode))
 
348
                        {
 
349
                                error_log($errstring);
 
350
                        }
 
351
                }
 
352
                else
 
353
                {
 
354
                        // Pass control on to previous error handler, trying to avoid loops...
 
355
                        if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler')
 
356
                        {
 
357
                                // NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers
 
358
                                if(is_array($GLOBALS['_xmlrpcs_prev_ehandler']))
 
359
                                {
 
360
                                        $GLOBALS['_xmlrpcs_prev_ehandler'][0]->$GLOBALS['_xmlrpcs_prev_ehandler'][1]($errcode, $errstring, $filename, $lineno, $context);
 
361
                                }
 
362
                                else
 
363
                                {
 
364
                                        $GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context);
 
365
                                }
 
366
                        }
 
367
                }
 
368
        }
 
369
 
 
370
        $GLOBALS['_xmlrpc_debuginfo']='';
 
371
 
 
372
        /**
 
373
        * Add a string to the debug info that can be later seralized by the server
 
374
        * as part of the response message.
 
375
        * Note that for best compatbility, the debug string should be encoded using
 
376
        * the $GLOBALS['xmlrpc_internalencoding'] character set.
 
377
        * @param string $m
 
378
        * @access public
 
379
        */
 
380
        function xmlrpc_debugmsg($m)
 
381
        {
 
382
                $GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
 
383
        }
 
384
 
 
385
        class xmlrpc_server
 
386
        {
 
387
                /// array defining php functions exposed as xmlrpc methods by this server
 
388
                var $dmap=array();
 
389
                /**
 
390
                * Defines how functions in dmap will be invokde: either using an xmlrpc msg object
 
391
                * or plain php values.
 
392
                * valid strings are 'xmlrpcvals' or 'phpvals'
 
393
                */
 
394
                var $functions_parameters_type='xmlrpcvals';
 
395
                /// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3
 
396
                var $debug = 1;
 
397
                /**
 
398
                * When set to true, it will enable HTTP compression of the response, in case
 
399
                * the client has declared its support for compression in the request.
 
400
                */
 
401
                var $compress_response = false;
 
402
                /**
 
403
                * List of http compression methods accepted by the server for requests.
 
404
                * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
 
405
                */
 
406
                var $accepted_compression = array();
 
407
                /// shall we serve calls to system.* methods?
 
408
                var $allow_system_funcs = true;
 
409
                /// list of charset encodings natively accepted for requests
 
410
                var $accepted_charset_encodings = array();
 
411
                /**
 
412
                * charset encoding to be used for response.
 
413
                * NB: if we can, we will convert the generated response from internal_encoding to the intended one.
 
414
                * can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled),
 
415
                * null (leave unspecified in response, convert output stream to US_ASCII),
 
416
                * 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert outpt stream if needed),
 
417
                * or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway).
 
418
                * NB: pretty dangerous if you accept every charset and do not have mbstring enabled)
 
419
                */
 
420
                var $response_charset_encoding = '';
 
421
                var $xml_header = "<?xml version=\"1.0\" ?>\n";
 
422
                /// storage for internal debug info
 
423
                var $debug_info = '';
 
424
 
 
425
                /**
 
426
                * @param array $dispmap the dispatch map withd efinition of exposed services
 
427
                * @param boolean $servicenow set to false to prevent the server from runnung upon construction
 
428
                */
 
429
                function xmlrpc_server($dispMap=null, $serviceNow=true)
 
430
                {
 
431
                        // if ZLIB is enabled, let the server by default accept compressed requests,
 
432
                        // and compress responses sent to clients that support them
 
433
                        if(function_exists('gzinflate'))
 
434
                        {
 
435
                                $this->accepted_compression = array('gzip', 'deflate');
 
436
                                $this->compress_response = true;
 
437
                        }
 
438
 
 
439
                        // by default the xml parser can support these 3 charset encodings
 
440
                        $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
 
441
 
 
442
                        // dispMap is a dispatch array of methods
 
443
                        // mapped to function names and signatures
 
444
                        // if a method
 
445
                        // doesn't appear in the map then an unknown
 
446
                        // method error is generated
 
447
                        /* milosch - changed to make passing dispMap optional.
 
448
                         * instead, you can use the class add_to_map() function
 
449
                         * to add functions manually (borrowed from SOAPX4)
 
450
                         */
 
451
                        if($dispMap)
 
452
                        {
 
453
                                $this->dmap = $dispMap;
 
454
                                if($serviceNow)
 
455
                                {
 
456
                                        $this->service();
 
457
                                }
 
458
                        }
 
459
                }
 
460
 
 
461
                /**
 
462
                * Set debug level of server.
 
463
                * @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments)
 
464
                * 0 = no debug info,
 
465
                * 1 = msgs set from user with debugmsg(),
 
466
                * 2 = add complete xmlrpc request (headers and body),
 
467
                * 3 = add also all processing warnings happened during method processing
 
468
                * (NB: this involves setting a custom error handler, and might interfere
 
469
                * with the standard processing of the php function exposed as method. In
 
470
                * particular, triggering an USER_ERROR level error will not halt script
 
471
                * execution anymore, but just end up logged in the xmlrpc response)
 
472
                * Note that info added at elevel 2 and 3 will be base64 encoded
 
473
                */
 
474
                function setDebug($in)
 
475
                {
 
476
                        $this->debug=$in;
 
477
                }
 
478
 
 
479
                /**
 
480
                * Return a string with the serialized representation of all debug info
 
481
                * @param string $charset_encoding the target charset encoding for the serialization
 
482
                * @return string an XML comment (or two)
 
483
                */
 
484
                function serializeDebug($charset_encoding='')
 
485
                {
 
486
                        // Tough encoding problem: which internal charset should we assume for debug info?
 
487
                        // It might contain a copy of raw data received from client, ie with unknown encoding,
 
488
                        // intermixed with php generated data and user generated data...
 
489
                        // so we split it: system debug is base 64 encoded,
 
490
                        // user debug info should be encoded by the end user using the INTERNAL_ENCODING
 
491
                        $out = '';
 
492
                        if ($this->debug_info != '') {
 
493
                                $out .= "<!-- SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n-->\n";
 
494
                        }
 
495
                        if($GLOBALS['_xmlrpc_debuginfo']!='')
 
496
                        {
 
497
 
 
498
                                $out .= "<!-- DEBUG INFO:\n" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n";
 
499
                                // NB: a better solution MIGHT be to use CDATA, but we need to insert it
 
500
                                // into return payload AFTER the beginning tag
 
501
                                //$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n";
 
502
                        }
 
503
                        return $out;
 
504
                }
 
505
 
 
506
                /**
 
507
                * Execute the xmlrpc request, printing the response
 
508
                * @param string $data the request body. If null, the http POST request will be examined
 
509
                */
 
510
                function service($data=null)
 
511
                {
 
512
                        if ($data === null) {
 
513
                                $data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
 
514
                        }
 
515
 
 
516
                        // reset internal debug info
 
517
                        $this->debug_info = '';
 
518
 
 
519
                        // Echo back what we received, before parsing it
 
520
                        if($this->debug > 1)
 
521
                        {
 
522
                                $this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++");
 
523
                        }
 
524
 
 
525
                        $r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding);
 
526
                        if (!$r)
 
527
                        {
 
528
                                $r=$this->parseRequest($data, $req_charset);
 
529
                        }
 
530
 
 
531
                        if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors'])
 
532
                        {
 
533
                                $this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" .
 
534
                                        $GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++");
 
535
                        }
 
536
 
 
537
                        //$payload='<?xml version="1.0" encoding="' . $GLOBALS['xmlrpc_defencoding'] . '"?' . '>' . "\n"
 
538
                        $payload=$this->xml_header;
 
539
                        if($this->debug > 0)
 
540
                        {
 
541
 
 
542
                                //$payload = $payload . "<methodResponse>\n" . $this->serializeDebug();
 
543
                                //$payload = $payload . substr($r->serialize(), 17);
 
544
                                $payload = $payload . $this->serializeDebug($resp_charset);
 
545
                        }
 
546
                        //else
 
547
                        //{
 
548
                        $payload = $payload . $r->serialize($resp_charset);
 
549
                        //}
 
550
 
 
551
 
 
552
                        // if we get a warning/error that has output some text before here, then we cannot
 
553
                        // add a new header. We cannot say we are sending xml, either...
 
554
                        if(!headers_sent())
 
555
                        {
 
556
                                header('Content-Type: '.$r->content_type);
 
557
                                // we do not know if client actually told us an accepted charset, but if he did
 
558
                                // we have to tell him what we did
 
559
                                header("Vary: Accept-Charset");
 
560
 
 
561
                                // http compression of output
 
562
                                if($this->compress_response && function_exists('gzencode') && $resp_encoding != '')
 
563
                                {
 
564
                                        if(strstr($resp_encoding, 'gzip'))
 
565
                                        {
 
566
                                                $payload = gzencode($payload);
 
567
                                                header("Content-Encoding: gzip");
 
568
                                                header("Vary: Accept-Encoding");
 
569
                                        }
 
570
                                        elseif (strstr($resp_encoding, 'deflate'))
 
571
                                        {
 
572
                                                $payload = gzdeflate($payload);
 
573
                                                header("Content-Encoding: deflate");
 
574
                                                header("Vary: Accept-Encoding");
 
575
                                        }
 
576
                                }
 
577
 
 
578
                                header('Content-Length: ' . (int)strlen($payload));
 
579
                        }
 
580
                        else
 
581
                        {
 
582
                                //print "Internal server error: headers sent before PHP response"
 
583
                        }
 
584
 
 
585
                        print $payload;
 
586
                }
 
587
 
 
588
                /**
 
589
                * Add a method to the dispatch map
 
590
                * @param string $methodname the name with which the method will be made available
 
591
                * @param string $function the php function that will get invoked
 
592
                * @param array $sig the array of valid method signatures
 
593
                * @param string $doc method documentation
 
594
                */
 
595
                function add_to_map($methodname,$function,$sig,$doc='')
 
596
                {
 
597
                        $this->dmap[$methodname] = array(
 
598
                                'function'      => $function,
 
599
                                'signature' => $sig,
 
600
                                'docstring' => $doc
 
601
                        );
 
602
                }
 
603
 
 
604
                /**
 
605
                * Verify type and number of parameters received against a list of known signatures
 
606
                * @param array $in array of either xmlrpcval objects or xmlrpc type definitions
 
607
                * @param array $sig array of known signatures to match against
 
608
                * @access private
 
609
                */
 
610
                function verifySignature($in, $sig)
 
611
                {
 
612
                        // check each possible signature in turn
 
613
                        if (is_object($in))
 
614
                        {
 
615
                                $numParams = $in->getNumParams();
 
616
                        }
 
617
                        else
 
618
                        {
 
619
                                $numParams = sizeof($in);
 
620
                        }
 
621
                        foreach($sig as $cursig)
 
622
                        {
 
623
                                if(sizeof($cursig)==$numParams+1)
 
624
                                {
 
625
                                        $itsOK=1;
 
626
                                        for($n=0; $n<$numParams; $n++)
 
627
                                        {
 
628
                                                if (is_object($in))
 
629
                                                {
 
630
                                                        $p=$in->getParam($n);
 
631
                                                        if($p->kindOf() == 'scalar')
 
632
                                                        {
 
633
                                                                $pt=$p->scalartyp();
 
634
                                                        }
 
635
                                                        else
 
636
                                                        {
 
637
                                                                $pt=$p->kindOf();
 
638
                                                        }
 
639
                                                }
 
640
                                                else
 
641
                                                {
 
642
                                                        $pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4...
 
643
                                                }
 
644
 
 
645
                                                // param index is $n+1, as first member of sig is return type
 
646
                                                if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue'])
 
647
                                                {
 
648
                                                        $itsOK=0;
 
649
                                                        $pno=$n+1;
 
650
                                                        $wanted=$cursig[$n+1];
 
651
                                                        $got=$pt;
 
652
                                                        break;
 
653
                                                }
 
654
                                        }
 
655
                                        if($itsOK)
 
656
                                        {
 
657
                                                return array(1,'');
 
658
                                        }
 
659
                                }
 
660
                        }
 
661
                        if(isset($wanted))
 
662
                        {
 
663
                                return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
 
664
                        }
 
665
                        else
 
666
                        {
 
667
                                return array(0, "No method signature matches number of parameters");
 
668
                        }
 
669
                }
 
670
 
 
671
                /**
 
672
                * Parse http headers received along with xmlrpc request. If needed, inflate request
 
673
                * @return null on success or an xmlrpcresp
 
674
                * @access private
 
675
                */
 
676
                function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression)
 
677
                {
 
678
                        // Play nice to PHP 4.0.x: superglobals were not yet invented...
 
679
                        if(!isset($_SERVER))
 
680
                        {
 
681
                                $_SERVER = $GLOBALS['HTTP_SERVER_VARS'];
 
682
                        }
 
683
 
 
684
                        if($this->debug > 1)
 
685
                        {
 
686
                                if(function_exists('getallheaders'))
 
687
                                {
 
688
                                        $this->debugmsg(''); // empty line
 
689
                                        foreach(getallheaders() as $name => $val)
 
690
                                        {
 
691
                                                $this->debugmsg("HEADER: $name: $val");
 
692
                                        }
 
693
                                }
 
694
 
 
695
                        }
 
696
 
 
697
                        if(isset($_SERVER['HTTP_CONTENT_ENCODING']))
 
698
                        {
 
699
                                $content_encoding = $_SERVER['HTTP_CONTENT_ENCODING'];
 
700
                        }
 
701
                        else
 
702
                        {
 
703
                                $content_encoding = '';
 
704
                        }
 
705
 
 
706
                        // check if request body has been compressed and decompress it
 
707
                        if($content_encoding != '' && strlen($data))
 
708
                        {
 
709
                                if($content_encoding == 'deflate' || $content_encoding == 'gzip')
 
710
                                {
 
711
                                        // if decoding works, use it. else assume data wasn't gzencoded
 
712
                                        if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression))
 
713
                                        {
 
714
                                                if($content_encoding == 'deflate' && $degzdata = @gzinflate($data))
 
715
                                                {
 
716
                                                        $data = $degzdata;
 
717
                                                        if($this->debug > 1)
 
718
                                                        {
 
719
                                                                $this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
 
720
                                                        }
 
721
                                                }
 
722
                                                elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
 
723
                                                {
 
724
                                                        $data = $degzdata;
 
725
                                                        if($this->debug > 1)
 
726
                                                                $this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
 
727
                                                }
 
728
                                                else
 
729
                                                {
 
730
                                                        $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']);
 
731
                                                        return $r;
 
732
                                                }
 
733
                                        }
 
734
                                        else
 
735
                                        {
 
736
                                                //error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
 
737
                                                $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']);
 
738
                                                return $r;
 
739
                                        }
 
740
                                }
 
741
                        }
 
742
 
 
743
                        // check if client specified accepted charsets, and if we know how to fulfill
 
744
                        // the request
 
745
                        if ($this->response_charset_encoding == 'auto')
 
746
                        {
 
747
                                $resp_encoding = '';
 
748
                                if (isset($_SERVER['HTTP_ACCEPT_CHARSET']))
 
749
                                {
 
750
                                        // here we should check if we can match the client-requested encoding
 
751
                                        // with the encodings we know we can generate.
 
752
                                        /// @todo we should parse q=0.x preferences instead of getting first charset specified...
 
753
                                        $client_accepted_charsets = split(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']));
 
754
                                        // Give preference to internal encoding
 
755
                                        $known_charsets = array($this->internal_encoding, 'UTF-8', 'ISO-8859-1', 'US-ASCII');
 
756
                                        foreach ($known_charsets as $charset)
 
757
                                        {
 
758
                                                foreach ($client_accepted_charsets as $accepted)
 
759
                                                        if (strpos($accepted, $charset) === 0)
 
760
                                                        {
 
761
                                                                $resp_encoding = $charset;
 
762
                                                                break;
 
763
                                                        }
 
764
                                                if ($resp_encoding)
 
765
                                                        break;
 
766
                                        }
 
767
                                }
 
768
                        }
 
769
                        else
 
770
                        {
 
771
 
 
772
                                $resp_encoding = $this->response_charset_encoding;
 
773
                        }
 
774
 
 
775
                        if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
 
776
                        {
 
777
                                $resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING'];
 
778
                        }
 
779
                        else
 
780
                        {
 
781
                                $resp_compression = '';
 
782
                        }
 
783
 
 
784
                        // 'guestimate' request encoding
 
785
                        /// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check???
 
786
                        $req_encoding = guess_encoding(isset($_SERVER['HTTP_CONTENT_TYPE']) ? $_SERVER['HTTP_CONTENT_TYPE'] : '',
 
787
                                $data);
 
788
 
 
789
                        return null;
 
790
                }
 
791
 
 
792
                /**
 
793
                * Parse an xml chunk containing an xmlrpc request and execute the corresponding
 
794
                * php function registered with the server
 
795
                * @param string $data the xml request
 
796
                * @param string $req_encoding (optional) the charset encoding of the xml request
 
797
                * @return xmlrpcresp
 
798
                * @access private
 
799
                */
 
800
                function parseRequest($data, $req_encoding='')
 
801
                {
 
802
                        // 2005/05/07 commented and moved into caller function code
 
803
                        //if($data=='')
 
804
                        //{
 
805
                        //      $data=$GLOBALS['HTTP_RAW_POST_DATA'];
 
806
                        //}
 
807
 
 
808
 
 
809
                        // G. Giunta 2005/02/13: we do NOT expect to receive html entities
 
810
                        // so we do not try to convert them into xml character entities
 
811
                        //$data = xmlrpc_html_entity_xlate($data);
 
812
 
 
813
                        $GLOBALS['_xh']=array();
 
814
                        $GLOBALS['_xh']['isf']=0;
 
815
                        $GLOBALS['_xh']['isf_reason']='';
 
816
                        $GLOBALS['_xh']['params']=array();
 
817
                        $GLOBALS['_xh']['pt']=array();
 
818
                        $GLOBALS['_xh']['stack']=array();
 
819
                        $GLOBALS['_xh']['valuestack'] = array();
 
820
                        $GLOBALS['_xh']['method']='';
 
821
 
 
822
                        // decompose incoming XML into request structure
 
823
                        if ($req_encoding != '')
 
824
                        {
 
825
                                if (!in_array($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
 
826
                                // the following code might be better for mb_string enabled installs, but
 
827
                                // makes the lib about 200% slower...
 
828
                                //if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
 
829
                                {
 
830
                                        error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding);
 
831
                                        $req_encoding = $GLOBALS['xmlrpc_defencoding'];
 
832
                                }
 
833
                                $parser = xml_parser_create($req_encoding);
 
834
                        }
 
835
                        else
 
836
                        {
 
837
                                $parser = xml_parser_create();
 
838
                        }
 
839
 
 
840
                        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
 
841
                        // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
 
842
                        // the xml parser to give us back data in the expected charset
 
843
                        xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
 
844
 
 
845
                        if ($this->functions_parameters_type == 'phpvals')
 
846
                                xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
 
847
                        else
 
848
                                xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
 
849
                        xml_set_character_data_handler($parser, 'xmlrpc_cd');
 
850
                        xml_set_default_handler($parser, 'xmlrpc_dh');
 
851
                        if(!xml_parse($parser, $data, 1))
 
852
                        {
 
853
                                // return XML error as a faultCode
 
854
                                $r=&new xmlrpcresp(0,
 
855
                                $GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser),
 
856
                                sprintf('XML error: %s at line %d',
 
857
                                        xml_error_string(xml_get_error_code($parser)),
 
858
                                        xml_get_current_line_number($parser)));
 
859
                                xml_parser_free($parser);
 
860
                        }
 
861
                        elseif ($GLOBALS['_xh']['isf'])
 
862
                        {
 
863
                                xml_parser_free($parser);
 
864
                                $r=&new xmlrpcresp(0,
 
865
                                        $GLOBALS['xmlrpcerr']['invalid_request'],
 
866
                                        $GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']);
 
867
                        }
 
868
                        else
 
869
                        {
 
870
                                xml_parser_free($parser);
 
871
                                if ($this->functions_parameters_type == 'phpvals')
 
872
                                {
 
873
                                        if($this->debug > 1)
 
874
                                        {
 
875
                                                $this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++");
 
876
                                        }
 
877
                                        $r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']);
 
878
                                }
 
879
                                else
 
880
                                {
 
881
                                        // build an xmlrpcmsg object with data parsed from xml
 
882
                                        $m=&new xmlrpcmsg($GLOBALS['_xh']['method']);
 
883
                                        // now add parameters in
 
884
                                        for($i=0; $i<sizeof($GLOBALS['_xh']['params']); $i++)
 
885
                                        {
 
886
                                                $m->addParam($GLOBALS['_xh']['params'][$i]);
 
887
                                        }
 
888
 
 
889
                                        if($this->debug > 1)
 
890
                                        {
 
891
                                                $this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++");
 
892
                                        }
 
893
 
 
894
                                        $r = $this->execute($m);
 
895
                                }
 
896
                        }
 
897
                        return $r;
 
898
                }
 
899
 
 
900
                /**
 
901
                * Execute a method invoked by the client, checking parameters used
 
902
                * @param mixed $m either an xmlrpcmsg obj or a method name
 
903
                * @param array $params array with method parameters as php types (if m is method name only)
 
904
                * @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only)
 
905
                * @return xmlrpcresp
 
906
                */
 
907
                function execute($m, $params=null, $paramtypes=null)
 
908
                {
 
909
                        if (is_object($m))
 
910
                        {
 
911
                                $methName = $m->method();
 
912
                        }
 
913
                        else
 
914
                        {
 
915
                                $methName = $m;
 
916
                        }
 
917
                        $sysCall = $this->allow_system_funcs && ereg("^system\.", $methName);
 
918
                        $dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap;
 
919
 
 
920
                        if(!isset($dmap[$methName]['function']))
 
921
                        {
 
922
                                // No such method
 
923
                                return new xmlrpcresp(0,
 
924
                                        $GLOBALS['xmlrpcerr']['unknown_method'],
 
925
                                        $GLOBALS['xmlrpcstr']['unknown_method']);
 
926
                        }
 
927
 
 
928
                        // Check signature
 
929
                        if(isset($dmap[$methName]['signature']))
 
930
                        {
 
931
                                $sig = $dmap[$methName]['signature'];
 
932
                                if (is_object($m))
 
933
                                {
 
934
                                        list($ok, $errstr) = $this->verifySignature($m, $sig);
 
935
                                }
 
936
                                else
 
937
                                {
 
938
                                list($ok, $errstr) = $this->verifySignature($paramtypes, $sig);
 
939
                                }
 
940
                                if(!$ok)
 
941
                                {
 
942
                                        // Didn't match.
 
943
                                        return new xmlrpcresp(
 
944
                                                0,
 
945
                                                $GLOBALS['xmlrpcerr']['incorrect_params'],
 
946
                                                $GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
 
947
                                        );
 
948
                                }
 
949
                        }
 
950
 
 
951
                        $func = $dmap[$methName]['function'];
 
952
                        // let the 'class::function' syntax be accepted in dispatch maps
 
953
                        if(is_string($func) && strpos($func, '::'))
 
954
                        {
 
955
                                $func = explode('::', $func);
 
956
                        }
 
957
                        // verify that function to be invoked is in fact callable
 
958
                        if(!is_callable($func))
 
959
                        {
 
960
                                return new xmlrpcresp(
 
961
                                        0,
 
962
                                        $GLOBALS['xmlrpcerr']['server_error'],
 
963
                                        $GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method"
 
964
                                );
 
965
                        }
 
966
 
 
967
                        // If debug level is 3, we should catch all errors generated during
 
968
                        // processing of user function, and log them as part of response
 
969
                        if($this->debug > 2)
 
970
                        {
 
971
                                $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');
 
972
                        }
 
973
                        if (is_object($m))
 
974
                        {
 
975
                                if($sysCall)
 
976
                                {
 
977
                                        $r = call_user_func($func, $this, $m);
 
978
                                }
 
979
                                else
 
980
                                {
 
981
                                        $r = call_user_func($func, $m);
 
982
                                }
 
983
                        }
 
984
                        else
 
985
                        {
 
986
                                // call a 'plain php' function
 
987
                                if($sysCall)
 
988
                                {
 
989
                                        array_unshift($params, $this);
 
990
                                        $r = call_user_func_array($func,$params);
 
991
                                }
 
992
                                else
 
993
                                {
 
994
                                        $r = call_user_func_array($func, $params);
 
995
                                }
 
996
                                // the return type can be either an xmlrpcresp object or a plain php value...
 
997
                                if (!is_a($r, 'xmlrpcresp'))
 
998
                                {
 
999
                                        // what should we assume here about automatic encoding of datetimes
 
1000
                                        // and php classes instances???
 
1001
                                        $r = new xmlrpcresp(php_xmlrpc_encode($r, array('auto_dates')));
 
1002
                                }
 
1003
                        }
 
1004
                        if($this->debug > 2)
 
1005
                        {
 
1006
                                // note: restore the error handler we found before calling the
 
1007
                                // user func, even if it has been changed inside the func itself
 
1008
                                if($GLOBALS['_xmlrpcs_prev_ehandler'])
 
1009
                                {
 
1010
                                        set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']);
 
1011
                                }
 
1012
                                else
 
1013
                                {
 
1014
                                        restore_error_handler();
 
1015
                                }
 
1016
                        }
 
1017
                        return $r;
 
1018
                }
 
1019
 
 
1020
                /**
 
1021
                * add a string to the 'internal debug message' (separate from 'user debug message')
 
1022
                * @param string $strings
 
1023
                * @access private
 
1024
                */
 
1025
                function debugmsg($string)
 
1026
                {
 
1027
                        $this->debug_info .= $string."\n";
 
1028
                }
 
1029
 
 
1030
                /**
 
1031
                * A debugging routine: just echoes back the input packet as a string value
 
1032
                * DEPRECATED!
 
1033
                */
 
1034
                function echoInput()
 
1035
                {
 
1036
                        $r=&new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string'));
 
1037
                        print $r->serialize();
 
1038
                }
 
1039
        }
 
1040
?>
 
 
b'\\ No newline at end of file'