00001 <?php 00018 // requires: xmlrpc.inc 00019 00028 function php_2_xmlrpc_type($phptype) 00029 { 00030 switch(strtolower($phptype)) 00031 { 00032 case 'string': 00033 return $GLOBALS['xmlrpcString']; 00034 case 'integer': 00035 case $GLOBALS['xmlrpcInt']: // 'int' 00036 case $GLOBALS['xmlrpcI4']: 00037 return $GLOBALS['xmlrpcInt']; 00038 case 'double': 00039 return $GLOBALS['xmlrpcDouble']; 00040 case 'boolean': 00041 return $GLOBALS['xmlrpcBoolean']; 00042 case 'array': 00043 return $GLOBALS['xmlrpcArray']; 00044 case 'object': 00045 return $GLOBALS['xmlrpcStruct']; 00046 case $GLOBALS['xmlrpcBase64']: 00047 case $GLOBALS['xmlrpcStruct']: 00048 return strtolower($phptype); 00049 case 'resource': 00050 return ''; 00051 default: 00052 if(class_exists($phptype)) 00053 { 00054 return $GLOBALS['xmlrpcStruct']; 00055 } 00056 else 00057 { 00058 // unknown: might be any 'extended' xmlrpc type 00059 return $GLOBALS['xmlrpcValue']; 00060 } 00061 } 00062 } 00063 00069 function xmlrpc_2_php_type($xmlrpctype) 00070 { 00071 switch(strtolower($xmlrpctype)) 00072 { 00073 case 'base64': 00074 case 'datetime.iso8601': 00075 case 'string': 00076 return $GLOBALS['xmlrpcString']; 00077 case 'int': 00078 case 'i4': 00079 return 'integer'; 00080 case 'struct': 00081 case 'array': 00082 return 'array'; 00083 case 'double': 00084 return 'float'; 00085 case 'undefined': 00086 return 'mixed'; 00087 case 'boolean': 00088 case 'null': 00089 default: 00090 // unknown: might be any xmlrpc type 00091 return strtolower($xmlrpctype); 00092 } 00093 } 00094 00144 function wrap_php_function($funcname, $newfuncname='', $extra_options=array()) 00145 { 00146 $buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true; 00147 $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; 00148 $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false; 00149 $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false; 00150 $catch_warnings = isset($extra_options['suppress_warnings']) && $extra_options['suppress_warnings'] ? '@' : ''; 00151 00152 if(version_compare(phpversion(), '5.0.3') == -1) 00153 { 00154 // up to php 5.0.3 some useful reflection methods were missing 00155 error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3'); 00156 return false; 00157 } 00158 00159 $exists = false; 00160 if(is_array($funcname)) 00161 { 00162 if(count($funcname) < 2 || (!is_string($funcname[0]) && !is_object($funcname[0]))) 00163 { 00164 error_log('XML-RPC: syntax for function to be wrapped is wrong'); 00165 return false; 00166 } 00167 if(is_string($funcname[0])) 00168 { 00169 $plainfuncname = implode('::', $funcname); 00170 } 00171 elseif(is_object($funcname[0])) 00172 { 00173 $plainfuncname = get_class($funcname[0]) . '->' . $funcname[1]; 00174 } 00175 $exists = method_exists($funcname[0], $funcname[1]); 00176 } 00177 else 00178 { 00179 $plainfuncname = $funcname; 00180 $exists = function_exists($funcname); 00181 } 00182 00183 if(!$exists) 00184 { 00185 error_log('XML-RPC: function to be wrapped is not defined: '.$plainfuncname); 00186 return false; 00187 } 00188 else 00189 { 00190 // determine name of new php function 00191 if($newfuncname == '') 00192 { 00193 if(is_array($funcname)) 00194 { 00195 if(is_string($funcname[0])) 00196 $xmlrpcfuncname = "{$prefix}_".implode('_', $funcname); 00197 else 00198 $xmlrpcfuncname = "{$prefix}_".get_class($funcname[0]) . '_' . $funcname[1]; 00199 } 00200 else 00201 { 00202 $xmlrpcfuncname = "{$prefix}_$funcname"; 00203 } 00204 } 00205 else 00206 { 00207 $xmlrpcfuncname = $newfuncname; 00208 } 00209 while($buildit && function_exists($xmlrpcfuncname)) 00210 { 00211 $xmlrpcfuncname .= 'x'; 00212 } 00213 00214 // start to introspect PHP code 00215 if(is_array($funcname)) 00216 { 00217 $func =& new ReflectionMethod($funcname[0], $funcname[1]); 00218 if($func->isPrivate()) 00219 { 00220 error_log('XML-RPC: method to be wrapped is private: '.$plainfuncname); 00221 return false; 00222 } 00223 if($func->isProtected()) 00224 { 00225 error_log('XML-RPC: method to be wrapped is protected: '.$plainfuncname); 00226 return false; 00227 } 00228 if($func->isConstructor()) 00229 { 00230 error_log('XML-RPC: method to be wrapped is the constructor: '.$plainfuncname); 00231 return false; 00232 } 00233 if($func->isDestructor()) 00234 { 00235 error_log('XML-RPC: method to be wrapped is the destructor: '.$plainfuncname); 00236 return false; 00237 } 00238 if($func->isAbstract()) 00239 { 00240 error_log('XML-RPC: method to be wrapped is abstract: '.$plainfuncname); 00241 return false; 00242 } 00244 } 00245 else 00246 { 00247 $func =& new ReflectionFunction($funcname); 00248 } 00249 if($func->isInternal()) 00250 { 00251 // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs 00252 // instead of getparameters to fully reflect internal php functions ? 00253 error_log('XML-RPC: function to be wrapped is internal: '.$plainfuncname); 00254 return false; 00255 } 00256 00257 // retrieve parameter names, types and description from javadoc comments 00258 00259 // function description 00260 $desc = ''; 00261 // type of return val: by default 'any' 00262 $returns = $GLOBALS['xmlrpcValue']; 00263 // desc of return val 00264 $returnsDocs = ''; 00265 // type + name of function parameters 00266 $paramDocs = array(); 00267 00268 $docs = $func->getDocComment(); 00269 if($docs != '') 00270 { 00271 $docs = explode("\n", $docs); 00272 $i = 0; 00273 foreach($docs as $doc) 00274 { 00275 $doc = trim($doc, " \r\t/*"); 00276 if(strlen($doc) && strpos($doc, '@') !== 0 && !$i) 00277 { 00278 if($desc) 00279 { 00280 $desc .= "\n"; 00281 } 00282 $desc .= $doc; 00283 } 00284 elseif(strpos($doc, '@param') === 0) 00285 { 00286 // syntax: @param type [$name] desc 00287 if(preg_match('/@param\s+(\S+)(\s+\$\S+)?\s+(.+)/', $doc, $matches)) 00288 { 00289 if(strpos($matches[1], '|')) 00290 { 00291 //$paramDocs[$i]['type'] = explode('|', $matches[1]); 00292 $paramDocs[$i]['type'] = 'mixed'; 00293 } 00294 else 00295 { 00296 $paramDocs[$i]['type'] = $matches[1]; 00297 } 00298 $paramDocs[$i]['name'] = trim($matches[2]); 00299 $paramDocs[$i]['doc'] = $matches[3]; 00300 } 00301 $i++; 00302 } 00303 elseif(strpos($doc, '@return') === 0) 00304 { 00305 // syntax: @return type desc 00306 //$returns = preg_split('/\s+/', $doc); 00307 if(preg_match('/@return\s+(\S+)\s+(.+)/', $doc, $matches)) 00308 { 00309 $returns = php_2_xmlrpc_type($matches[1]); 00310 if(isset($matches[2])) 00311 { 00312 $returnsDocs = $matches[2]; 00313 } 00314 } 00315 } 00316 } 00317 } 00318 00319 // execute introspection of actual function prototype 00320 $params = array(); 00321 $i = 0; 00322 foreach($func->getParameters() as $paramobj) 00323 { 00324 $params[$i] = array(); 00325 $params[$i]['name'] = '$'.$paramobj->getName(); 00326 $params[$i]['isoptional'] = $paramobj->isOptional(); 00327 $i++; 00328 } 00329 00330 00331 // start building of PHP code to be eval'd 00332 $innercode = ''; 00333 $i = 0; 00334 $parsvariations = array(); 00335 $pars = array(); 00336 $pnum = count($params); 00337 foreach($params as $param) 00338 { 00339 if (isset($paramDocs[$i]['name']) && $paramDocs[$i]['name'] && strtolower($paramDocs[$i]['name']) != strtolower($param['name'])) 00340 { 00341 // param name from phpdoc info does not match param definition! 00342 $paramDocs[$i]['type'] = 'mixed'; 00343 } 00344 00345 if($param['isoptional']) 00346 { 00347 // this particular parameter is optional. save as valid previous list of parameters 00348 $innercode .= "if (\$paramcount > $i) {\n"; 00349 $parsvariations[] = $pars; 00350 } 00351 $innercode .= "\$p$i = \$msg->getParam($i);\n"; 00352 if ($decode_php_objects) 00353 { 00354 $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i, array('decode_php_objs'));\n"; 00355 } 00356 else 00357 { 00358 $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i);\n"; 00359 } 00360 00361 $pars[] = "\$p$i"; 00362 $i++; 00363 if($param['isoptional']) 00364 { 00365 $innercode .= "}\n"; 00366 } 00367 if($i == $pnum) 00368 { 00369 // last allowed parameters combination 00370 $parsvariations[] = $pars; 00371 } 00372 } 00373 00374 $sigs = array(); 00375 $psigs = array(); 00376 if(count($parsvariations) == 0) 00377 { 00378 // only known good synopsis = no parameters 00379 $parsvariations[] = array(); 00380 $minpars = 0; 00381 } 00382 else 00383 { 00384 $minpars = count($parsvariations[0]); 00385 } 00386 00387 if($minpars) 00388 { 00389 // add to code the check for min params number 00390 // NB: this check needs to be done BEFORE decoding param values 00391 $innercode = "\$paramcount = \$msg->getNumParams();\n" . 00392 "if (\$paramcount < $minpars) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}');\n" . $innercode; 00393 } 00394 else 00395 { 00396 $innercode = "\$paramcount = \$msg->getNumParams();\n" . $innercode; 00397 } 00398 00399 $innercode .= "\$np = false;\n"; 00400 // since there are no closures in php, if we are given an object instance, 00401 // we store a pointer to it in a global var... 00402 if ( is_array($funcname) && is_object($funcname[0]) ) 00403 { 00404 $GLOBALS['xmlrpcWPFObjHolder'][$xmlrpcfuncname] =& $funcname[0]; 00405 $innercode .= "\$obj =& \$GLOBALS['xmlrpcWPFObjHolder']['$xmlrpcfuncname'];\n"; 00406 $realfuncname = '$obj->'.$funcname[1]; 00407 } 00408 else 00409 { 00410 $realfuncname = $plainfuncname; 00411 } 00412 foreach($parsvariations as $pars) 00413 { 00414 $innercode .= "if (\$paramcount == " . count($pars) . ") \$retval = {$catch_warnings}$realfuncname(" . implode(',', $pars) . "); else\n"; 00415 // build a 'generic' signature (only use an appropriate return type) 00416 $sig = array($returns); 00417 $psig = array($returnsDocs); 00418 for($i=0; $i < count($pars); $i++) 00419 { 00420 if (isset($paramDocs[$i]['type'])) 00421 { 00422 $sig[] = php_2_xmlrpc_type($paramDocs[$i]['type']); 00423 } 00424 else 00425 { 00426 $sig[] = $GLOBALS['xmlrpcValue']; 00427 } 00428 $psig[] = isset($paramDocs[$i]['doc']) ? $paramDocs[$i]['doc'] : ''; 00429 } 00430 $sigs[] = $sig; 00431 $psigs[] = $psig; 00432 } 00433 $innercode .= "\$np = true;\n"; 00434 $innercode .= "if (\$np) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}'); else {\n"; 00435 //$innercode .= "if (\$_xmlrpcs_error_occurred) return new xmlrpcresp(0, $GLOBALS['xmlrpcerr']user, \$_xmlrpcs_error_occurred); else\n"; 00436 $innercode .= "if (is_a(\$retval, '{$prefix}resp')) return \$retval; else\n"; 00437 if($returns == $GLOBALS['xmlrpcDateTime'] || $returns == $GLOBALS['xmlrpcBase64']) 00438 { 00439 $innercode .= "return new {$prefix}resp(new {$prefix}val(\$retval, '$returns'));"; 00440 } 00441 else 00442 { 00443 if ($encode_php_objects) 00444 $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval, array('encode_php_objs')));\n"; 00445 else 00446 $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval));\n"; 00447 } 00448 // shall we exclude functions returning by ref? 00449 // if($func->returnsReference()) 00450 // return false; 00451 $code = "function $xmlrpcfuncname(\$msg) {\n" . $innercode . "}\n}"; 00452 //print_r($code); 00453 if ($buildit) 00454 { 00455 $allOK = 0; 00456 eval($code.'$allOK=1;'); 00457 // alternative 00458 //$xmlrpcfuncname = create_function('$m', $innercode); 00459 00460 if(!$allOK) 00461 { 00462 error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap php function '.$plainfuncname); 00463 return false; 00464 } 00465 } 00466 00469 00470 $ret = array('function' => $xmlrpcfuncname, 'signature' => $sigs, 'docstring' => $desc, 'signature_docs' => $psigs, 'source' => $code); 00471 return $ret; 00472 } 00473 } 00474 00488 function wrap_php_class($classname, $extra_options=array()) 00489 { 00490 $methodfilter = isset($extra_options['method_filter']) ? $extra_options['method_filter'] : ''; 00491 $methodtype = isset($extra_options['method_type']) ? $extra_options['method_type'] : 'auto'; 00492 00493 if(version_compare(phpversion(), '5.0.3') == -1) 00494 { 00495 // up to php 5.0.3 some useful reflection methods were missing 00496 error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3'); 00497 return false; 00498 } 00499 00500 $result = array(); 00501 $mlist = get_class_methods($classname); 00502 foreach($mlist as $mname) 00503 { 00504 if ($methodfilter == '' || preg_match($methodfilter, $mname)) 00505 { 00506 // echo $mlist."\n"; 00507 $func =& new ReflectionMethod($classname, $mname); 00508 if(!$func->isPrivate() && !$func->isProtected() && !$func->isConstructor() && !$func->isDestructor() && !$func->isAbstract()) 00509 { 00510 if(($func->isStatic && ($methodtype == 'all' || $methodtype == 'static' || ($methodtype == 'auto' && is_string($classname)))) || 00511 (!$func->isStatic && ($methodtype == 'all' || $methodtype == 'nonstatic' || ($methodtype == 'auto' && is_object($classname))))) 00512 { 00513 $methodwrap = wrap_php_function(array($classname, $mname), '', $extra_options); 00514 if ( $methodwrap ) 00515 { 00516 $result[$methodwrap['function']] = $methodwrap['function']; 00517 } 00518 } 00519 } 00520 } 00521 } 00522 return $result; 00523 } 00524 00562 function wrap_xmlrpc_method($client, $methodname, $extra_options=0, $timeout=0, $protocol='', $newfuncname='') 00563 { 00564 // mind numbing: let caller use sane calling convention (as per javadoc, 3 params), 00565 // OR the 2.0 calling convention (no options) - we really love backward compat, don't we? 00566 if (!is_array($extra_options)) 00567 { 00568 $signum = $extra_options; 00569 $extra_options = array(); 00570 } 00571 else 00572 { 00573 $signum = isset($extra_options['signum']) ? (int)$extra_options['signum'] : 0; 00574 $timeout = isset($extra_options['timeout']) ? (int)$extra_options['timeout'] : 0; 00575 $protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : ''; 00576 $newfuncname = isset($extra_options['new_function_name']) ? $extra_options['new_function_name'] : ''; 00577 } 00578 //$encode_php_objects = in_array('encode_php_objects', $extra_options); 00579 //$verbatim_client_copy = in_array('simple_client_copy', $extra_options) ? 1 : 00580 // in_array('build_class_code', $extra_options) ? 2 : 0; 00581 00582 $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false; 00583 $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false; 00584 $simple_client_copy = isset($extra_options['simple_client_copy']) ? (int)($extra_options['simple_client_copy']) : 0; 00585 $buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true; 00586 $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; 00587 if (isset($extra_options['return_on_fault'])) 00588 { 00589 $decode_fault = true; 00590 $fault_response = $extra_options['return_on_fault']; 00591 } 00592 else 00593 { 00594 $decode_fault = false; 00595 $fault_response = ''; 00596 } 00597 $debug = isset($extra_options['debug']) ? ($extra_options['debug']) : 0; 00598 00599 $msgclass = $prefix.'msg'; 00600 $valclass = $prefix.'val'; 00601 $decodefunc = 'php_'.$prefix.'_decode'; 00602 00603 $msg =& new $msgclass('system.methodSignature'); 00604 $msg->addparam(new $valclass($methodname)); 00605 $client->setDebug($debug); 00606 $response =& $client->send($msg, $timeout, $protocol); 00607 if($response->faultCode()) 00608 { 00609 error_log('XML-RPC: could not retrieve method signature from remote server for method '.$methodname); 00610 return false; 00611 } 00612 else 00613 { 00614 $msig = $response->value(); 00615 if ($client->return_type != 'phpvals') 00616 { 00617 $msig = $decodefunc($msig); 00618 } 00619 if(!is_array($msig) || count($msig) <= $signum) 00620 { 00621 error_log('XML-RPC: could not retrieve method signature nr.'.$signum.' from remote server for method '.$methodname); 00622 return false; 00623 } 00624 else 00625 { 00626 // pick a suitable name for the new function, avoiding collisions 00627 if($newfuncname != '') 00628 { 00629 $xmlrpcfuncname = $newfuncname; 00630 } 00631 else 00632 { 00633 // take care to insure that methodname is translated to valid 00634 // php function name 00635 $xmlrpcfuncname = $prefix.'_'.preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'), 00636 array('_', ''), $methodname); 00637 } 00638 while($buildit && function_exists($xmlrpcfuncname)) 00639 { 00640 $xmlrpcfuncname .= 'x'; 00641 } 00642 00643 $msig = $msig[$signum]; 00644 $mdesc = ''; 00645 // if in 'offline' mode, get method description too. 00646 // in online mode, favour speed of operation 00647 if(!$buildit) 00648 { 00649 $msg =& new $msgclass('system.methodHelp'); 00650 $msg->addparam(new $valclass($methodname)); 00651 $response =& $client->send($msg, $timeout, $protocol); 00652 if (!$response->faultCode()) 00653 { 00654 $mdesc = $response->value(); 00655 if ($client->return_type != 'phpvals') 00656 { 00657 $mdesc = $mdesc->scalarval(); 00658 } 00659 } 00660 } 00661 00662 $results = build_remote_method_wrapper_code($client, $methodname, 00663 $xmlrpcfuncname, $msig, $mdesc, $timeout, $protocol, $simple_client_copy, 00664 $prefix, $decode_php_objects, $encode_php_objects, $decode_fault, 00665 $fault_response); 00666 00667 //print_r($code); 00668 if ($buildit) 00669 { 00670 $allOK = 0; 00671 eval($results['source'].'$allOK=1;'); 00672 // alternative 00673 //$xmlrpcfuncname = create_function('$m', $innercode); 00674 if($allOK) 00675 { 00676 return $xmlrpcfuncname; 00677 } 00678 else 00679 { 00680 error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap remote method '.$methodname); 00681 return false; 00682 } 00683 } 00684 else 00685 { 00686 $results['function'] = $xmlrpcfuncname; 00687 return $results; 00688 } 00689 } 00690 } 00691 } 00692 00701 function wrap_xmlrpc_server($client, $extra_options=array()) 00702 { 00703 $methodfilter = isset($extra_options['method_filter']) ? $extra_options['method_filter'] : ''; 00704 //$signum = isset($extra_options['signum']) ? (int)$extra_options['signum'] : 0; 00705 $timeout = isset($extra_options['timeout']) ? (int)$extra_options['timeout'] : 0; 00706 $protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : ''; 00707 $newclassname = isset($extra_options['new_class_name']) ? $extra_options['new_class_name'] : ''; 00708 $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false; 00709 $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false; 00710 $verbatim_client_copy = isset($extra_options['simple_client_copy']) ? !($extra_options['simple_client_copy']) : true; 00711 $buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true; 00712 $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; 00713 00714 $msgclass = $prefix.'msg'; 00715 //$valclass = $prefix.'val'; 00716 $decodefunc = 'php_'.$prefix.'_decode'; 00717 00718 $msg =& new $msgclass('system.listMethods'); 00719 $response =& $client->send($msg, $timeout, $protocol); 00720 if($response->faultCode()) 00721 { 00722 error_log('XML-RPC: could not retrieve method list from remote server'); 00723 return false; 00724 } 00725 else 00726 { 00727 $mlist = $response->value(); 00728 if ($client->return_type != 'phpvals') 00729 { 00730 $mlist = $decodefunc($mlist); 00731 } 00732 if(!is_array($mlist) || !count($mlist)) 00733 { 00734 error_log('XML-RPC: could not retrieve meaningful method list from remote server'); 00735 return false; 00736 } 00737 else 00738 { 00739 // pick a suitable name for the new function, avoiding collisions 00740 if($newclassname != '') 00741 { 00742 $xmlrpcclassname = $newclassname; 00743 } 00744 else 00745 { 00746 $xmlrpcclassname = $prefix.'_'.preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'), 00747 array('_', ''), $client->server).'_client'; 00748 } 00749 while($buildit && class_exists($xmlrpcclassname)) 00750 { 00751 $xmlrpcclassname .= 'x'; 00752 } 00753 00755 $source = "class $xmlrpcclassname\n{\nvar \$client;\n\n"; 00756 $source .= "function $xmlrpcclassname()\n{\n"; 00757 $source .= build_client_wrapper_code($client, $verbatim_client_copy, $prefix); 00758 $source .= "\$this->client =& \$client;\n}\n\n"; 00759 $opts = array('simple_client_copy' => 2, 'return_source' => true, 00760 'timeout' => $timeout, 'protocol' => $protocol, 00761 'encode_php_objs' => $encode_php_objects, 'prefix' => $prefix, 00762 'decode_php_objs' => $decode_php_objects 00763 ); 00765 foreach($mlist as $mname) 00766 { 00767 if ($methodfilter == '' || preg_match($methodfilter, $mname)) 00768 { 00769 $opts['new_function_name'] = preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'), 00770 array('_', ''), $mname); 00771 $methodwrap = wrap_xmlrpc_method($client, $mname, $opts); 00772 if ($methodwrap) 00773 { 00774 if (!$buildit) 00775 { 00776 $source .= $methodwrap['docstring']; 00777 } 00778 $source .= $methodwrap['source']."\n"; 00779 } 00780 else 00781 { 00782 error_log('XML-RPC: will not create class method to wrap remote method '.$mname); 00783 } 00784 } 00785 } 00786 $source .= "}\n"; 00787 if ($buildit) 00788 { 00789 $allOK = 0; 00790 eval($source.'$allOK=1;'); 00791 // alternative 00792 //$xmlrpcfuncname = create_function('$m', $innercode); 00793 if($allOK) 00794 { 00795 return $xmlrpcclassname; 00796 } 00797 else 00798 { 00799 error_log('XML-RPC: could not create class '.$xmlrpcclassname.' to wrap remote server '.$client->server); 00800 return false; 00801 } 00802 } 00803 else 00804 { 00805 return array('class' => $xmlrpcclassname, 'code' => $source, 'docstring' => ''); 00806 } 00807 } 00808 } 00809 } 00810 00819 function build_remote_method_wrapper_code($client, $methodname, $xmlrpcfuncname, 00820 $msig, $mdesc='', $timeout=0, $protocol='', $client_copy_mode=0, $prefix='xmlrpc', 00821 $decode_php_objects=false, $encode_php_objects=false, $decode_fault=false, 00822 $fault_response='') 00823 { 00824 $code = "function $xmlrpcfuncname ("; 00825 if ($client_copy_mode < 2) 00826 { 00827 // client copy mode 0 or 1 == partial / full client copy in emitted code 00828 $innercode = build_client_wrapper_code($client, $client_copy_mode, $prefix); 00829 $innercode .= "\$client->setDebug(\$debug);\n"; 00830 $this_ = ''; 00831 } 00832 else 00833 { 00834 // client copy mode 2 == no client copy in emitted code 00835 $innercode = ''; 00836 $this_ = 'this->'; 00837 } 00838 $innercode .= "\$msg =& new {$prefix}msg('$methodname');\n"; 00839 00840 if ($mdesc != '') 00841 { 00842 // take care that PHP comment is not terminated unwillingly by method description 00843 $mdesc = "/**\n* ".str_replace('*/', '* /', $mdesc)."\n"; 00844 } 00845 else 00846 { 00847 $mdesc = "/**\nFunction $xmlrpcfuncname\n"; 00848 } 00849 00850 // param parsing 00851 $plist = array(); 00852 $pcount = count($msig); 00853 for($i = 1; $i < $pcount; $i++) 00854 { 00855 $plist[] = "\$p$i"; 00856 $ptype = $msig[$i]; 00857 if($ptype == 'i4' || $ptype == 'int' || $ptype == 'boolean' || $ptype == 'double' || 00858 $ptype == 'string' || $ptype == 'dateTime.iso8601' || $ptype == 'base64' || $ptype == 'null') 00859 { 00860 // only build directly xmlrpcvals when type is known and scalar 00861 $innercode .= "\$p$i =& new {$prefix}val(\$p$i, '$ptype');\n"; 00862 } 00863 else 00864 { 00865 if ($encode_php_objects) 00866 { 00867 $innercode .= "\$p$i =& php_{$prefix}_encode(\$p$i, array('encode_php_objs'));\n"; 00868 } 00869 else 00870 { 00871 $innercode .= "\$p$i =& php_{$prefix}_encode(\$p$i);\n"; 00872 } 00873 } 00874 $innercode .= "\$msg->addparam(\$p$i);\n"; 00875 $mdesc .= '* @param '.xmlrpc_2_php_type($ptype)." \$p$i\n"; 00876 } 00877 if ($client_copy_mode < 2) 00878 { 00879 $plist[] = '$debug=0'; 00880 $mdesc .= "* @param int \$debug when 1 (or 2) will enable debugging of the underlying {$prefix} call (defaults to 0)\n"; 00881 } 00882 $plist = implode(', ', $plist); 00883 $mdesc .= '* @return '.xmlrpc_2_php_type($msig[0])." (or an {$prefix}resp obj instance if call fails)\n*/\n"; 00884 00885 $innercode .= "\$res =& \${$this_}client->send(\$msg, $timeout, '$protocol');\n"; 00886 if ($decode_fault) 00887 { 00888 if (is_string($fault_response) && ((strpos($fault_response, '%faultCode%') !== false) || (strpos($fault_response, '%faultString%') !== false))) 00889 { 00890 $respcode = "str_replace(array('%faultCode%', '%faultString%'), array(\$res->faultCode(), \$res->faultString()), '".str_replace("'", "''", $fault_response)."')"; 00891 } 00892 else 00893 { 00894 $respcode = var_export($fault_response, true); 00895 } 00896 } 00897 else 00898 { 00899 $respcode = '$res'; 00900 } 00901 if ($decode_php_objects) 00902 { 00903 $innercode .= "if (\$res->faultcode()) return $respcode; else return php_{$prefix}_decode(\$res->value(), array('decode_php_objs'));"; 00904 } 00905 else 00906 { 00907 $innercode .= "if (\$res->faultcode()) return $respcode; else return php_{$prefix}_decode(\$res->value());"; 00908 } 00909 00910 $code = $code . $plist. ") {\n" . $innercode . "\n}\n"; 00911 00912 return array('source' => $code, 'docstring' => $mdesc); 00913 } 00914 00921 function build_client_wrapper_code($client, $verbatim_client_copy, $prefix='xmlrpc') 00922 { 00923 $code = "\$client =& new {$prefix}_client('".str_replace("'", "\'", $client->path). 00924 "', '" . str_replace("'", "\'", $client->server) . "', $client->port);\n"; 00925 00926 // copy all client fields to the client that will be generated runtime 00927 // (this provides for future expansion or subclassing of client obj) 00928 if ($verbatim_client_copy) 00929 { 00930 foreach($client as $fld => $val) 00931 { 00932 if($fld != 'debug' && $fld != 'return_type') 00933 { 00934 $val = var_export($val, true); 00935 $code .= "\$client->$fld = $val;\n"; 00936 } 00937 } 00938 } 00939 // only make sure that client always returns the correct data type 00940 $code .= "\$client->return_type = '{$prefix}vals';\n"; 00941 //$code .= "\$client->setDebug(\$debug);\n"; 00942 return $code; 00943 } 00944 ?>
Copyright © 2003 - 2009 MyOOS [Shopsystem]. All rights reserved. MyOOS [Shopsystem] is Free Software released under the GNU/GPL License. Webmaster: info@r23.de (Impressum) |
|