forked from extern/egroupware
HEAD only: Add client from 2.0 lib - adds compression, proxy auth, etc.
This commit is contained in:
parent
e726d3f7ae
commit
7d18902b97
@ -37,20 +37,111 @@
|
||||
{
|
||||
var $path;
|
||||
var $server;
|
||||
var $port;
|
||||
var $port=0;
|
||||
var $method='http';
|
||||
var $errno;
|
||||
var $errstring;
|
||||
var $errstr;
|
||||
var $debug=0;
|
||||
var $username='';
|
||||
var $password='';
|
||||
var $cert='';
|
||||
var $certpass='';
|
||||
var $verifypeer=1;
|
||||
var $verifyhost=1;
|
||||
var $no_multicall=False;
|
||||
var $proxy = '';
|
||||
var $proxyport=0;
|
||||
var $proxy_user = '';
|
||||
var $proxy_pass = '';
|
||||
/**
|
||||
* List of http compression methods accepted by the client for responses.
|
||||
* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
|
||||
*
|
||||
* NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since
|
||||
* in those cases it will be up to CURL to decide the compression methods
|
||||
* it supports. You might check for the presence of 'zlib' in the output of
|
||||
* curl_version() to determine wheter compression is supported or not
|
||||
*/
|
||||
var $accepted_compression = array();
|
||||
/**
|
||||
* Name of compression scheme to be used for sending requests.
|
||||
* Either null, gzip or deflate
|
||||
*/
|
||||
var $request_compression = '';
|
||||
/**
|
||||
* CURL handle: used for keep-alive connections (PHP 4.3.8 up, see:
|
||||
* http://curl.haxx.se/docs/faq.html#7.3)
|
||||
*/
|
||||
var $xmlrpc_curl_handle = null;
|
||||
/// Whether to use persistent connections for http 1.1 and https
|
||||
var $keepalive = false;
|
||||
|
||||
function xmlrpc_client($path='', $server='', $port=0)
|
||||
function xmlrpc_client($path, $server='', $port='', $method='')
|
||||
{
|
||||
// allow user to specify all params in $path
|
||||
if($server == '' and $port == '' and $method == '')
|
||||
{
|
||||
$parts = parse_url($path);
|
||||
$server = $parts['host'];
|
||||
$path = $parts['path'];
|
||||
if(isset($parts['query']))
|
||||
{
|
||||
$path .= '?'.$parts['query'];
|
||||
}
|
||||
if(isset($parts['fragment']))
|
||||
{
|
||||
$path .= '#'.$parts['fragment'];
|
||||
}
|
||||
if(isset($parts['port']))
|
||||
{
|
||||
$port = $parts['port'];
|
||||
}
|
||||
if(isset($parts['scheme']))
|
||||
{
|
||||
$method = $parts['scheme'];
|
||||
}
|
||||
if(isset($parts['user']))
|
||||
{
|
||||
$this->username = $parts['user'];
|
||||
}
|
||||
if(isset($parts['pass']))
|
||||
{
|
||||
$this->password = $parts['pass'];
|
||||
}
|
||||
}
|
||||
if($path == '' || $path[0] != '/')
|
||||
{
|
||||
$this->path='/'.$path;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->path=$path;
|
||||
}
|
||||
$this->server=$server;
|
||||
if($port != '')
|
||||
{
|
||||
$this->port=$port;
|
||||
$this->server = $server;
|
||||
$this->path = $path;
|
||||
}
|
||||
if($method != '')
|
||||
{
|
||||
$this->method=$method;
|
||||
}
|
||||
|
||||
// if ZLIB is enabled, let the server by default accept compressed requests
|
||||
if(function_exists('gzinflate') || (
|
||||
function_exists('curl_init') && (($info = curl_version()) &&
|
||||
((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
|
||||
))
|
||||
{
|
||||
$this->accepted_compression = array('gzip', 'deflate');
|
||||
}
|
||||
|
||||
// keepalives: enabled by default ONLY for PHP >= 4.3.8
|
||||
// (see http://curl.haxx.se/docs/faq.html#7.3)
|
||||
if(version_compare(phpversion(), '4.3.8') >= 0)
|
||||
{
|
||||
$this->keepalive = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setDebug($in)
|
||||
@ -77,14 +168,61 @@
|
||||
$this->certpass = $certpass;
|
||||
}
|
||||
|
||||
function send($msg, $timeout=0, $method='http')
|
||||
function setSSLVerifyPeer($i)
|
||||
{
|
||||
/* where msg is an xmlrpcmsg */
|
||||
$this->verifypeer = $i;
|
||||
}
|
||||
|
||||
function setSSLVerifyHost($i)
|
||||
{
|
||||
$this->verifyhost = $i;
|
||||
}
|
||||
/**
|
||||
* set proxy info
|
||||
*
|
||||
* @param string $proxyhost
|
||||
* @param string $proxyport. Defaults to 8080 for HTTP and 443 for HTTPS
|
||||
* @param string $proxyusername
|
||||
* @param string $proxypassword
|
||||
* @access public
|
||||
*/
|
||||
function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
|
||||
{
|
||||
$this->proxy = $proxyhost;
|
||||
$this->proxyport = $proxyport;
|
||||
$this->proxy_user = $proxyusername;
|
||||
$this->proxy_pass = $proxypassword;
|
||||
}
|
||||
|
||||
function& send($msg, $timeout=0, $method='')
|
||||
{
|
||||
// if user does not specify http protocol, use native method of this client
|
||||
// (i.e. method set during call to constructor)
|
||||
if($method == '')
|
||||
{
|
||||
$method = $this->method;
|
||||
}
|
||||
|
||||
if(is_array($msg))
|
||||
{
|
||||
// $msg is an array of xmlrpcmsg's
|
||||
$r =& $this->multicall($msg, $timeout, $method);
|
||||
return $r;
|
||||
}
|
||||
elseif(is_string($msg))
|
||||
{
|
||||
$n =& new xmlrpcmsg('');
|
||||
$n->payload = $msg;
|
||||
$msg = $n;
|
||||
}
|
||||
|
||||
// where msg is an xmlrpcmsg
|
||||
$msg->debug=$this->debug;
|
||||
|
||||
if ($method == 'https')
|
||||
switch($method)
|
||||
{
|
||||
return $this->sendPayloadHTTPS(
|
||||
case 'https':
|
||||
$r =& $this->sendPayloadHTTPS(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
@ -92,38 +230,161 @@
|
||||
$this->username,
|
||||
$this->password,
|
||||
$this->cert,
|
||||
$this->certpass
|
||||
$this->certpass,
|
||||
$this->proxy,
|
||||
$this->proxyport,
|
||||
$this->proxy_user,
|
||||
$this->proxy_pass,
|
||||
'https',
|
||||
$this->keepalive
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->sendPayloadHTTP10(
|
||||
break;
|
||||
case 'http11':
|
||||
$r =& $this->sendPayloadCURL(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password
|
||||
$this->password,
|
||||
null,
|
||||
null,
|
||||
$this->proxy,
|
||||
$this->proxyport,
|
||||
$this->proxy_user,
|
||||
$this->proxy_pass,
|
||||
'http',
|
||||
$this->keepalive
|
||||
);
|
||||
break;
|
||||
case 'http10':
|
||||
default:
|
||||
$r =& $this->sendPayloadHTTP10(
|
||||
$msg,
|
||||
$this->server,
|
||||
$this->port,
|
||||
$timeout,
|
||||
$this->username,
|
||||
$this->password,
|
||||
$this->proxy,
|
||||
$this->proxyport,
|
||||
$this->proxy_user,
|
||||
$this->proxy_pass
|
||||
);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
|
||||
function &sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='',
|
||||
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='')
|
||||
{
|
||||
if($port==0)
|
||||
{
|
||||
$port=80;
|
||||
}
|
||||
if($timeout>0)
|
||||
|
||||
// Only create the payload if it was not created previously
|
||||
if(empty($msg->payload))
|
||||
{
|
||||
$fp = fsockopen($server, $port, &$this->errno, &$this->errstr, $timeout);
|
||||
$msg->createPayload();
|
||||
}
|
||||
|
||||
// Deflate request body and set appropriate request headers
|
||||
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
|
||||
{
|
||||
if($this->request_compression == 'gzip')
|
||||
{
|
||||
$a = @gzencode($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: gzip\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$fp = fsockopen($server, $port, &$this->errno, &$this->errstr);
|
||||
}
|
||||
if (!$fp)
|
||||
$a = @gzdeflate($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: deflate\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$encoding_hdr = '';
|
||||
}
|
||||
|
||||
// thanks to Grant Rauscher <grant7@firstworld.net>
|
||||
// for this
|
||||
$credentials='';
|
||||
if($username!='')
|
||||
{
|
||||
$credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
|
||||
}
|
||||
|
||||
$accepted_encoding = '';
|
||||
if(is_array($this->accepted_compression) && count($this->accepted_compression))
|
||||
{
|
||||
$accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n";
|
||||
}
|
||||
|
||||
$proxy_credentials = '';
|
||||
if($proxyhost)
|
||||
{
|
||||
if($proxyport == 0)
|
||||
{
|
||||
$proxyport = 8080;
|
||||
}
|
||||
$connectserver = $proxyhost;
|
||||
$connectport = $proxyport;
|
||||
$uri = 'http://'.$server.':'.$port.$this->path;
|
||||
if($proxyusername != '')
|
||||
{
|
||||
$proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$connectserver = $server;
|
||||
$connectport = $port;
|
||||
$uri = $this->path;
|
||||
}
|
||||
|
||||
$op= "POST " . $uri. " HTTP/1.0\r\n"
|
||||
. "User-Agent: " . $GLOBALS['xmlrpcName'] . " " . $GLOBALS['xmlrpcVersion'] . "\r\n"
|
||||
. 'X-EGW-Server: ' . $this->server . ' ' . "\r\n"
|
||||
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
|
||||
. "Host: ". $this->server . "\r\n"
|
||||
. $credentials
|
||||
. $proxy_credentials
|
||||
. $accepted_encoding
|
||||
. $encoding_hdr
|
||||
. "Accept-Charset: " . $GLOBALS['xmlrpc_defencoding'] . "\r\n"
|
||||
. "Content-Type: text/xml\r\nContent-Length: "
|
||||
. strlen($msg->payload) . "\r\n\r\n"
|
||||
. $msg->payload;
|
||||
|
||||
if($timeout>0)
|
||||
{
|
||||
$fp = @fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
$fp = @fsockopen($connectserver, $connectport, $this->errno, $this->errstr);
|
||||
}
|
||||
if($fp)
|
||||
{
|
||||
if($timeout>0 && function_exists('stream_set_timeout'))
|
||||
{
|
||||
stream_set_timeout($fp, $timeout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errstr='Connect error: '.$this->errstr;
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
@ -132,28 +393,6 @@
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
// Only create the payload if it was not created previously
|
||||
if(empty($msg->payload))
|
||||
{
|
||||
$msg->createPayload();
|
||||
}
|
||||
|
||||
// thanks to Grant Rauscher <grant7@firstworld.net>
|
||||
// for this
|
||||
$credentials = '';
|
||||
if ($username && $password)
|
||||
{
|
||||
$credentials = 'Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
|
||||
}
|
||||
|
||||
$op = 'POST ' . $this->path . " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 2.0\r\n"
|
||||
. 'Host: '. $this->server . "\r\n"
|
||||
. 'X-EGW-Server: ' . $this->server . ' ' . "\r\n"
|
||||
. 'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'] . "\r\n"
|
||||
. $credentials
|
||||
. "Content-Type: text/xml\r\nContent-Length: "
|
||||
. strlen($msg->payload) . "\r\n\r\n"
|
||||
. $msg->payload;
|
||||
|
||||
if(!fputs($fp, $op, strlen($op)))
|
||||
{
|
||||
@ -165,72 +404,203 @@
|
||||
$GLOBALS['xmlrpcstr']['http_error']
|
||||
);
|
||||
}
|
||||
$resp = $msg->parseResponseFile($fp);
|
||||
else
|
||||
{
|
||||
// should we reset errno and errstr on succesful socket connection?
|
||||
}
|
||||
$resp =& $msg->parseResponseFile($fp);
|
||||
// shall we move this into parseresponsefile, cuz' we have to close the socket 1st
|
||||
// and do the parsing second if we want to have recursive calls
|
||||
// (i.e. redirects)
|
||||
fclose($fp);
|
||||
return $resp;
|
||||
}
|
||||
|
||||
/* contributed by Justin Miller <justin@voxel.net> - requires curl to be built into PHP */
|
||||
function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='')
|
||||
// contributed by Justin Miller <justin@voxel.net>
|
||||
// requires curl to be built into PHP
|
||||
// NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
|
||||
function &sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='',
|
||||
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $keepalive=false)
|
||||
{
|
||||
$r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, $password, $cert, $certpass,
|
||||
$proxyhost, $proxyport, $proxyusername, $proxypassword, $keepalive);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='', $password='', $cert='', $certpass='',
|
||||
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $method='https', $keepalive=false)
|
||||
{
|
||||
if(!function_exists('curl_init'))
|
||||
{
|
||||
return CreateObject(
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['no_curl'],
|
||||
$GLOBALS['xmlrpcstr']['no_curl']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
|
||||
if($method == 'https')
|
||||
{
|
||||
if(($info = curl_version()) &&
|
||||
((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))))
|
||||
{
|
||||
$this->errstr = 'SSL unavailable on this install';
|
||||
$r = CreateObject(
|
||||
'phpgwapi.xmlrpcresp',
|
||||
'',
|
||||
$GLOBALS['xmlrpcerr']['no_ssl'],
|
||||
$GLOBALS['xmlrpcstr']['no_ssl']
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
if($port == 0)
|
||||
{
|
||||
if($method == 'http')
|
||||
{
|
||||
$port = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
$port = 443;
|
||||
}
|
||||
/* Only create the payload if it was not created previously */
|
||||
}
|
||||
|
||||
// Only create the payload if it was not created previously
|
||||
if(empty($msg->payload))
|
||||
{
|
||||
$msg->createPayload();
|
||||
}
|
||||
|
||||
$curl = curl_init('https://' . $server . ':' . $port . $this->path);
|
||||
// Deflate request body and set appropriate request headers
|
||||
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
|
||||
{
|
||||
if($this->request_compression == 'gzip')
|
||||
{
|
||||
$a = @gzencode($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: gzip";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$a = @gzdeflate($msg->payload);
|
||||
if($a)
|
||||
{
|
||||
$msg->payload = $a;
|
||||
$encoding_hdr = "Content-Encoding: deflate";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$encoding_hdr = '';
|
||||
}
|
||||
|
||||
if(!$keepalive || !$this->xmlrpc_curl_handle)
|
||||
{
|
||||
$curl = curl_init($method . '://' . $server . ':' . $port . $this->path);
|
||||
if($keepalive)
|
||||
{
|
||||
$this->xmlrpc_curl_handle = $curl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$curl = $this->xmlrpc_curl_handle;
|
||||
}
|
||||
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
// results into variable
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
if($this->debug)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_VERBOSE, 1);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC 1.0');
|
||||
// required for XMLRPC
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']);
|
||||
// required for XMLRPC: post the data
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
// post the data
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
|
||||
// the data
|
||||
curl_setopt($curl, CURLOPT_HEADER, 1);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
|
||||
|
||||
// return the header too
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
|
||||
'X-EGW-Server: ' . $this->server,
|
||||
'X-EGW-Version: ' . $GLOBALS['egw_info']['server']['versions']['phpgwapi'],
|
||||
'Content-Type: text/xml'
|
||||
));
|
||||
|
||||
// will only work with PHP >= 5.0
|
||||
// NB: if we set an empty string, CURL will add http header indicating
|
||||
// ALL methods it is supporting. This is possibly a better option than
|
||||
// letting the user tell what curl can / cannot do...
|
||||
if(is_array($this->accepted_compression) && count($this->accepted_compression))
|
||||
{
|
||||
//curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression));
|
||||
curl_setopt($curl, CURLOPT_ENCODING, '');
|
||||
}
|
||||
// extra headers
|
||||
$headers = array('Content-Type: text/xml', 'Accept-Charset: '.$GLOBALS['xmlrpc_internalencoding']);
|
||||
// if no keepalive is wanted, let the server know it in advance
|
||||
if(!$keepalive)
|
||||
{
|
||||
$headers[] = 'Connection: close';
|
||||
}
|
||||
// request compression header
|
||||
if($encoding_hdr)
|
||||
{
|
||||
$headers[] = $encoding_hdr;
|
||||
}
|
||||
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
// timeout is borked
|
||||
if($timeout)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
|
||||
}
|
||||
|
||||
if($username && $password)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
|
||||
}
|
||||
|
||||
if($method == 'https')
|
||||
{
|
||||
// set cert file
|
||||
if($cert)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSLCERT, $cert);
|
||||
}
|
||||
// set cert password
|
||||
if($certpass)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass);
|
||||
}
|
||||
// set cert password
|
||||
// whether to verify remote host's cert
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
|
||||
// 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
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
|
||||
}
|
||||
|
||||
// proxy info
|
||||
if($proxyhost)
|
||||
{
|
||||
if($proxyport == 0)
|
||||
{
|
||||
$proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_PROXY,$proxyhost.':'.$proxyport);
|
||||
//curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport);
|
||||
if($proxyusername)
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword);
|
||||
}
|
||||
}
|
||||
|
||||
$result = curl_exec($curl);
|
||||
|
||||
@ -243,14 +613,130 @@
|
||||
$GLOBALS['xmlrpcerr']['curl_fail'],
|
||||
$GLOBALS['xmlrpcstr']['curl_fail'] . ': ' . curl_error($curl)
|
||||
);
|
||||
if(!$keepalive)
|
||||
{
|
||||
curl_close($curl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$resp = $msg->parseResponse($result);
|
||||
}
|
||||
if(!$keepalive)
|
||||
{
|
||||
curl_close($curl);
|
||||
|
||||
}
|
||||
$resp =& $msg->parseResponse($result, true);
|
||||
}
|
||||
return $resp;
|
||||
}
|
||||
|
||||
function& multicall($msgs, $timeout=0, $method='http')
|
||||
{
|
||||
$results = false;
|
||||
|
||||
if(!$this->no_multicall)
|
||||
{
|
||||
$results = $this->_try_multicall($msgs, $timeout, $method);
|
||||
if($results !== false)
|
||||
{
|
||||
// Either the system.multicall succeeded, or the send
|
||||
// failed (e.g. due to HTTP timeout). In either case,
|
||||
// we're done for now.
|
||||
return $results;
|
||||
}
|
||||
else
|
||||
{
|
||||
// system.multicall unsupported by server,
|
||||
// don't try it next time...
|
||||
$this->no_multicall = true;
|
||||
}
|
||||
}
|
||||
|
||||
// system.multicall is unupported by server:
|
||||
// Emulate multicall via multiple requests
|
||||
$results = array();
|
||||
foreach($msgs as $msg)
|
||||
{
|
||||
$results[] =& $this->send($msg, $timeout, $method);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Attempt to boxcar $msgs via system.multicall.
|
||||
function _try_multicall($msgs, $timeout, $method)
|
||||
{
|
||||
// Construct multicall message
|
||||
$calls = array();
|
||||
foreach($msgs as $msg)
|
||||
{
|
||||
$call['methodName'] =& new xmlrpcval($msg->method(),'string');
|
||||
$numParams = $msg->getNumParams();
|
||||
$params = array();
|
||||
for($i = 0; $i < $numParams; $i++)
|
||||
{
|
||||
$params[$i] = $msg->getParam($i);
|
||||
}
|
||||
$call['params'] =& new xmlrpcval($params, 'array');
|
||||
$calls[] =& new xmlrpcval($call, 'struct');
|
||||
}
|
||||
$multicall =& new xmlrpcmsg('system.multicall');
|
||||
$multicall->addParam(new xmlrpcval($calls, 'array'));
|
||||
|
||||
// Attempt RPC call
|
||||
$result =& $this->send($multicall, $timeout, $method);
|
||||
//if(!is_object($result))
|
||||
//{
|
||||
// return ($result || 0); // transport failed
|
||||
//}
|
||||
|
||||
if($result->faultCode() != 0)
|
||||
{
|
||||
return false; // system.multicall failed
|
||||
}
|
||||
|
||||
// Unpack responses.
|
||||
$rets = $result->value();
|
||||
if($rets->kindOf() != 'array')
|
||||
{
|
||||
return false; // bad return type from system.multicall
|
||||
}
|
||||
$numRets = $rets->arraysize();
|
||||
if($numRets != count($msgs))
|
||||
{
|
||||
return false; // wrong number of return values.
|
||||
}
|
||||
|
||||
$response = array();
|
||||
for($i = 0; $i < $numRets; $i++)
|
||||
{
|
||||
$val = $rets->arraymem($i);
|
||||
switch($val->kindOf())
|
||||
{
|
||||
case 'array':
|
||||
if($val->arraysize() != 1)
|
||||
{
|
||||
return false; // Bad value
|
||||
}
|
||||
// Normal return value
|
||||
$response[$i] =& new xmlrpcresp($val->arraymem(0));
|
||||
break;
|
||||
case 'struct':
|
||||
$code = $val->structmem('faultCode');
|
||||
if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$str = $val->structmem('faultString');
|
||||
if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$response[$i] =& new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
} // end class xmlrpc_client
|
||||
?>
|
||||
|
Loading…
Reference in New Issue
Block a user