⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmlrpc_wrappers.php

📁 Joomla!是一套获得过多个奖项的内容管理系统(Content Management System, CMS)。Joomla!采用PHP+MySQL数据库开发
💻 PHP
📖 第 1 页 / 共 2 页
字号:
<?php/** * PHP-XMLRPC "wrapper" functions * Generate stubs to transparently access xmlrpc methods as php functions and viceversa * * @version $Id: xmlrpc_wrappers.inc,v 1.10 2006/09/01 21:49:19 ggiunta Exp $ * @copyright G. Giunta (C) 2006 * @author Gaetano Giunta * * @todo separate introspection from code generation for func-2-method wrapping * @todo use some better templating system from code generation? * @todo implement method wrapping with preservation of php objs in calls * @todo when wrapping methods without obj rebuilding, use return_type = 'phpvals' (faster) * @todo implement self-parsing of php code for PHP <= 4 */	// requires: xmlrpc.inc	/**	* Given a string defining a php type or phpxmlrpc type (loosely defined: strings	* accepted come from javadoc blocks), return corresponding phpxmlrpc type.	* NB: for php 'resource' types returns empty string, since resources cannot be serialized;	* for php class names returns 'struct', since php objects can be serialized as xmlrpc structs	* @param string $phptype	* @return string	*/	function php_2_xmlrpc_type($phptype)	{		switch(strtolower($phptype))		{			case 'string':				return $GLOBALS['xmlrpcString'];			case 'integer':			case $GLOBALS['xmlrpcInt']: // 'int'			case $GLOBALS['xmlrpcI4']:				return $GLOBALS['xmlrpcInt'];			case 'double':				return $GLOBALS['xmlrpcDouble'];			case 'boolean':				return $GLOBALS['xmlrpcBoolean'];			case 'array':				return $GLOBALS['xmlrpcArray'];			case 'object':				return $GLOBALS['xmlrpcStruct'];			case $GLOBALS['xmlrpcBase64']:			case $GLOBALS['xmlrpcStruct']:				return strtolower($phptype);			case 'resource':				return '';			default:				if(class_exists($phptype))				{					return $GLOBALS['xmlrpcStruct'];				}				else				{					// unknown: might be any 'extended' xmlrpc type					return $GLOBALS['xmlrpcValue'];				}		}	}	/**	* Given a string defining a phpxmlrpc type return corresponding php type.	* @param string $xmlrpctype	* @return string	*/	function xmlrpc_2_php_type($xmlrpctype)	{		switch(strtolower($xmlrpctype))		{			case 'base64':			case 'datetime.iso8601':			case 'string':				return $GLOBALS['xmlrpcString'];			case 'int':			case 'i4':				return 'integer';			case 'struct':			case 'array':				return 'array';			case 'double':				return 'float';			case 'undefined':				return 'mixed';			case 'boolean':			case 'null':			default:				// unknown: might be any xmlrpc type				return strtolower($xmlrpctype);		}	}	/**	* Given a user-defined PHP function, create a PHP 'wrapper' function that can	* be exposed as xmlrpc method from an xmlrpc_server object and called from remote	* clients (as well as its corresponding signature info).	*	* Since php is a typeless language, to infer types of input and output parameters,	* it relies on parsing the javadoc-style comment block associated with the given	* function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and base64)	* in the @param tag is also allowed, if you need the php function to receive/send	* data in that particular format (note that base64 encoding/decoding is transparently	* carried out by the lib, while datetime vals are passed around as strings)	*	* Known limitations:	* - requires PHP 5.0.3 +	* - only works for user-defined functions, not for PHP internal functions	*   (reflection does not support retrieving number/type of params for those)	* - functions returning php objects will generate special xmlrpc responses:	*   when the xmlrpc decoding of those responses is carried out by this same lib, using	*   the appropriate param in php_xmlrpc_decode, the php objects will be rebuilt.	*   In short: php objects can be serialized, too (except for their resource members),	*   using this function.	*   Other libs might choke on the very same xml that will be generated in this case	*   (i.e. it has a nonstandard attribute on struct element tags)	* - usage of javadoc @param tags using param names in a different order from the	*   function prototype is not considered valid (to be fixed?)	*	* Note that since rel. 2.0RC3 the preferred method to have the server call 'standard'	* php functions (ie. functions not expecting a single xmlrpcmsg obj as parameter)	* is by making use of the functions_parameters_type class member.	*	* @param string $funcname the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') might be ok too, in the future...	* @param string $newfuncname (optional) name for function to be created	* @param array $extra_options (optional) array of options for conversion. valid values include:	*        bool  return_source when true, php code w. function definition will be returned, not evaluated	*        bool  encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects	*        bool  decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers ---	*        bool  suppress_warnings  remove from produced xml any runtime warnings due to the php function being invoked	* @return false on error, or an array containing the name of the new php function,	*         its signature and docs, to be used in the server dispatch map	*	* @todo decide how to deal with params passed by ref: bomb out or allow?	* @todo finish using javadoc info to build method sig if all params are named but out of order	* @todo add a check for params of 'resource' type	* @todo add some trigger_errors / error_log when returning false?	* @todo what to do when the PHP function returns NULL? we are currently an empty string value...	* @todo add an option to suppress php warnings in invocation of user function, similar to server debug level 3?	*/	function wrap_php_function($funcname, $newfuncname='', $extra_options=array())	{		$buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true;		$prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc';		$encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false;		$decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false;		$catch_warnings = isset($extra_options['suppress_warnings']) && $extra_options['suppress_warnings'] ? '@' : '';		if(version_compare(phpversion(), '5.0.3') == -1)		{			// up to php 5.0.3 some useful reflection methods were missing			error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3');			return false;		}		if((is_array($funcname) && !method_exists($funcname[0], $funcname[1])) || !function_exists($funcname))		{			error_log('XML-RPC: function to be wrapped is not defined: '.$funcname);			return false;		}		else		{			// determine name of new php function			if($newfuncname == '')			{				if(is_array($funcname))				{					$xmlrpcfuncname = "{$prefix}_".implode('_', $funcname);				}				else				{					$xmlrpcfuncname = "{$prefix}_$funcname";				}			}			else			{				$xmlrpcfuncname = $newfuncname;			}			while($buildit && function_exists($xmlrpcfuncname))			{				$xmlrpcfuncname .= 'x';			}			// start to introspect PHP code			$func =& new ReflectionFunction($funcname);			if($func->isInternal())			{				// Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs				// instead of getparameters to fully reflect internal php functions ?				error_log('XML-RPC: function to be wrapped is internal: '.$funcname);				return false;			}			// retrieve parameter names, types and description from javadoc comments			// function description			$desc = '';			// type of return val: by default 'any'			$returns = $GLOBALS['xmlrpcValue'];			// desc of return val			$returnsDocs = '';			// type + name of function parameters			$paramDocs = array();			$docs = $func->getDocComment();			if($docs != '')			{				$docs = explode("\n", $docs);				$i = 0;				foreach($docs as $doc)				{					$doc = trim($doc, " \r\t/*");					if(strlen($doc) && strpos($doc, '@') !== 0 && !$i)					{						if($desc)						{							$desc .= "\n";						}						$desc .= $doc;					}					elseif(strpos($doc, '@param') === 0)					{						// syntax: @param type [$name] desc						if(preg_match('/@param\s+(\S+)(\s+\$\S+)?\s+(.+)/', $doc, $matches))						{							if(strpos($matches[1], '|'))							{								//$paramDocs[$i]['type'] = explode('|', $matches[1]);								$paramDocs[$i]['type'] = 'mixed';							}							else							{								$paramDocs[$i]['type'] = $matches[1];							}							$paramDocs[$i]['name'] = trim($matches[2]);							$paramDocs[$i]['doc'] = $matches[3];						}						$i++;					}					elseif(strpos($doc, '@return') === 0)					{						// syntax: @return type desc						//$returns = preg_split('/\s+/', $doc);						if(preg_match('/@return\s+(\S+)\s+(.+)/', $doc, $matches))						{							$returns = php_2_xmlrpc_type($matches[1]);							if(isset($matches[2]))							{								$returnsDocs = $matches[2];							}						}					}				}			}			// execute introspection of actual function prototype			$params = array();			$i = 0;			foreach($func->getParameters() as $paramobj)			{				$params[$i] = array();				$params[$i]['name'] = '$'.$paramobj->getName();				$params[$i]['isoptional'] = $paramobj->isOptional();				$i++;			}			// start  building of PHP code to be eval'd			$innercode = '';			$i = 0;			$parsvariations = array();			$pars = array();			$pnum = count($params);			foreach($params as $param)			{				if (isset($paramDocs[$i]['name']) && $paramDocs[$i]['name'] && strtolower($paramDocs[$i]['name']) != strtolower($param['name']))				{					// param name from phpdoc info does not match param definition!					$paramDocs[$i]['type'] = 'mixed';				}				if($param['isoptional'])				{					// this particular parameter is optional. save as valid previous list of parameters					$innercode .= "if (\$paramcount > $i) {\n";					$parsvariations[] = $pars;				}				$innercode .= "\$p$i = \$msg->getParam($i);\n";				if ($decode_php_objects)				{					$innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i, array('decode_php_objs'));\n";				}				else				{					$innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i);\n";				}				$pars[] = "\$p$i";				$i++;				if($param['isoptional'])				{					$innercode .= "}\n";				}				if($i == $pnum)				{					// last allowed parameters combination					$parsvariations[] = $pars;				}			}			$sigs = array();			$psigs = array();			if(count($parsvariations) == 0)			{				// only known good synopsis = no parameters				$parsvariations[] = array();				$minpars = 0;			}			else			{				$minpars = count($parsvariations[0]);			}			if($minpars)			{				// add to code the check for min params number				// NB: this check needs to be done BEFORE decoding param values				$innercode = "\$paramcount = \$msg->getNumParams();\n" .				"if (\$paramcount < $minpars) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}');\n" . $innercode;			}			else			{				$innercode = "\$paramcount = \$msg->getNumParams();\n" . $innercode;			}			$innercode .= "\$np = false;\n";			foreach($parsvariations as $pars)			{				$innercode .= "if (\$paramcount == " . count($pars) . ") \$retval = {$catch_warnings}$funcname(" . implode(',', $pars) . "); else\n";				// build a 'generic' signature (only use an appropriate return type)				$sig = array($returns);				$psig = array($returnsDocs);				for($i=0; $i < count($pars); $i++)				{					if (isset($paramDocs[$i]['type']))					{						$sig[] = php_2_xmlrpc_type($paramDocs[$i]['type']);					}					else					{						$sig[] = $GLOBALS['xmlrpcValue'];					}					$psig[] = isset($paramDocs[$i]['doc']) ? $paramDocs[$i]['doc'] : '';				}				$sigs[] = $sig;				$psigs[] = $psig;			}			$innercode .= "\$np = true;\n";			$innercode .= "if (\$np) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}'); else {\n";			//$innercode .= "if (\$_xmlrpcs_error_occurred) return new xmlrpcresp(0, $GLOBALS['xmlrpcerr']user, \$_xmlrpcs_error_occurred); else\n";			$innercode .= "if (is_a(\$retval, '{$prefix}resp')) return \$retval; else\n";			if($returns == $GLOBALS['xmlrpcDateTime'] || $returns == $GLOBALS['xmlrpcBase64'])			{				$innercode .= "return new {$prefix}resp(new {$prefix}val(\$retval, '$returns'));";			}			else			{				if ($encode_php_objects)					$innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval, array('encode_php_objs')));\n";				else					$innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval));\n";			}			// shall we exclude functions returning by ref?			// if($func->returnsReference())			// 	return false;			$code = "function $xmlrpcfuncname(\$msg) {\n" . $innercode . "}\n}";			//print_r($code);			if ($buildit)			{				$allOK = 0;				eval($code.'$allOK=1;');				// alternative				//$xmlrpcfuncname = create_function('$m', $innercode);				if(!$allOK)				{					error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap php function '.$funcname);					return false;				}			}			/// @todo examine if $paramDocs matches $parsvariations and build array for			/// usage as method signature, plus put together a nice string for docs			$ret = array('function' => $xmlrpcfuncname, 'signature' => $sigs, 'docstring' => $desc, 'signature_docs' => $psigs, 'source' => $code);			return $ret;		}	}	/**	* Given an xmlrpc client and a method name, register a php wrapper function	* that will call it and return results using native php types for both	* params and results. The generated php function will return an xmlrpcresp	* oject for failed xmlrpc calls	*	* Known limitations:	* - server must support system.methodsignature for the wanted xmlrpc method	* - for methods that expose many signatures, only one can be picked (we	*   could in priciple check if signatures differ only by number of params	*   and not by type, but it would be more complication than we can spare time)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -