$msig = $msig[$methodsig]; $proto = $protocol == 2 ? 'https' : $protocol == 1 ? 'http11' : ''; if ($proxy == '' && $username == '' && !$requestcompression && !$responsecompression && $clientcookies == '') { $opts = 0; // simple client copy in stub code } else { $opts = 1; // complete client copy in stub code } if ($wstype == 1) { $prefix = 'jsonrpc'; } else { $prefix = 'xmlrpc'; } //$code = wrap_xmlrpc_method($client, $method, $methodsig, 0, $proto, '', $opts); $code = build_remote_method_wrapper_code($client, $method, str_replace('.', '_', $prefix . '_' . $method), $msig, $mdesc, $timeout, $proto, $opts, $prefix); //if ($code) //{ echo "<div id=\"phpcode\">\n"; highlight_string("<?php\n" . $code['docstring'] . $code['source'] . '?>'); echo "\n</div>"; //} //else //{ // echo 'Error while building php code stub...'; } break; case 'execute': echo '<div id="response"><h2>Response:</h2>' . htmlspecialchars($response->serialize()) . '</div>'; break; default:
/** * 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) * - nested xmlrpc params: the caller of the generated php function has to * encode on its own the params passed to the php function if these are structs * or arrays whose (sub)members include values of type datetime or base64 * * Notes: the connection properties of the given client will be copied * and reused for the connection used during the call to the generated * php function. * Calling the generated php function 'might' be slow: a new xmlrpc client * is created on every invocation and an xmlrpc-connection opened+closed. * An extra 'debug' param is appended to param list of xmlrpc method, useful * for debugging purposes. * * @param xmlrpc_client $client an xmlrpc client set up correctly to communicate with target server * @param string $methodname the xmlrpc method to be mapped to a php function * @param array $extra_options array of options that specify conversion details. valid ptions include * integer signum the index of the method signature to use in mapping (if method exposes many sigs) * integer timeout timeout (in secs) to be used when executing function/calling remote method * string protocol 'http' (default), 'http11' or 'https' * string new_function_name the name of php function to create. If unsepcified, lib will pick an appropriate name * string return_source if true return php code w. function definition instead fo function name * 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 --- * mixed return_on_fault a php value to be returned when the xmlrpc call fails/returns a fault response (by default the xmlrpcresp object is returned in this case). If a string is used, '%faultCode%' and '%faultString%' tokens will be substituted with actual error values * bool debug set it to 1 or 2 to see debug results of querying server for method synopsis * @return string the name of the generated php function (or false) - OR AN ARRAY... */ function wrap_xmlrpc_method($client, $methodname, $extra_options = 0, $timeout = 0, $protocol = '', $newfuncname = '') { // mind numbing: let caller use sane calling convention (as per javadoc, 3 params), // OR the 2.0 calling convention (no options) - we really love backward compat, don't we? if (!is_array($extra_options)) { $signum = $extra_options; $extra_options = array(); } else { $signum = isset($extra_options['signum']) ? (int) $extra_options['signum'] : 0; $timeout = isset($extra_options['timeout']) ? (int) $extra_options['timeout'] : 0; $protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : ''; $newfuncname = isset($extra_options['new_function_name']) ? $extra_options['new_function_name'] : ''; } //$encode_php_objects = in_array('encode_php_objects', $extra_options); //$verbatim_client_copy = in_array('simple_client_copy', $extra_options) ? 1 : // in_array('build_class_code', $extra_options) ? 2 : 0; $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; $simple_client_copy = isset($extra_options['simple_client_copy']) ? (int) $extra_options['simple_client_copy'] : 0; $buildit = isset($extra_options['return_source']) ? !$extra_options['return_source'] : true; $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; if (isset($extra_options['return_on_fault'])) { $decode_fault = true; $fault_response = $extra_options['return_on_fault']; } else { $decode_fault = false; $fault_response = ''; } $debug = isset($extra_options['debug']) ? $extra_options['debug'] : 0; $msgclass = $prefix . 'msg'; $valclass = $prefix . 'val'; $decodefunc = 'php_' . $prefix . '_decode'; $msg = new $msgclass('system.methodSignature'); $msg->addparam(new $valclass($methodname)); $client->setDebug($debug); $response =& $client->send($msg, $timeout, $protocol); if ($response->faultCode()) { error_log('XML-RPC: could not retrieve method signature from remote server for method ' . $methodname); return false; } else { $msig = $response->value(); if ($client->return_type != 'phpvals') { $msig = $decodefunc($msig); } if (!is_array($msig) || count($msig) <= $signum) { error_log('XML-RPC: could not retrieve method signature nr.' . $signum . ' from remote server for method ' . $methodname); return false; } else { // pick a suitable name for the new function, avoiding collisions if ($newfuncname != '') { $xmlrpcfuncname = $newfuncname; } else { // take care to insure that methodname is translated to valid // php function name $xmlrpcfuncname = $prefix . '_' . preg_replace(array('/\\./', '/[^a-zA-Z0-9_\\x7f-\\xff]/'), array('_', ''), $methodname); } while ($buildit && function_exists($xmlrpcfuncname)) { $xmlrpcfuncname .= 'x'; } $msig = $msig[$signum]; $mdesc = ''; // if in 'offline' mode, get method description too. // in online mode, favour speed of operation if (!$buildit) { $msg = new $msgclass('system.methodHelp'); $msg->addparam(new $valclass($methodname)); $response =& $client->send($msg, $timeout, $protocol); if (!$response->faultCode()) { $mdesc = $response->value(); if ($client->return_type != 'phpvals') { $mdesc = $mdesc->scalarval(); } } } $results = build_remote_method_wrapper_code($client, $methodname, $xmlrpcfuncname, $msig, $mdesc, $timeout, $protocol, $simple_client_copy, $prefix, $decode_php_objects, $encode_php_objects, $decode_fault, $fault_response); //print_r($code); if ($buildit) { $allOK = 0; eval($results['source'] . '$allOK=1;'); // alternative //$xmlrpcfuncname = create_function('$m', $innercode); if ($allOK) { return $xmlrpcfuncname; } else { error_log('XML-RPC: could not create function ' . $xmlrpcfuncname . ' to wrap remote method ' . $methodname); return false; } } else { $results['function'] = $xmlrpcfuncname; return $results; } } } }