+ $methodFilter = isset($extraOptions['method_filter']) ? $extraOptions['method_filter'] : '';
+ $timeout = isset($extraOptions['timeout']) ? (int)$extraOptions['timeout'] : 0;
+ $protocol = isset($extraOptions['protocol']) ? $extraOptions['protocol'] : '';
+ $newClassName = isset($extraOptions['new_class_name']) ? $extraOptions['new_class_name'] : '';
+ $encodePhpObjects = isset($extraOptions['encode_php_objs']) ? (bool)$extraOptions['encode_php_objs'] : false;
+ $decodePhpObjects = isset($extraOptions['decode_php_objs']) ? (bool)$extraOptions['decode_php_objs'] : false;
+ $verbatimClientCopy = isset($extraOptions['simple_client_copy']) ? !($extraOptions['simple_client_copy']) : true;
+ $buildIt = isset($extraOptions['return_source']) ? !($extraOptions['return_source']) : true;
+ $prefix = isset($extraOptions['prefix']) ? $extraOptions['prefix'] : 'xmlrpc';
+ $namespace = '\\PhpXmlRpc\\';
+
+ $reqClass = $namespace . 'Request';
+ $decoderClass = $namespace . 'Encoder';
+
+ $req = new $reqClass('system.listMethods');
+ $response = $client->send($req, $timeout, $protocol);
+ if ($response->faultCode()) {
+ error_log('XML-RPC: ' . __METHOD__ . ': could not retrieve method list from remote server');
+
+ return false;
+ } else {
+ $mList = $response->value();
+ if ($client->return_type != 'phpvals') {
+ $decoder = new $decoderClass();
+ $mList = $decoder->decode($mList);
+ }
+ if (!is_array($mList) || !count($mList)) {
+ error_log('XML-RPC: ' . __METHOD__ . ': could not retrieve meaningful method list from remote server');
+
+ return false;
+ } else {
+ // pick a suitable name for the new function, avoiding collisions
+ if ($newClassName != '') {
+ $xmlrpcClassName = $newClassName;
+ } else {
+ $xmlrpcClassName = $prefix . '_' . preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
+ array('_', ''), $client->server) . '_client';
+ }
+ while ($buildIt && class_exists($xmlrpcClassName)) {
+ $xmlrpcClassName .= 'x';
+ }
+
+ /// @todo add function setdebug() to new class, to enable/disable debugging
+ $source = "class $xmlrpcClassName\n{\npublic \$client;\n\n";
+ $source .= "function __construct()\n{\n";
+ $source .= $this->buildClientWrapperCode($client, $verbatimClientCopy, $prefix, $namespace);
+ $source .= "\$this->client = \$client;\n}\n\n";
+ $opts = array(
+ 'return_source' => true,
+ 'simple_client_copy' => 2, // do not produce code to copy the client object
+ 'timeout' => $timeout,
+ 'protocol' => $protocol,
+ 'encode_php_objs' => $encodePhpObjects,
+ 'decode_php_objs' => $decodePhpObjects,
+ 'prefix' => $prefix,
+ );
+ /// @todo build phpdoc for class definition, too
+ foreach ($mList as $mName) {
+ if ($methodFilter == '' || preg_match($methodFilter, $mName)) {
+ // note: this will fail if server exposes 2 methods called f.e. do.something and do_something
+ $opts['new_function_name'] = preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
+ array('_', ''), $mName);
+ $methodWrap = $this->wrapXmlrpcMethod($client, $mName, $opts);
+ if ($methodWrap) {
+ if (!$buildIt) {
+ $source .= $methodWrap['docstring'];
+ }
+ $source .= $methodWrap['source'] . "\n";
+ } else {
+ error_log('XML-RPC: ' . __METHOD__ . ': will not create class method to wrap remote method ' . $mName);
+ }
+ }
+ }
+ $source .= "}\n";
+ if ($buildIt) {
+ $allOK = 0;
+ eval($source . '$allOK=1;');
+ if ($allOK) {
+ return $xmlrpcClassName;
+ } else {
+ error_log('XML-RPC: ' . __METHOD__ . ': could not create class ' . $xmlrpcClassName . ' to wrap remote server ' . $client->server);
+ return false;
+ }
+ } else {
+ return array('class' => $xmlrpcClassName, 'code' => $source, 'docstring' => '');
+ }
+ }
+ }
+ }
+
+ /**
+ * Given necessary info, generate php code that will build a client object just like the given one.
+ * Take care that no full checking of input parameters is done to ensure that
+ * valid php code is emitted.
+ * @param Client $client
+ * @param bool $verbatimClientCopy when true, copy all of the state of the client, except for 'debug' and 'return_type'
+ * @param string $prefix used for the return_type of the created client
+ * @param string $namespace
+ *
+ * @return string
+ */
+ protected function buildClientWrapperCode($client, $verbatimClientCopy, $prefix = 'xmlrpc', $namespace = '\\PhpXmlRpc\\' )
+ {
+ $code = "\$client = new {$namespace}Client('" . str_replace("'", "\'", $client->path) .