Passed
Push — php51 ( 29fddb...e2e917 )
by Gaetano
09:58
created

xmlrpc_server::service()   F

Complexity

Conditions 18
Paths 1152

Size

Total Lines 98
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 41
c 0
b 0
f 0
nc 1152
nop 2
dl 0
loc 98
rs 0.7

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// by Edd Dumbill (C) 1999-2002
3
// <[email protected]>
4
5
// Copyright (c) 1999,2000,2002 Edd Dumbill.
6
// All rights reserved.
7
//
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions
10
// are met:
11
//
12
//    * Redistributions of source code must retain the above copyright
13
//      notice, this list of conditions and the following disclaimer.
14
//
15
//    * Redistributions in binary form must reproduce the above
16
//      copyright notice, this list of conditions and the following
17
//      disclaimer in the documentation and/or other materials provided
18
//      with the distribution.
19
//
20
//    * Neither the name of the "XML-RPC for PHP" nor the names of its
21
//      contributors may be used to endorse or promote products derived
22
//      from this software without specific prior written permission.
23
//
24
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35
// OF THE POSSIBILITY OF SUCH DAMAGE.
36
37
	// XML RPC Server class
38
	// requires: xmlrpc.inc
39
40
	$GLOBALS['xmlrpcs_capabilities'] = array(
41
		// xmlrpc spec: always supported
42
		'xmlrpc' => new xmlrpcval(array(
43
			'specUrl' => new xmlrpcval('http://www.xmlrpc.com/spec', 'string'),
44
			'specVersion' => new xmlrpcval(1, 'int')
45
		), 'struct'),
46
		// if we support system.xxx functions, we always support multicall, too...
47
		// Note that, as of 2006/09/17, the following URL does not respond anymore
48
		'system.multicall' => new xmlrpcval(array(
49
			'specUrl' => new xmlrpcval('http://www.xmlrpc.com/discuss/msgReader$1208', 'string'),
50
			'specVersion' => new xmlrpcval(1, 'int')
51
		), 'struct'),
52
		// introspection: version 2! we support 'mixed', too
53
		'introspection' => new xmlrpcval(array(
54
			'specUrl' => new xmlrpcval('http://phpxmlrpc.sourceforge.net/doc-2/ch10.html', 'string'),
55
			'specVersion' => new xmlrpcval(2, 'int')
56
		), 'struct')
57
	);
58
59
	/* Functions that implement system.XXX methods of xmlrpc servers */
60
	$_xmlrpcs_getCapabilities_sig=array(array($GLOBALS['xmlrpcStruct']));
61
	$_xmlrpcs_getCapabilities_doc='This method lists all the capabilites that the XML-RPC server has: the (more or less standard) extensions to the xmlrpc spec that it adheres to';
62
	$_xmlrpcs_getCapabilities_sdoc=array(array('list of capabilities, described as structs with a version number and url for the spec'));
63
	function _xmlrpcs_getCapabilities($server, $m=null)
0 ignored issues
show
Unused Code introduced by
The parameter $m is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

63
	function _xmlrpcs_getCapabilities($server, /** @scrutinizer ignore-unused */ $m=null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $server is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

63
	function _xmlrpcs_getCapabilities(/** @scrutinizer ignore-unused */ $server, $m=null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
64
	{
65
		$outAr = $GLOBALS['xmlrpcs_capabilities'];
66
		// NIL extension
67
		if ($GLOBALS['xmlrpc_null_extension']) {
68
			$outAr['nil'] = new xmlrpcval(array(
69
				'specUrl' => new xmlrpcval('http://www.ontosys.com/xml-rpc/extensions.php', 'string'),
70
				'specVersion' => new xmlrpcval(1, 'int')
71
			), 'struct');
72
		}
73
		return new xmlrpcresp(new xmlrpcval($outAr, 'struct'));
74
	}
75
76
	// listMethods: signature was either a string, or nothing.
77
	// The useless string variant has been removed
78
	$_xmlrpcs_listMethods_sig=array(array($GLOBALS['xmlrpcArray']));
79
	$_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch';
80
	$_xmlrpcs_listMethods_sdoc=array(array('list of method names'));
81
	function _xmlrpcs_listMethods($server, $m=null) // if called in plain php values mode, second param is missing
0 ignored issues
show
Unused Code introduced by
The parameter $m is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

81
	function _xmlrpcs_listMethods($server, /** @scrutinizer ignore-unused */ $m=null) // if called in plain php values mode, second param is missing

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
82
	{
83
84
		$outAr=array();
85
		foreach($server->dmap as $key => $val)
86
		{
87
			$outAr[]=new xmlrpcval($key, 'string');
88
		}
89
		if($server->allow_system_funcs)
90
		{
91
			foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val)
92
			{
93
				$outAr[]=new xmlrpcval($key, 'string');
94
			}
95
		}
96
		return new xmlrpcresp(new xmlrpcval($outAr, 'array'));
97
	}
98
99
	$_xmlrpcs_methodSignature_sig=array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcString']));
100
	$_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)';
101
	$_xmlrpcs_methodSignature_sdoc=array(array('list of known signatures, each sig being an array of xmlrpc type names', 'name of method to be described'));
102
	function _xmlrpcs_methodSignature($server, $m)
103
	{
104
		// let accept as parameter both an xmlrpcval or string
105
		if (is_object($m))
106
		{
107
			$methName=$m->getParam(0);
108
			$methName=$methName->scalarval();
109
		}
110
		else
111
		{
112
			$methName=$m;
113
		}
114
		if(strpos($methName, "system.") === 0)
115
		{
116
			$dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
0 ignored issues
show
Unused Code introduced by
The assignment to $sysCall is dead and can be removed.
Loading history...
117
		}
118
		else
119
		{
120
			$dmap=$server->dmap; $sysCall=0;
121
		}
122
		if(isset($dmap[$methName]))
123
		{
124
			if(isset($dmap[$methName]['signature']))
125
			{
126
				$sigs=array();
127
				foreach($dmap[$methName]['signature'] as $inSig)
128
				{
129
					$cursig=array();
130
					foreach($inSig as $sig)
131
					{
132
						$cursig[]=new xmlrpcval($sig, 'string');
133
					}
134
					$sigs[]=new xmlrpcval($cursig, 'array');
135
				}
136
				$r=new xmlrpcresp(new xmlrpcval($sigs, 'array'));
137
			}
138
			else
139
			{
140
				// NB: according to the official docs, we should be returning a
141
				// "none-array" here, which means not-an-array
142
				$r=new xmlrpcresp(new xmlrpcval('undef', 'string'));
143
			}
144
		}
145
		else
146
		{
147
			$r=new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
148
		}
149
		return $r;
150
	}
151
152
	$_xmlrpcs_methodHelp_sig=array(array($GLOBALS['xmlrpcString'], $GLOBALS['xmlrpcString']));
153
	$_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string';
154
	$_xmlrpcs_methodHelp_sdoc=array(array('method description', 'name of the method to be described'));
155
	function _xmlrpcs_methodHelp($server, $m)
156
	{
157
		// let accept as parameter both an xmlrpcval or string
158
		if (is_object($m))
159
		{
160
			$methName=$m->getParam(0);
161
			$methName=$methName->scalarval();
162
		}
163
		else
164
		{
165
			$methName=$m;
166
		}
167
		if(strpos($methName, "system.") === 0)
168
		{
169
			$dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
0 ignored issues
show
Unused Code introduced by
The assignment to $sysCall is dead and can be removed.
Loading history...
170
		}
171
		else
172
		{
173
			$dmap=$server->dmap; $sysCall=0;
174
		}
175
		if(isset($dmap[$methName]))
176
		{
177
			if(isset($dmap[$methName]['docstring']))
178
			{
179
				$r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
0 ignored issues
show
Bug introduced by
'string' of type string is incompatible with the type integer expected by parameter $fcode of xmlrpcresp::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

179
				$r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), /** @scrutinizer ignore-type */ 'string');
Loading history...
180
			}
181
			else
182
			{
183
				$r=new xmlrpcresp(new xmlrpcval('', 'string'));
184
			}
185
		}
186
		else
187
		{
188
			$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
189
		}
190
		return $r;
191
	}
192
193
	$_xmlrpcs_multicall_sig = array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcArray']));
194
	$_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details';
195
	$_xmlrpcs_multicall_sdoc = array(array('list of response structs, where each struct has the usual members', 'list of calls, with each call being represented as a struct, with members "methodname" and "params"'));
196
	function _xmlrpcs_multicall_error($err)
197
	{
198
		if(is_string($err))
199
		{
200
			$str = $GLOBALS['xmlrpcstr']["multicall_${err}"];
201
			$code = $GLOBALS['xmlrpcerr']["multicall_${err}"];
202
		}
203
		else
204
		{
205
			$code = $err->faultCode();
206
			$str = $err->faultString();
207
		}
208
		$struct = array();
209
		$struct['faultCode'] = new xmlrpcval($code, 'int');
210
		$struct['faultString'] = new xmlrpcval($str, 'string');
211
		return new xmlrpcval($struct, 'struct');
212
	}
213
214
	function _xmlrpcs_multicall_do_call($server, $call)
215
	{
216
		if($call->kindOf() != 'struct')
217
		{
218
			return _xmlrpcs_multicall_error('notstruct');
219
		}
220
		$methName = @$call->structmem('methodName');
221
		if(!$methName)
222
		{
223
			return _xmlrpcs_multicall_error('nomethod');
224
		}
225
		if($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
226
		{
227
			return _xmlrpcs_multicall_error('notstring');
228
		}
229
		if($methName->scalarval() == 'system.multicall')
230
		{
231
			return _xmlrpcs_multicall_error('recursion');
232
		}
233
234
		$params = @$call->structmem('params');
235
		if(!$params)
236
		{
237
			return _xmlrpcs_multicall_error('noparams');
238
		}
239
		if($params->kindOf() != 'array')
240
		{
241
			return _xmlrpcs_multicall_error('notarray');
242
		}
243
		$numParams = $params->arraysize();
244
245
		$msg = new xmlrpcmsg($methName->scalarval());
246
		for($i = 0; $i < $numParams; $i++)
247
		{
248
			if(!$msg->addParam($params->arraymem($i)))
249
			{
250
				$i++;
251
				return _xmlrpcs_multicall_error(new xmlrpcresp(0,
252
					$GLOBALS['xmlrpcerr']['incorrect_params'],
253
					$GLOBALS['xmlrpcstr']['incorrect_params'] . ": probable xml error in param " . $i));
254
			}
255
		}
256
257
		$result = $server->execute($msg);
258
259
		if($result->faultCode() != 0)
260
		{
261
			return _xmlrpcs_multicall_error($result);		// Method returned fault.
262
		}
263
264
		return new xmlrpcval(array($result->value()), 'array');
265
	}
266
267
	function _xmlrpcs_multicall_do_call_phpvals($server, $call)
268
	{
269
		if(!is_array($call))
270
		{
271
			return _xmlrpcs_multicall_error('notstruct');
272
		}
273
		if(!array_key_exists('methodName', $call))
274
		{
275
			return _xmlrpcs_multicall_error('nomethod');
276
		}
277
		if (!is_string($call['methodName']))
278
		{
279
			return _xmlrpcs_multicall_error('notstring');
280
		}
281
		if($call['methodName'] == 'system.multicall')
282
		{
283
			return _xmlrpcs_multicall_error('recursion');
284
		}
285
		if(!array_key_exists('params', $call))
286
		{
287
			return _xmlrpcs_multicall_error('noparams');
288
		}
289
		if(!is_array($call['params']))
290
		{
291
			return _xmlrpcs_multicall_error('notarray');
292
		}
293
294
		// this is a real dirty and simplistic hack, since we might have received a
295
		// base64 or datetime values, but they will be listed as strings here...
296
		$numParams = count($call['params']);
0 ignored issues
show
Unused Code introduced by
The assignment to $numParams is dead and can be removed.
Loading history...
297
		$pt = array();
298
		foreach($call['params'] as $val)
299
			$pt[] = php_2_xmlrpc_type(gettype($val));
300
301
		$result = $server->execute($call['methodName'], $call['params'], $pt);
302
303
		if($result->faultCode() != 0)
304
		{
305
			return _xmlrpcs_multicall_error($result);		// Method returned fault.
306
		}
307
308
		return new xmlrpcval(array($result->value()), 'array');
309
	}
310
311
	function _xmlrpcs_multicall($server, $m)
312
	{
313
		$result = array();
314
		// let accept a plain list of php parameters, beside a single xmlrpc msg object
315
		if (is_object($m))
316
		{
317
			$calls = $m->getParam(0);
318
			$numCalls = $calls->arraysize();
319
			for($i = 0; $i < $numCalls; $i++)
320
			{
321
				$call = $calls->arraymem($i);
322
				$result[$i] = _xmlrpcs_multicall_do_call($server, $call);
323
			}
324
		}
325
		else
326
		{
327
			$numCalls=count($m);
328
			for($i = 0; $i < $numCalls; $i++)
329
			{
330
				$result[$i] = _xmlrpcs_multicall_do_call_phpvals($server, $m[$i]);
331
			}
332
		}
333
334
		return new xmlrpcresp(new xmlrpcval($result, 'array'));
335
	}
336
337
	$GLOBALS['_xmlrpcs_dmap']=array(
338
		'system.listMethods' => array(
339
			'function' => '_xmlrpcs_listMethods',
340
			'signature' => $_xmlrpcs_listMethods_sig,
341
			'docstring' => $_xmlrpcs_listMethods_doc,
342
			'signature_docs' => $_xmlrpcs_listMethods_sdoc),
343
		'system.methodHelp' => array(
344
			'function' => '_xmlrpcs_methodHelp',
345
			'signature' => $_xmlrpcs_methodHelp_sig,
346
			'docstring' => $_xmlrpcs_methodHelp_doc,
347
			'signature_docs' => $_xmlrpcs_methodHelp_sdoc),
348
		'system.methodSignature' => array(
349
			'function' => '_xmlrpcs_methodSignature',
350
			'signature' => $_xmlrpcs_methodSignature_sig,
351
			'docstring' => $_xmlrpcs_methodSignature_doc,
352
			'signature_docs' => $_xmlrpcs_methodSignature_sdoc),
353
		'system.multicall' => array(
354
			'function' => '_xmlrpcs_multicall',
355
			'signature' => $_xmlrpcs_multicall_sig,
356
			'docstring' => $_xmlrpcs_multicall_doc,
357
			'signature_docs' => $_xmlrpcs_multicall_sdoc),
358
		'system.getCapabilities' => array(
359
			'function' => '_xmlrpcs_getCapabilities',
360
			'signature' => $_xmlrpcs_getCapabilities_sig,
361
			'docstring' => $_xmlrpcs_getCapabilities_doc,
362
			'signature_docs' => $_xmlrpcs_getCapabilities_sdoc)
363
	);
364
365
	$GLOBALS['_xmlrpcs_occurred_errors'] = '';
366
	$GLOBALS['_xmlrpcs_prev_ehandler'] = '';
367
368
	/**
369
	* Error handler used to track errors that occur during server-side execution of PHP code.
370
	* This allows to report back to the client whether an internal error has occurred or not
371
	* using an xmlrpc response object, instead of letting the client deal with the html junk
372
	* that a PHP execution error on the server generally entails.
373
	*
374
	* NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors.
375
	*
376
	*/
377
	function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null)
378
	{
379
		// obey the @ protocol
380
		if (error_reporting() == 0)
381
			return;
382
383
		//if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING)
384
		if($errcode != E_STRICT)
385
		{
386
			$GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n";
387
		}
388
		// Try to avoid as much as possible disruption to the previous error handling
389
		// mechanism in place
390
		if($GLOBALS['_xmlrpcs_prev_ehandler'] == '')
391
		{
392
			// The previous error handler was the default: all we should do is log error
393
			// to the default error log (if level high enough)
394
			if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode))
395
			{
396
				error_log($errstring);
397
			}
398
		}
399
		else
400
		{
401
			// Pass control on to previous error handler, trying to avoid loops...
402
			if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler')
403
			{
404
				// NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers
405
				if(is_array($GLOBALS['_xmlrpcs_prev_ehandler']))
406
				{
407
					// the following works both with static class methods and plain object methods as error handler
408
					call_user_func_array($GLOBALS['_xmlrpcs_prev_ehandler'], array($errcode, $errstring, $filename, $lineno, $context));
409
				}
410
				else
411
				{
412
					$GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context);
413
				}
414
			}
415
		}
416
	}
417
418
	$GLOBALS['_xmlrpc_debuginfo']='';
419
420
	/**
421
	* Add a string to the debug info that can be later seralized by the server
422
	* as part of the response message.
423
	* Note that for best compatibility, the debug string should be encoded using
424
	* the $GLOBALS['xmlrpc_internalencoding'] character set.
425
	* @param string $m
426
	* @access public
427
	*/
428
	function xmlrpc_debugmsg($m)
429
	{
430
		$GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
431
	}
432
433
	class xmlrpc_server
434
	{
435
		/**
436
		* Array defining php functions exposed as xmlrpc methods by this server
437
		* @access private
438
		*/
439
		var $dmap=array();
440
		/**
441
		* Defines how functions in dmap will be invoked: either using an xmlrpc msg object
442
		* or plain php values.
443
		* valid strings are 'xmlrpcvals', 'phpvals' or 'epivals'
444
		*/
445
		var $functions_parameters_type='xmlrpcvals';
446
		/**
447
		* Option used for fine-tuning the encoding the php values returned from
448
		* functions registered in the dispatch map when the functions_parameters_types
449
		* member is set to 'phpvals'
450
		* @see php_xmlrpc_encode for a list of values
451
		*/
452
		var $phpvals_encoding_options = array( 'auto_dates' );
453
		/// controls whether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3
454
		var $debug = 1;
455
		/**
456
		* Controls behaviour of server when invoked user function throws an exception:
457
		* 0 = catch it and return an 'internal error' xmlrpc response (default)
458
		* 1 = catch it and return an xmlrpc response with the error corresponding to the exception
459
		* 2 = allow the exception to float to the upper layers
460
		*/
461
		var $exception_handling = 0;
462
		/**
463
		* When set to true, it will enable HTTP compression of the response, in case
464
		* the client has declared its support for compression in the request.
465
		*/
466
		var $compress_response = false;
467
		/**
468
		* List of http compression methods accepted by the server for requests.
469
		* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
470
		*/
471
		var $accepted_compression = array();
472
		/// shall we serve calls to system.* methods?
473
		var $allow_system_funcs = true;
474
		/// list of charset encodings natively accepted for requests
475
		var $accepted_charset_encodings = array();
476
		/**
477
		* charset encoding to be used for response.
478
		* NB: if we can, we will convert the generated response from internal_encoding to the intended one.
479
		* can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled),
480
		* null (leave unspecified in response, convert output stream to US_ASCII),
481
		* 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed),
482
		* 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).
483
		* NB: pretty dangerous if you accept every charset and do not have mbstring enabled)
484
		*/
485
		var $response_charset_encoding = '';
486
		/**
487
		* Storage for internal debug info
488
		* @access private
489
		*/
490
		var $debug_info = '';
491
		/**
492
		* Extra data passed at runtime to method handling functions. Used only by EPI layer
493
		*/
494
		var $user_data = null;
495
496
		/**
497
		* @param array $dispmap the dispatch map with definition of exposed services
498
		* @param boolean $servicenow set to false to prevent the server from running upon construction
499
		*/
500
		function __construct($dispMap=null, $serviceNow=true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
501
		{
502
			// if ZLIB is enabled, let the server by default accept compressed requests,
503
			// and compress responses sent to clients that support them
504
			if(function_exists('gzinflate'))
505
			{
506
				$this->accepted_compression = array('gzip', 'deflate');
507
				$this->compress_response = true;
508
			}
509
510
			// by default the xml parser can support these 3 charset encodings
511
			$this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
512
513
			// dispMap is a dispatch array of methods
514
			// mapped to function names and signatures
515
			// if a method
516
			// doesn't appear in the map then an unknown
517
			// method error is generated
518
			/* milosch - changed to make passing dispMap optional.
519
			 * instead, you can use the class add_to_map() function
520
			 * to add functions manually (borrowed from SOAPX4)
521
			 */
522
			if($dispMap)
523
			{
524
				$this->dmap = $dispMap;
525
				if($serviceNow)
526
				{
527
					$this->service();
528
				}
529
			}
530
		}
531
532
		/**
533
		* @deprecated
534
		*/
535
		function xmlrpc_client($dispMap=null, $serviceNow=true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
536
		{
537
			self::__construct($dispMap, $serviceNow);
0 ignored issues
show
Bug Best Practice introduced by
The method xmlrpc_server::__construct() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

537
			self::/** @scrutinizer ignore-call */ __construct($dispMap, $serviceNow);
Loading history...
538
		}
539
540
		/**
541
		* Set debug level of server.
542
		* @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments)
543
		* 0 = no debug info,
544
		* 1 = msgs set from user with debugmsg(),
545
		* 2 = add complete xmlrpc request (headers and body),
546
		* 3 = add also all processing warnings happened during method processing
547
		* (NB: this involves setting a custom error handler, and might interfere
548
		* with the standard processing of the php function exposed as method. In
549
		* particular, triggering an USER_ERROR level error will not halt script
550
		* execution anymore, but just end up logged in the xmlrpc response)
551
		* Note that info added at level 2 and 3 will be base64 encoded
552
		* @access public
553
		*/
554
		function setDebug($in)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
555
		{
556
			$this->debug=$in;
557
		}
558
559
		/**
560
		* Return a string with the serialized representation of all debug info
561
		* @param string $charset_encoding the target charset encoding for the serialization
562
		* @return string an XML comment (or two)
563
		*/
564
		function serializeDebug($charset_encoding='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
565
		{
566
			// Tough encoding problem: which internal charset should we assume for debug info?
567
			// It might contain a copy of raw data received from client, ie with unknown encoding,
568
			// intermixed with php generated data and user generated data...
569
			// so we split it: system debug is base 64 encoded,
570
			// user debug info should be encoded by the end user using the INTERNAL_ENCODING
571
			$out = '';
572
			if ($this->debug_info != '')
573
			{
574
				$out .= "<!-- SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n-->\n";
575
			}
576
			if($GLOBALS['_xmlrpc_debuginfo']!='')
577
			{
578
579
				$out .= "<!-- DEBUG INFO:\n" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n";
580
				// NB: a better solution MIGHT be to use CDATA, but we need to insert it
581
				// into return payload AFTER the beginning tag
582
				//$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n";
583
			}
584
			return $out;
585
		}
586
587
		/**
588
		* Execute the xmlrpc request, printing the response
589
		* @param string $data the request body. If null, the http POST request will be examined
590
		* @return xmlrpcresp the response object (usually not used by caller...)
591
		* @access public
592
		*/
593
		function service($data=null, $return_payload=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
594
		{
595
			if ($data === null)
596
			{
597
				// workaround for a known bug in php ver. 5.2.2 that broke $HTTP_RAW_POST_DATA
598
				$data = file_get_contents('php://input');
599
			}
600
			$raw_data = $data;
601
602
			// reset internal debug info
603
			$this->debug_info = '';
604
605
			// Echo back what we received, before parsing it
606
			if($this->debug > 1)
607
			{
608
				$this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++");
609
			}
610
611
			$r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding);
612
			if (!$r)
613
			{
614
				$r=$this->parseRequest($data, $req_charset);
615
			}
616
617
			// save full body of request into response, for more debugging usages
618
			$r->raw_data = $raw_data;
619
620
			if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors'])
621
			{
622
				$this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" .
623
					$GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++");
624
			}
625
626
			$payload=$this->xml_header($resp_charset);
627
			if($this->debug > 0)
628
			{
629
				$payload = $payload . $this->serializeDebug($resp_charset);
630
			}
631
632
			// G. Giunta 2006-01-27: do not create response serialization if it has
633
			// already happened. Helps building json magic
634
			if (empty($r->payload))
635
			{
636
				$r->serialize($resp_charset);
637
			}
638
			$payload = $payload . $r->payload;
639
640
			if ($return_payload)
641
			{
642
				return $payload;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $payload returns the type string which is incompatible with the documented return type xmlrpcresp.
Loading history...
643
			}
644
645
			// if we get a warning/error that has output some text before here, then we cannot
646
			// add a new header. We cannot say we are sending xml, either...
647
			if(!headers_sent())
648
			{
649
				header('Content-Type: '.$r->content_type);
650
				// we do not know if client actually told us an accepted charset, but if he did
651
				// we have to tell him what we did
652
				header("Vary: Accept-Charset");
653
654
				// http compression of output: only
655
				// if we can do it, and we want to do it, and client asked us to,
656
				// and php ini settings do not force it already
657
				$php_no_self_compress = !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler');
658
				if($this->compress_response && function_exists('gzencode') && $resp_encoding != ''
659
					&& $php_no_self_compress)
660
				{
661
					if(strpos($resp_encoding, 'gzip') !== false)
662
					{
663
						$payload = gzencode($payload);
664
						header("Content-Encoding: gzip");
665
						header("Vary: Accept-Encoding");
666
					}
667
					elseif (strpos($resp_encoding, 'deflate') !== false)
668
					{
669
						$payload = gzcompress($payload);
670
						header("Content-Encoding: deflate");
671
						header("Vary: Accept-Encoding");
672
					}
673
				}
674
675
				// do not ouput content-length header if php is compressing output for us:
676
				// it will mess up measurements
677
				if($php_no_self_compress)
678
				{
679
					header('Content-Length: ' . (int)strlen($payload));
680
				}
681
			}
682
			else
683
			{
684
				error_log('XML-RPC: '.__METHOD__.': http headers already sent before response is fully generated. Check for php warning or error messages');
685
			}
686
687
			print $payload;
688
689
			// return request, in case subclasses want it
690
			return $r;
691
		}
692
693
		/**
694
		* Add a method to the dispatch map
695
		* @param string $methodname the name with which the method will be made available
696
		* @param string $function the php function that will get invoked
697
		* @param array $sig the array of valid method signatures
698
		* @param string $doc method documentation
699
		* @param array $sigdoc the array of valid method signatures docs (one string per param, one for return type)
700
		* @access public
701
		*/
702
		function add_to_map($methodname,$function,$sig=null,$doc=false,$sigdoc=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
703
		{
704
			$this->dmap[$methodname] = array(
705
				'function'	=> $function,
706
				'docstring' => $doc
707
			);
708
			if ($sig)
709
			{
710
				$this->dmap[$methodname]['signature'] = $sig;
711
			}
712
			if ($sigdoc)
713
			{
714
				$this->dmap[$methodname]['signature_docs'] = $sigdoc;
715
			}
716
		}
717
718
		/**
719
		* Verify type and number of parameters received against a list of known signatures
720
		* @param array $in array of either xmlrpcval objects or xmlrpc type definitions
721
		* @param array $sig array of known signatures to match against
722
		* @return array
723
		* @access private
724
		*/
725
		function verifySignature($in, $sig)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
726
		{
727
			// check each possible signature in turn
728
			if (is_object($in))
0 ignored issues
show
introduced by
The condition is_object($in) is always false.
Loading history...
729
			{
730
				$numParams = $in->getNumParams();
731
			}
732
			else
733
			{
734
				$numParams = count($in);
735
			}
736
			foreach($sig as $cursig)
737
			{
738
				if(count($cursig)==$numParams+1)
739
				{
740
					$itsOK=1;
741
					for($n=0; $n<$numParams; $n++)
742
					{
743
						if (is_object($in))
744
						{
745
							$p=$in->getParam($n);
746
							if($p->kindOf() == 'scalar')
747
							{
748
								$pt=$p->scalartyp();
749
							}
750
							else
751
							{
752
								$pt=$p->kindOf();
753
							}
754
						}
755
						else
756
						{
757
							$pt= $in[$n] == 'i4' ? 'int' : strtolower($in[$n]); // dispatch maps never use i4...
758
						}
759
760
						// param index is $n+1, as first member of sig is return type
761
						if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue'])
762
						{
763
							$itsOK=0;
764
							$pno=$n+1;
765
							$wanted=$cursig[$n+1];
766
							$got=$pt;
767
							break;
768
						}
769
					}
770
					if($itsOK)
771
					{
772
						return array(1,'');
773
					}
774
				}
775
			}
776
			if(isset($wanted))
777
			{
778
				return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pno does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $got does not seem to be defined for all execution paths leading up to this point.
Loading history...
779
			}
780
			else
781
			{
782
				return array(0, "No method signature matches number of parameters");
783
			}
784
		}
785
786
		/**
787
		* Parse http headers received along with xmlrpc request. If needed, inflate request
788
		* @return mixed null on success or an xmlrpcresp
789
		* @access private
790
		*/
791
		function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression)
792
		{
793
			// check if $_SERVER is populated: it might have been disabled via ini file
794
			// (this is true even when in CLI mode)
795
			if (count($_SERVER) == 0)
796
			{
797
				error_log('XML-RPC: '.__METHOD__.': cannot parse request headers as $_SERVER is not populated');
798
			}
799
800
			if($this->debug > 1)
801
			{
802
				if(function_exists('getallheaders'))
803
				{
804
					$this->debugmsg(''); // empty line
805
					foreach(getallheaders() as $name => $val)
806
					{
807
						$this->debugmsg("HEADER: $name: $val");
808
					}
809
				}
810
811
			}
812
813
			if(isset($_SERVER['HTTP_CONTENT_ENCODING']))
814
			{
815
				$content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']);
816
			}
817
			else
818
			{
819
				$content_encoding = '';
820
			}
821
822
			// check if request body has been compressed and decompress it
823
			if($content_encoding != '' && strlen($data))
824
			{
825
				if($content_encoding == 'deflate' || $content_encoding == 'gzip')
826
				{
827
					// if decoding works, use it. else assume data wasn't gzencoded
828
					if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression))
829
					{
830
						if($content_encoding == 'deflate' && $degzdata = @gzuncompress($data))
831
						{
832
							$data = $degzdata;
833
							if($this->debug > 1)
834
							{
835
								$this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
836
							}
837
						}
838
						elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
839
						{
840
							$data = $degzdata;
841
							if($this->debug > 1)
842
								$this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
843
						}
844
						else
845
						{
846
							$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']);
847
							return $r;
848
						}
849
					}
850
					else
851
					{
852
						//error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
853
						$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']);
854
						return $r;
855
					}
856
				}
857
			}
858
859
			// check if client specified accepted charsets, and if we know how to fulfill
860
			// the request
861
			if ($this->response_charset_encoding == 'auto')
862
			{
863
				$resp_encoding = '';
864
				if (isset($_SERVER['HTTP_ACCEPT_CHARSET']))
865
				{
866
					// here we should check if we can match the client-requested encoding
867
					// with the encodings we know we can generate.
868
					/// @todo we should parse q=0.x preferences instead of getting first charset specified...
869
					$client_accepted_charsets = explode(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']));
870
					// Give preference to internal encoding
871
					$known_charsets = array($GLOBALS['xmlrpc_internalencoding'], 'UTF-8', 'ISO-8859-1', 'US-ASCII');
872
					foreach ($known_charsets as $charset)
873
					{
874
						foreach ($client_accepted_charsets as $accepted)
875
							if (strpos($accepted, $charset) === 0)
876
							{
877
								$resp_encoding = $charset;
878
								break;
879
							}
880
						if ($resp_encoding)
881
							break;
882
					}
883
				}
884
			}
885
			else
886
			{
887
				$resp_encoding = $this->response_charset_encoding;
888
			}
889
890
			if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
891
			{
892
				$resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING'];
893
			}
894
			else
895
			{
896
				$resp_compression = '';
897
			}
898
899
			// 'guestimate' request encoding
900
			/// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check???
901
			$req_encoding = guess_encoding(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '',
902
				$data);
903
904
			return null;
905
		}
906
907
		/**
908
		* Parse an xml chunk containing an xmlrpc request and execute the corresponding
909
		* php function registered with the server
910
		* @param string $data the xml request
911
		* @param string $req_encoding (optional) the charset encoding of the xml request
912
		* @return xmlrpcresp
913
		* @access private
914
		*/
915
		function parseRequest($data, $req_encoding='')
916
		{
917
			// 2005/05/07 commented and moved into caller function code
918
			//if($data=='')
919
			//{
920
			//	$data=$GLOBALS['HTTP_RAW_POST_DATA'];
921
			//}
922
923
			// G. Giunta 2005/02/13: we do NOT expect to receive html entities
924
			// so we do not try to convert them into xml character entities
925
			//$data = xmlrpc_html_entity_xlate($data);
926
927
			$GLOBALS['_xh']=array();
928
			$GLOBALS['_xh']['ac']='';
929
			$GLOBALS['_xh']['stack']=array();
930
			$GLOBALS['_xh']['valuestack'] = array();
931
			$GLOBALS['_xh']['params']=array();
932
			$GLOBALS['_xh']['pt']=array();
933
			$GLOBALS['_xh']['isf']=0;
934
			$GLOBALS['_xh']['isf_reason']='';
935
			$GLOBALS['_xh']['method']=false; // so we can check later if we got a methodname or not
936
			$GLOBALS['_xh']['rt']='';
937
938
			// decompose incoming XML into request structure
939
940
			if ($req_encoding != '')
941
			{
942
				// Since parsing will fail if charset is not specified in the xml prologue,
943
				// the encoding is not UTF8 and there are non-ascii chars in the text, we try to work round that...
944
				// The following code might be better for mb_string enabled installs, but
945
				// makes the lib about 200% slower...
946
				//if (!is_valid_charset($req_encoding, array('UTF-8')))
947
				if (!in_array($req_encoding, array('UTF-8', 'US-ASCII')) && !has_encoding($data)) {
948
					if ($req_encoding == 'ISO-8859-1') {
949
						$data = utf8_encode($data);
950
					} else {
951
						if (extension_loaded('mbstring')) {
952
							$data = mb_convert_encoding($data, 'UTF-8', $req_encoding);
953
						} else {
954
							error_log('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of received request: ' . $req_encoding);
955
						}
956
					}
957
				}
958
			}
959
960
			$parser = xml_parser_create();
961
			xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
962
			// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
963
			// the xml parser to give us back data in the expected charset
964
			// What if internal encoding is not in one of the 3 allowed?
965
			// we use the broadest one, ie. utf8
966
			// This allows to send data which is native in various charset,
967
			// by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding
968
			if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
969
			{
970
				xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
971
			}
972
			else
973
			{
974
				xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
975
			}
976
977
			if ($this->functions_parameters_type != 'xmlrpcvals')
978
				xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
979
			else
980
				xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
981
			xml_set_character_data_handler($parser, 'xmlrpc_cd');
982
			xml_set_default_handler($parser, 'xmlrpc_dh');
983
			if(!xml_parse($parser, $data, 1))
984
			{
985
				// return XML error as a faultCode
986
				$r=new xmlrpcresp(0,
987
				$GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser),
988
				sprintf('XML error: %s at line %d, column %d',
989
					xml_error_string(xml_get_error_code($parser)),
990
					xml_get_current_line_number($parser), xml_get_current_column_number($parser)));
991
				xml_parser_free($parser);
992
			}
993
			elseif ($GLOBALS['_xh']['isf'])
994
			{
995
				xml_parser_free($parser);
996
				$r=new xmlrpcresp(0,
997
					$GLOBALS['xmlrpcerr']['invalid_request'],
998
					$GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']);
999
			}
1000
			else
1001
			{
1002
				xml_parser_free($parser);
1003
				// small layering violation in favor of speed and memory usage:
1004
				// we should allow the 'execute' method handle this, but in the
1005
				// most common scenario (xmlrpcvals type server with some methods
1006
				// registered as phpvals) that would mean a useless encode+decode pass
1007
				if ($this->functions_parameters_type != 'xmlrpcvals' || (isset($this->dmap[$GLOBALS['_xh']['method']]['parameters_type']) && ($this->dmap[$GLOBALS['_xh']['method']]['parameters_type'] == 'phpvals')))
1008
				{
1009
					if($this->debug > 1)
1010
					{
1011
						$this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++");
1012
					}
1013
					$r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']);
1014
				}
1015
				else
1016
				{
1017
					// build an xmlrpcmsg object with data parsed from xml
1018
					$m=new xmlrpcmsg($GLOBALS['_xh']['method']);
1019
					// now add parameters in
1020
					for($i=0; $i<count($GLOBALS['_xh']['params']); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1021
					{
1022
						$m->addParam($GLOBALS['_xh']['params'][$i]);
1023
					}
1024
1025
					if($this->debug > 1)
1026
					{
1027
						$this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++");
1028
					}
1029
					$r = $this->execute($m);
1030
				}
1031
			}
1032
			return $r;
1033
		}
1034
1035
		/**
1036
		* Execute a method invoked by the client, checking parameters used
1037
		* @param mixed $m either an xmlrpcmsg obj or a method name
1038
		* @param array $params array with method parameters as php types (if m is method name only)
1039
		* @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only)
1040
		* @return xmlrpcresp
1041
		* @access private
1042
		*/
1043
		function execute($m, $params=null, $paramtypes=null)
1044
		{
1045
			if (is_object($m))
1046
			{
1047
				$methName = $m->method();
1048
			}
1049
			else
1050
			{
1051
				$methName = $m;
1052
			}
1053
			$sysCall = $this->allow_system_funcs && (strpos($methName, "system.") === 0);
1054
			$dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap;
1055
1056
			if(!isset($dmap[$methName]['function']))
1057
			{
1058
				// No such method
1059
				return new xmlrpcresp(0,
1060
					$GLOBALS['xmlrpcerr']['unknown_method'],
1061
					$GLOBALS['xmlrpcstr']['unknown_method']);
1062
			}
1063
1064
			// Check signature
1065
			if(isset($dmap[$methName]['signature']))
1066
			{
1067
				$sig = $dmap[$methName]['signature'];
1068
				if (is_object($m))
1069
				{
1070
					list($ok, $errstr) = $this->verifySignature($m, $sig);
0 ignored issues
show
Bug introduced by
$m of type object is incompatible with the type array expected by parameter $in of xmlrpc_server::verifySignature(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1070
					list($ok, $errstr) = $this->verifySignature(/** @scrutinizer ignore-type */ $m, $sig);
Loading history...
1071
				}
1072
				else
1073
				{
1074
					list($ok, $errstr) = $this->verifySignature($paramtypes, $sig);
1075
				}
1076
				if(!$ok)
1077
				{
1078
					// Didn't match.
1079
					return new xmlrpcresp(
1080
						0,
1081
						$GLOBALS['xmlrpcerr']['incorrect_params'],
1082
						$GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
1083
					);
1084
				}
1085
			}
1086
1087
			$func = $dmap[$methName]['function'];
1088
			// let the 'class::function' syntax be accepted in dispatch maps
1089
			if(is_string($func) && strpos($func, '::'))
1090
			{
1091
				$func = explode('::', $func);
1092
			}
1093
			// verify that function to be invoked is in fact callable
1094
			if(!is_callable($func))
1095
			{
1096
				error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler is not callable");
1097
				return new xmlrpcresp(
1098
					0,
1099
					$GLOBALS['xmlrpcerr']['server_error'],
1100
					$GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method"
1101
				);
1102
			}
1103
1104
			// If debug level is 3, we should catch all errors generated during
1105
			// processing of user function, and log them as part of response
1106
			if($this->debug > 2)
1107
			{
1108
				$GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');
1109
			}
1110
			try
1111
			{
1112
				// Allow mixed-convention servers
1113
				if (is_object($m))
1114
				{
1115
					if($sysCall)
1116
					{
1117
						$r = call_user_func($func, $this, $m);
1118
					}
1119
					else
1120
					{
1121
						$r = call_user_func($func, $m);
1122
					}
1123
					if (!is_a($r, 'xmlrpcresp'))
1124
					{
1125
						error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpcresp object");
1126
						if (is_a($r, 'xmlrpcval'))
1127
						{
1128
							$r = new xmlrpcresp($r);
1129
						}
1130
						else
1131
						{
1132
							$r = new xmlrpcresp(
1133
								0,
1134
								$GLOBALS['xmlrpcerr']['server_error'],
1135
								$GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object"
1136
							);
1137
						}
1138
					}
1139
				}
1140
				else
1141
				{
1142
					// call a 'plain php' function
1143
					if($sysCall)
1144
					{
1145
						array_unshift($params, $this);
0 ignored issues
show
Bug introduced by
It seems like $params can also be of type null; however, parameter $array of array_unshift() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1145
						array_unshift(/** @scrutinizer ignore-type */ $params, $this);
Loading history...
1146
						$r = call_user_func_array($func, $params);
1147
					}
1148
					else
1149
					{
1150
						// 3rd API convention for method-handling functions: EPI-style
1151
						if ($this->functions_parameters_type == 'epivals')
1152
						{
1153
							$r = call_user_func_array($func, array($methName, $params, $this->user_data));
1154
							// mimic EPI behaviour: if we get an array that looks like an error, make it
1155
							// an eror response
1156
							if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))
1157
							{
1158
								$r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);
1159
							}
1160
							else
1161
							{
1162
								// functions using EPI api should NOT return resp objects,
1163
								// so make sure we encode the return type correctly
1164
								$r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api')));
1165
							}
1166
						}
1167
						else
1168
						{
1169
							$r = call_user_func_array($func, $params);
0 ignored issues
show
Bug introduced by
It seems like $params can also be of type null; however, parameter $param_arr of call_user_func_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1169
							$r = call_user_func_array($func, /** @scrutinizer ignore-type */ $params);
Loading history...
1170
						}
1171
					}
1172
					// the return type can be either an xmlrpcresp object or a plain php value...
1173
					if (!is_a($r, 'xmlrpcresp'))
1174
					{
1175
						// what should we assume here about automatic encoding of datetimes
1176
						// and php classes instances???
1177
						$r = new xmlrpcresp(php_xmlrpc_encode($r, $this->phpvals_encoding_options));
1178
					}
1179
				}
1180
			}
1181
			catch(Exception $e)
1182
			{
1183
				// (barring errors in the lib) an uncatched exception happened
1184
				// in the called function, we wrap it in a proper error-response
1185
				switch($this->exception_handling)
1186
				{
1187
					case 2:
1188
						throw $e;
1189
						break;
1190
					case 1:
1191
						$r = new xmlrpcresp(0, $e->getCode(), $e->getMessage());
1192
						break;
1193
					default:
1194
						$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_error'], $GLOBALS['xmlrpcstr']['server_error']);
1195
				}
1196
			}
1197
			if($this->debug > 2)
1198
			{
1199
				// note: restore the error handler we found before calling the
1200
				// user func, even if it has been changed inside the func itself
1201
				if($GLOBALS['_xmlrpcs_prev_ehandler'])
1202
				{
1203
					set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']);
1204
				}
1205
				else
1206
				{
1207
					restore_error_handler();
1208
				}
1209
			}
1210
			return $r;
1211
		}
1212
1213
		/**
1214
		* add a string to the 'internal debug message' (separate from 'user debug message')
1215
		* @param string $string
1216
		* @access private
1217
		*/
1218
		function debugmsg($string)
1219
		{
1220
			$this->debug_info .= $string."\n";
1221
		}
1222
1223
		/**
1224
		* @access private
1225
		*/
1226
		function xml_header($charset_encoding='')
1227
		{
1228
			if ($charset_encoding != '')
1229
			{
1230
				return "<?xml version=\"1.0\" encoding=\"$charset_encoding\"?" . ">\n";
1231
			}
1232
			else
1233
			{
1234
				return "<?xml version=\"1.0\"?" . ">\n";
1235
			}
1236
		}
1237
1238
		/**
1239
		* A debugging routine: just echoes back the input packet as a string value
1240
		* @deprecated
1241
		*/
1242
		function echoInput()
1243
		{
1244
			$r=new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string'));
1245
			print $r->serialize();
1246
		}
1247
	}
1248
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...