22 var $no_multicall=false;
27 var $proxy_authtype=1;
29 var $extracurlopts=array();
32 * List of http compression methods accepted by the client for responses.
33 * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
35 * NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since
36 * in those cases it will be up to CURL to decide the compression methods
37 * it supports. You might check for the presence of 'zlib' in the output of
38 * curl_version() to determine wheter compression is supported or not
40 var $accepted_compression = array();
42 * Name of compression scheme to be used for sending requests.
43 * Either null, gzip or deflate
45 var $request_compression = '';
47 * CURL handle: used for keep-alive connections (PHP 4.3.8 up, see:
48 * http://curl.haxx.se/docs/faq.html#7.3)
50 var $xmlrpc_curl_handle = null;
51 /// Whether to use persistent connections for http 1.1 and https
52 var $keepalive = false;
53 /// Charset encodings that can be decoded without problems by the client
54 var $accepted_charset_encodings = array();
55 /// Charset encoding to be used in serializing request. NULL = use ASCII
56 var $request_charset_encoding = '';
58 * Decides the content of xmlrpcresp objects returned by calls to send()
59 * valid strings are 'xmlrpcvals', 'phpvals' or 'xml'
61 var $return_type = 'xmlrpcvals';
63 * Sent to servers in http headers
68 * @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php
69 * @param string $server the server name / ip address
70 * @param integer $port the port the server is listening on, defaults to 80 or 443 depending on protocol used
71 * @param string $method the http protocol variant: defaults to 'http', 'https' and 'http11' can be used if CURL is installed
73 function xmlrpc_client($path, $server='', $port='', $method='')
75 $xmlrpc = Xmlrpc::instance();
77 // allow user to specify all params in $path
78 if($server == '' and $port == '' and $method == '')
80 $parts = parse_url($path);
81 $server = $parts['host'];
82 $path = isset($parts['path']) ? $parts['path'] : '';
83 if(isset($parts['query']))
85 $path .= '?'.$parts['query'];
87 if(isset($parts['fragment']))
89 $path .= '#'.$parts['fragment'];
91 if(isset($parts['port']))
93 $port = $parts['port'];
95 if(isset($parts['scheme']))
97 $method = $parts['scheme'];
99 if(isset($parts['user']))
101 $this->username = $parts['user'];
103 if(isset($parts['pass']))
105 $this->password = $parts['pass'];
108 if($path == '' || $path[0] != '/')
110 $this->path='/'.$path;
116 $this->server=$server;
123 $this->method=$method;
126 // if ZLIB is enabled, let the client by default accept compressed responses
127 if(function_exists('gzinflate') || (
128 function_exists('curl_init') && (($info = curl_version()) &&
129 ((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
132 $this->accepted_compression = array('gzip', 'deflate');
135 // keepalives: enabled by default
136 $this->keepalive = true;
138 // by default the xml parser can support these 3 charset encodings
139 $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
141 // initialize user_agent string
142 $this->user_agent = $xmlrpc->xmlrpcName . ' ' . $xmlrpc->xmlrpcVersion;
146 * Enables/disables the echoing to screen of the xmlrpc responses received
147 * @param integer $in values 0, 1 and 2 are supported (2 = echo sent msg too, before received response)
150 function setDebug($in)
156 * Add some http BASIC AUTH credentials, used by the client to authenticate
157 * @param string $u username
158 * @param string $p password
159 * @param integer $t auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC (basic auth)
162 function setCredentials($u, $p, $t=1)
170 * Add a client-side https certificate
171 * @param string $cert
172 * @param string $certpass
175 function setCertificate($cert, $certpass)
178 $this->certpass = $certpass;
182 * Add a CA certificate to verify server with (see man page about
183 * CURLOPT_CAINFO for more details)
184 * @param string $cacert certificate file name (or dir holding certificates)
185 * @param bool $is_dir set to true to indicate cacert is a dir. defaults to false
188 function setCaCertificate($cacert, $is_dir=false)
192 $this->cacertdir = $cacert;
196 $this->cacert = $cacert;
201 * Set attributes for SSL communication: private SSL key
202 * NB: does not work in older php/curl installs
203 * Thanks to Daniel Convissor
204 * @param string $key The name of a file containing a private SSL key
205 * @param string $keypass The secret password needed to use the private SSL key
208 function setKey($key, $keypass)
211 $this->keypass = $keypass;
215 * Set attributes for SSL communication: verify server certificate
216 * @param bool $i enable/disable verification of peer certificate
219 function setSSLVerifyPeer($i)
221 $this->verifypeer = $i;
225 * Set attributes for SSL communication: verify match of server cert w. hostname
229 function setSSLVerifyHost($i)
231 $this->verifyhost = $i;
236 * @param string $proxyhost
237 * @param string $proxyport Defaults to 8080 for HTTP and 443 for HTTPS
238 * @param string $proxyusername Leave blank if proxy has public access
239 * @param string $proxypassword Leave blank if proxy has public access
240 * @param int $proxyauthtype set to constant CURLAUTH_NTLM to use NTLM auth with proxy
243 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 1)
245 $this->proxy = $proxyhost;
246 $this->proxyport = $proxyport;
247 $this->proxy_user = $proxyusername;
248 $this->proxy_pass = $proxypassword;
249 $this->proxy_authtype = $proxyauthtype;
253 * Enables/disables reception of compressed xmlrpc responses.
254 * Note that enabling reception of compressed responses merely adds some standard
255 * http headers to xmlrpc requests. It is up to the xmlrpc server to return
256 * compressed responses when receiving such requests.
257 * @param string $compmethod either 'gzip', 'deflate', 'any' or ''
260 function setAcceptedCompression($compmethod)
262 if ($compmethod == 'any')
263 $this->accepted_compression = array('gzip', 'deflate');
265 if ($compmethod == false )
266 $this->accepted_compression = array();
268 $this->accepted_compression = array($compmethod);
272 * Enables/disables http compression of xmlrpc request.
273 * Take care when sending compressed requests: servers might not support them
274 * (and automatic fallback to uncompressed requests is not yet implemented)
275 * @param string $compmethod either 'gzip', 'deflate' or ''
278 function setRequestCompression($compmethod)
280 $this->request_compression = $compmethod;
284 * Adds a cookie to list of cookies that will be sent to server.
285 * NB: setting any param but name and value will turn the cookie into a 'version 1' cookie:
286 * do not do it unless you know what you are doing
287 * @param string $name
288 * @param string $value
289 * @param string $path
290 * @param string $domain
294 * @todo check correctness of urlencoding cookie value (copied from php way of doing it...)
296 function setCookie($name, $value='', $path='', $domain='', $port=null)
298 $this->cookies[$name]['value'] = urlencode($value);
299 if ($path || $domain || $port)
301 $this->cookies[$name]['path'] = $path;
302 $this->cookies[$name]['domain'] = $domain;
303 $this->cookies[$name]['port'] = $port;
304 $this->cookies[$name]['version'] = 1;
308 $this->cookies[$name]['version'] = 0;
313 * Directly set cURL options, for extra flexibility
314 * It allows eg. to bind client to a specific IP interface / address
315 * @param array $options
317 function SetCurlOptions( $options )
319 $this->extracurlopts = $options;
323 * Set user-agent string that will be used by this client instance
324 * in http headers sent to the server
326 function SetUserAgent( $agentstring )
328 $this->user_agent = $agentstring;
332 * Send an xmlrpc request
333 * @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request
334 * @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply
335 * @param string $method if left unspecified, the http protocol chosen during creation of the object will be used
339 function& send($msg, $timeout=0, $method='')
341 // if user deos not specify http protocol, use native method of this client
342 // (i.e. method set during call to constructor)
345 $method = $this->method;
350 // $msg is an array of xmlrpcmsg's
351 $r = $this->multicall($msg, $timeout, $method);
354 elseif(is_string($msg))
356 $n = new xmlrpcmsg('');
361 // where msg is an xmlrpcmsg
362 $msg->debug=$this->debug;
364 if($method == 'https')
366 $r =& $this->sendPayloadHTTPS(
382 $this->proxy_authtype,
388 elseif($method == 'http11')
390 $r =& $this->sendPayloadCURL(
406 $this->proxy_authtype,
413 $r =& $this->sendPayloadHTTP10(
425 $this->proxy_authtype
435 function &sendPayloadHTTP10($msg, $server, $port, $timeout=0,
436 $username='', $password='', $authtype=1, $proxyhost='',
437 $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1)
439 $xmlrpc = Xmlrpc::instance();
446 // Only create the payload if it was not created previously
447 if(empty($msg->payload))
449 $msg->createPayload($this->request_charset_encoding);
452 $payload = $msg->payload;
453 // Deflate request body and set appropriate request headers
454 if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
456 if($this->request_compression == 'gzip')
458 $a = @gzencode($payload);
462 $encoding_hdr = "Content-Encoding: gzip\r\n";
467 $a = @gzcompress($payload);
471 $encoding_hdr = "Content-Encoding: deflate\r\n";
480 // thanks to Grant Rauscher <grant7@firstworld.net> for this
484 $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
487 error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported with HTTP 1.0');
491 $accepted_encoding = '';
492 if(is_array($this->accepted_compression) && count($this->accepted_compression))
494 $accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n";
497 $proxy_credentials = '';
504 $connectserver = $proxyhost;
505 $connectport = $proxyport;
506 $uri = 'http://'.$server.':'.$port.$this->path;
507 if($proxyusername != '')
509 if ($proxyauthtype != 1)
511 error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported with HTTP 1.0');
513 $proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";
518 $connectserver = $server;
519 $connectport = $port;
523 // Cookie generation, as per rfc2965 (version 1 cookies) or
524 // netscape's rules (version 0 cookies)
526 if (count($this->cookies))
529 foreach ($this->cookies as $name => $cookie)
531 if ($cookie['version'])
533 $version = ' $Version="' . $cookie['version'] . '";';
534 $cookieheader .= ' ' . $name . '="' . $cookie['value'] . '";';
536 $cookieheader .= ' $Path="' . $cookie['path'] . '";';
537 if ($cookie['domain'])
538 $cookieheader .= ' $Domain="' . $cookie['domain'] . '";';
540 $cookieheader .= ' $Port="' . $cookie['port'] . '";';
544 $cookieheader .= ' ' . $name . '=' . $cookie['value'] . ";";
547 $cookieheader = 'Cookie:' . $version . substr($cookieheader, 0, -1) . "\r\n";
551 $port = ($port == 80) ? '' : (':' . $port);
553 $op= 'POST ' . $uri. " HTTP/1.0\r\n" .
554 'User-Agent: ' . $this->user_agent . "\r\n" .
555 'Host: '. $server . $port . "\r\n" .
560 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings) . "\r\n" .
562 'Content-Type: ' . $msg->content_type . "\r\nContent-Length: " .
563 strlen($payload) . "\r\n\r\n" .
568 print "<PRE>\n---SENDING---\n" . htmlentities($op) . "\n---END---\n</PRE>";
569 // let the client see this now in case http times out...
575 $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout);
579 $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr);
583 if($timeout>0 && function_exists('stream_set_timeout'))
585 stream_set_timeout($fp, $timeout);
590 $this->errstr='Connect error: '.$this->errstr;
591 $r=new xmlrpcresp(0, $xmlrpc->xmlrpcerr['http_error'], $this->errstr . ' (' . $this->errno . ')');
595 if(!fputs($fp, $op, strlen($op)))
598 $this->errstr='Write error';
599 $r=new xmlrpcresp(0, $xmlrpc->xmlrpcerr['http_error'], $this->errstr);
604 // reset errno and errstr on successful socket connection
607 // G. Giunta 2005/10/24: close socket before parsing.
608 // should yield slightly better execution times, and make easier recursive calls (e.g. to follow http redirects)
612 // shall we check for $data === FALSE?
613 // as per the manual, it signals an error
614 $ipd.=fread($fp, 32768);
617 $r =& $msg->parseResponse($ipd, false, $this->return_type);
625 function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='',
626 $password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='',
627 $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1,
628 $keepalive=false, $key='', $keypass='')
630 $r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username,
631 $password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport,
632 $proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass);
637 * Contributed by Justin Miller <justin@voxel.net>
638 * Requires curl to be built into PHP
639 * NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
642 function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='',
643 $password='', $authtype=1, $cert='', $certpass='', $cacert='', $cacertdir='',
644 $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $method='https',
645 $keepalive=false, $key='', $keypass='')
647 $xmlrpc = Xmlrpc::instance();
649 if(!function_exists('curl_init'))
651 $this->errstr='CURL unavailable on this install';
652 $r=new xmlrpcresp(0, $xmlrpc->xmlrpcerr['no_curl'], $xmlrpc->xmlrpcstr['no_curl']);
655 if($method == 'https')
657 if(($info = curl_version()) &&
658 ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))))
660 $this->errstr='SSL unavailable on this install';
661 $r=new xmlrpcresp(0, $xmlrpc->xmlrpcerr['no_ssl'], $xmlrpc->xmlrpcstr['no_ssl']);
668 if($method == 'http')
678 // Only create the payload if it was not created previously
679 if(empty($msg->payload))
681 $msg->createPayload($this->request_charset_encoding);
684 // Deflate request body and set appropriate request headers
685 $payload = $msg->payload;
686 if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
688 if($this->request_compression == 'gzip')
690 $a = @gzencode($payload);
694 $encoding_hdr = 'Content-Encoding: gzip';
699 $a = @gzcompress($payload);
703 $encoding_hdr = 'Content-Encoding: deflate';
714 print "<PRE>\n---SENDING---\n" . htmlentities($payload) . "\n---END---\n</PRE>";
715 // let the client see this now in case http times out...
719 if(!$keepalive || !$this->xmlrpc_curl_handle)
721 $curl = curl_init($method . '://' . $server . ':' . $port . $this->path);
724 $this->xmlrpc_curl_handle = $curl;
729 $curl = $this->xmlrpc_curl_handle;
732 // results into variable
733 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
737 curl_setopt($curl, CURLOPT_VERBOSE, 1);
739 curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent);
740 // required for XMLRPC: post the data
741 curl_setopt($curl, CURLOPT_POST, 1);
743 curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
745 // return the header too
746 curl_setopt($curl, CURLOPT_HEADER, 1);
748 // NB: if we set an empty string, CURL will add http header indicating
749 // ALL methods it is supporting. This is possibly a better option than
750 // letting the user tell what curl can / cannot do...
751 if(is_array($this->accepted_compression) && count($this->accepted_compression))
753 //curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression));
754 // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
755 if (count($this->accepted_compression) == 1)
757 curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]);
760 curl_setopt($curl, CURLOPT_ENCODING, '');
763 $headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings));
764 // if no keepalive is wanted, let the server know it in advance
767 $headers[] = 'Connection: close';
769 // request compression header
772 $headers[] = $encoding_hdr;
775 curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
779 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
782 if($username && $password)
784 curl_setopt($curl, CURLOPT_USERPWD, $username.':'.$password);
785 if (defined('CURLOPT_HTTPAUTH'))
787 curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype);
789 else if ($authtype != 1)
791 error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported by the current PHP/curl install');
795 if($method == 'https')
800 curl_setopt($curl, CURLOPT_SSLCERT, $cert);
805 curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass);
807 // whether to verify remote host's cert
808 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
809 // set ca certificates file/dir
812 curl_setopt($curl, CURLOPT_CAINFO, $cacert);
816 curl_setopt($curl, CURLOPT_CAPATH, $cacertdir);
818 // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
821 curl_setopt($curl, CURLOPT_SSLKEY, $key);
823 // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
826 curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass);
828 // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
829 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
837 $proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080
839 curl_setopt($curl, CURLOPT_PROXY, $proxyhost.':'.$proxyport);
840 //curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport);
843 curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword);
844 if (defined('CURLOPT_PROXYAUTH'))
846 curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype);
848 else if ($proxyauthtype != 1)
850 error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported by the current PHP/curl install');
855 // NB: should we build cookie http headers by hand rather than let CURL do it?
856 // the following code does not honour 'expires', 'path' and 'domain' cookie attributes
857 // set to client obj the the user...
858 if (count($this->cookies))
861 foreach ($this->cookies as $name => $cookie)
863 $cookieheader .= $name . '=' . $cookie['value'] . '; ';
865 curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2));
868 foreach ($this->extracurlopts as $opt => $val)
870 curl_setopt($curl, $opt, $val);
873 $result = curl_exec($curl);
875 if ($this->debug > 1)
877 print "<PRE>\n---CURL INFO---\n";
878 foreach(curl_getinfo($curl) as $name => $val)
882 $val = implode("\n", $val);
884 print $name . ': ' . htmlentities($val) . "\n";
887 print "---END---\n</PRE>";
890 if(!$result) /// @todo we should use a better check here - what if we get back '' or '0'?
892 $this->errstr='no response';
893 $resp=new xmlrpcresp(0, $xmlrpc->xmlrpcerr['curl_fail'], $xmlrpc->xmlrpcstr['curl_fail']. ': '. curl_error($curl));
897 $this->xmlrpc_curl_handle = null;
906 $resp =& $msg->parseResponse($result, true, $this->return_type);
907 // if we got back a 302, we can not reuse the curl handle for later calls
908 if($resp->faultCode() == $xmlrpc->xmlrpcerr['http_error'] && $keepalive)
911 $this->xmlrpc_curl_handle = null;
918 * Send an array of request messages and return an array of responses.
919 * Unless $this->no_multicall has been set to true, it will try first
920 * to use one single xmlrpc call to server method system.multicall, and
921 * revert to sending many successive calls in case of failure.
922 * This failure is also stored in $this->no_multicall for subsequent calls.
923 * Unfortunately, there is no server error code universally used to denote
924 * the fact that multicall is unsupported, so there is no way to reliably
925 * distinguish between that and a temporary failure.
926 * If you are sure that server supports multicall and do not want to
927 * fallback to using many single calls, set the fourth parameter to FALSE.
929 * NB: trying to shoehorn extra functionality into existing syntax has resulted
930 * in pretty much convoluted code...
932 * @param array $msgs an array of xmlrpcmsg objects
933 * @param integer $timeout connection timeout (in seconds)
934 * @param string $method the http protocol variant to be used
935 * @param boolean fallback When true, upon receiving an error during multicall, multiple single calls will be attempted
939 function multicall($msgs, $timeout=0, $method='', $fallback=true)
941 $xmlrpc = Xmlrpc::instance();
945 $method = $this->method;
947 if(!$this->no_multicall)
949 $results = $this->_try_multicall($msgs, $timeout, $method);
950 if(is_array($results))
952 // System.multicall succeeded
957 // either system.multicall is unsupported by server,
958 // or call failed for some other reason.
961 // Don't try it next time...
962 $this->no_multicall = true;
966 if (is_a($results, 'xmlrpcresp'))
972 $result = new xmlrpcresp(0, $xmlrpc->xmlrpcerr['multicall_error'], $xmlrpc->xmlrpcstr['multicall_error']);
979 // override fallback, in case careless user tries to do two
980 // opposite things at the same time
987 // system.multicall is (probably) unsupported by server:
988 // emulate multicall via multiple requests
989 foreach($msgs as $msg)
991 $results[] =& $this->send($msg, $timeout, $method);
996 // user does NOT want to fallback on many single calls:
997 // since we should always return an array of responses,
998 // return an array with the same error repeated n times
999 foreach($msgs as $msg)
1001 $results[] = $result;
1008 * Attempt to boxcar $msgs via system.multicall.
1009 * Returns either an array of xmlrpcreponses, an xmlrpc error response
1010 * or false (when received response does not respect valid multicall syntax)
1013 function _try_multicall($msgs, $timeout, $method)
1015 // Construct multicall message
1017 foreach($msgs as $msg)
1019 $call['methodName'] = new xmlrpcval($msg->method(),'string');
1020 $numParams = $msg->getNumParams();
1022 for($i = 0; $i < $numParams; $i++)
1024 $params[$i] = $msg->getParam($i);
1026 $call['params'] = new xmlrpcval($params, 'array');
1027 $calls[] = new xmlrpcval($call, 'struct');
1029 $multicall = new xmlrpcmsg('system.multicall');
1030 $multicall->addParam(new xmlrpcval($calls, 'array'));
1033 $result =& $this->send($multicall, $timeout, $method);
1035 if($result->faultCode() != 0)
1037 // call to system.multicall failed
1041 // Unpack responses.
1042 $rets = $result->value();
1044 if ($this->return_type == 'xml')
1048 else if ($this->return_type == 'phpvals')
1050 ///@todo test this code branch...
1051 $rets = $result->value();
1052 if(!is_array($rets))
1054 return false; // bad return type from system.multicall
1056 $numRets = count($rets);
1057 if($numRets != count($msgs))
1059 return false; // wrong number of return values.
1062 $response = array();
1063 for($i = 0; $i < $numRets; $i++)
1066 if (!is_array($val)) {
1074 return false; // Bad value
1076 // Normal return value
1077 $response[$i] = new xmlrpcresp($val[0], 0, '', 'phpvals');
1080 /// @todo remove usage of @: it is apparently quite slow
1081 $code = @$val['faultCode'];
1086 $str = @$val['faultString'];
1087 if(!is_string($str))
1091 $response[$i] = new xmlrpcresp(0, $code, $str);
1099 else // return type == 'xmlrpcvals'
1101 $rets = $result->value();
1102 if($rets->kindOf() != 'array')
1104 return false; // bad return type from system.multicall
1106 $numRets = $rets->arraysize();
1107 if($numRets != count($msgs))
1109 return false; // wrong number of return values.
1112 $response = array();
1113 for($i = 0; $i < $numRets; $i++)
1115 $val = $rets->arraymem($i);
1116 switch($val->kindOf())
1119 if($val->arraysize() != 1)
1121 return false; // Bad value
1123 // Normal return value
1124 $response[$i] = new xmlrpcresp($val->arraymem(0));
1127 $code = $val->structmem('faultCode');
1128 if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
1132 $str = $val->structmem('faultString');
1133 if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
1137 $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
1146 } // end class xmlrpc_client