\n---SENDING---\n" . htmlentities($op) . "\n---END---\n"; // let the client see this now in case http times out... flush(); } 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=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')'); return $r; } if(!fputs($fp, $op, strlen($op))) { fclose($fp); $this->errstr='Write error'; $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr); return $r; } else { // reset errno and errstr on successful socket connection $this->errstr = ''; } // G. Giunta 2005/10/24: close socket before parsing. // should yield slightly better execution times, and make easier recursive calls (e.g. to follow http redirects) $ipd=''; do { // shall we check for $data === FALSE? // as per the manual, it signals an error $ipd.=fread($fp, 32768); } while(!feof($fp)); fclose($fp); $r =& $msg->parseResponse($ipd, false, $this->return_type); return $r; } /** * @access private */ function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='', $password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='', $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $keepalive=false, $key='', $keypass='') { $r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, $password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport, $proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass); return $r; } /** * Contributed by Justin Miller
\n---SENDING---\n" . htmlentities($payload) . "\n---END---\n"; // let the client see this now in case http times out... flush(); } if(!$keepalive || !$this->xmlrpc_curl_handle) { $curl = curl_init($method . '://' . $server . ':' . $port . $this->path . ($this->extraUrlParams != null ? '?' . http_build_query($this->extraUrlParams) : '')); if($keepalive) { $this->xmlrpc_curl_handle = $curl; } } else { $curl = $this->xmlrpc_curl_handle; } // results into variable curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); if($this->debug) { curl_setopt($curl, CURLOPT_VERBOSE, 1); } curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent); // required for XMLRPC: post the data curl_setopt($curl, CURLOPT_POST, 1); // the data curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); // return the header too curl_setopt($curl, CURLOPT_HEADER, 1); // 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)); // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?) if (count($this->accepted_compression) == 1) { curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]); } else curl_setopt($curl, CURLOPT_ENCODING, ''); } // extra headers $headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings)); // 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 (defined('CURLOPT_HTTPAUTH')) { curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype); } else if ($authtype != 1) { error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported by the current PHP/curl install'); } } 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); } // whether to verify remote host's cert curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer); // set ca certificates file/dir if($cacert) { curl_setopt($curl, CURLOPT_CAINFO, $cacert); } if($cacertdir) { curl_setopt($curl, CURLOPT_CAPATH, $cacertdir); } // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?) if($key) { curl_setopt($curl, CURLOPT_SSLKEY, $key); } // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?) if($keypass) { curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass); } // 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); if (defined('CURLOPT_PROXYAUTH')) { curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype); } else if ($proxyauthtype != 1) { error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); } } } // NB: should we build cookie http headers by hand rather than let CURL do it? // the following code does not honour 'expires', 'path' and 'domain' cookie attributes // set to client obj the the user... if (count($this->cookies)) { $cookieheader = ''; foreach ($this->cookies as $name => $cookie) { $cookieheader .= $name . '=' . $cookie['value'] . '; '; } curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2)); } foreach ($this->extracurlopts as $opt => $val) { curl_setopt($curl, $opt, $val); } $result = curl_exec($curl); if ($this->debug > 1) { print "
\n---CURL INFO---\n";
foreach(curl_getinfo($curl) as $name => $val)
{
if (is_array($val))
{
$val = implode("\n", $val);
}
print $name . ': ' . htmlentities($val) . "\n";
}
print "---END---\n";
}
$this->curlError = curl_error($curl);
if ($this->curlError){
$this->curlInfo = curl_getinfo($curl);
$this->curlErrorNo = curl_errno($curl);
}
if(!$result) /// @todo we should use a better check here - what if we get back '' or '0'?
{
$this->errstr='no response';
$resp=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl));
curl_close($curl);
if($keepalive)
{
$this->xmlrpc_curl_handle = null;
}
}
else
{
if(!$keepalive)
{
curl_close($curl);
}
$resp =& $msg->parseResponse($result, true, $this->return_type);
// if we got back a 302, we can not reuse the curl handle for later calls
if($resp->faultCode() == $GLOBALS['xmlrpcerr']['http_error'] && $keepalive)
{
curl_close($curl);
$this->xmlrpc_curl_handle = null;
}
}
return $resp;
}
/**
* Send an array of request messages and return an array of responses.
* Unless $this->no_multicall has been set to true, it will try first
* to use one single xmlrpc call to server method system.multicall, and
* revert to sending many successive calls in case of failure.
* This failure is also stored in $this->no_multicall for subsequent calls.
* Unfortunately, there is no server error code universally used to denote
* the fact that multicall is unsupported, so there is no way to reliably
* distinguish between that and a temporary failure.
* If you are sure that server supports multicall and do not want to
* fallback to using many single calls, set the fourth parameter to FALSE.
*
* NB: trying to shoehorn extra functionality into existing syntax has resulted
* in pretty much convoluted code...
*
* @param array $msgs an array of xmlrpcmsg objects
* @param integer $timeout connection timeout (in seconds)
* @param string $method the http protocol variant to be used
* @param boolean fallback When true, upon receiving an error during multicall, multiple single calls will be attempted
* @return array
* @access public
*/
function multicall($msgs, $timeout=0, $method='', $fallback=true)
{
if ($method == '')
{
$method = $this->method;
}
if(!$this->no_multicall)
{
$results = $this->_try_multicall($msgs, $timeout, $method);
if(is_array($results))
{
// System.multicall succeeded
return $results;
}
else
{
// either system.multicall is unsupported by server,
// or call failed for some other reason.
if ($fallback)
{
// Don't try it next time...
$this->no_multicall = true;
}
else
{
if (is_a($results, 'xmlrpcresp'))
{
$result = $results;
}
else
{
$result = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']);
}
}
}
}
else
{
// override fallback, in case careless user tries to do two
// opposite things at the same time
$fallback = true;
}
$results = array();
if ($fallback)
{
// system.multicall is (probably) unsupported by server:
// emulate multicall via multiple requests
foreach($msgs as $msg)
{
$results[] =& $this->send($msg, $timeout, $method);
}
}
else
{
// user does NOT want to fallback on many single calls:
// since we should always return an array of responses,
// return an array with the same error repeated n times
foreach($msgs as $msg)
{
$results[] = $result;
}
}
return $results;
}
/**
* Attempt to boxcar $msgs via system.multicall.
* Returns either an array of xmlrpcreponses, an xmlrpc error response
* or false (when received response does not respect valid multicall syntax)
* @access private
*/
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($result->faultCode() != 0)
{
// call to system.multicall failed
return $result;
}
// Unpack responses.
$rets = $result->value();
if ($this->return_type == 'xml')
{
return $rets;
}
else if ($this->return_type == 'phpvals')
{
///@todo test this code branch...
$rets = $result->value();
if(!is_array($rets))
{
return false; // bad return type from system.multicall
}
$numRets = count($rets);
if($numRets != count($msgs))
{
return false; // wrong number of return values.
}
$response = array();
for($i = 0; $i < $numRets; $i++)
{
$val = $rets[$i];
if (!is_array($val)) {
return false;
}
switch(count($val))
{
case 1:
if(!isset($val[0]))
{
return false; // Bad value
}
// Normal return value
$response[$i] = new xmlrpcresp($val[0], 0, '', 'phpvals');
break;
case 2:
/// @todo remove usage of @: it is apparently quite slow
$code = @$val['faultCode'];
if(!is_int($code))
{
return false;
}
$str = @$val['faultString'];
if(!is_string($str))
{
return false;
}
$response[$i] = new xmlrpcresp(0, $code, $str);
break;
default:
return false;
}
}
return $response;
}
else // return type == 'xmlrpcvals'
{
$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
class xmlrpcresp
{
var $val = 0;
var $valtyp;
var $errno = 0;
var $errstr = '';
var $payload;
var $hdrs = array();
var $_cookies = array();
var $content_type = 'text/xml';
var $raw_data = '';
/**
* @param mixed $val either an xmlrpcval obj, a php value or the xml serialization of an xmlrpcval (a string)
* @param integer $fcode set it to anything but 0 to create an error response
* @param string $fstr the error string, in case of an error response
* @param string $valtyp either 'xmlrpcvals', 'phpvals' or 'xml'
*
* @todo add check that $val / $fcode / $fstr is of correct type???
* NB: as of now we do not do it, since it might be either an xmlrpcval or a plain
* php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called...
*/
function __construct($val, $fcode = 0, $fstr = '', $valtyp='')
{
if($fcode != 0)
{
// error response
$this->errno = $fcode;
$this->errstr = $fstr;
//$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
}
else
{
// successful response
$this->val = $val;
if ($valtyp == '')
{
// user did not declare type of response value: try to guess it
if (is_object($this->val) && is_a($this->val, 'xmlrpcval'))
{
$this->valtyp = 'xmlrpcvals';
}
else if (is_string($this->val))
{
$this->valtyp = 'xml';
}
else
{
$this->valtyp = 'phpvals';
}
}
else
{
// user declares type of resp value: believe him
$this->valtyp = $valtyp;
}
}
}
/**
* Returns the error code of the response.
* @return integer the error code of this response (0 for not-error responses)
* @access public
*/
function faultCode()
{
return $this->errno;
}
/**
* Returns the error code of the response.
* @return string the error string of this response ('' for not-error responses)
* @access public
*/
function faultString()
{
return $this->errstr;
}
/**
* Returns the value received by the server.
* @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects
* @access public
*/
function value()
{
return $this->val;
}
/**
* Returns an array with the cookies received from the server.
* Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 = $val2, ...)
* with attributes being e.g. 'expires', 'path', domain'.
* NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past)
* are still present in the array. It is up to the user-defined code to decide
* how to use the received cookies, and whether they have to be sent back with the next
* request to the server (using xmlrpc_client::setCookie) or not
* @return array array of cookies received from the server
* @access public
*/
function cookies()
{
return $this->_cookies;
}
/**
* Returns xml representation of the response. XML prologue not included
* @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
* @return string the xml representation of the response
* @access public
*/
function serialize($charset_encoding='')
{
if ($charset_encoding != '')
$this->content_type = 'text/xml; charset=' . $charset_encoding;
else
$this->content_type = 'text/xml';
if ($GLOBALS['xmlrpc_null_apache_encoding'])
{
$result = "';
foreach($GLOBALS['_xh']['headers'] as $header => $value)
{
print htmlentities("HEADER: $header: $value\n");
}
foreach($GLOBALS['_xh']['cookies'] as $header => $value)
{
print htmlentities("COOKIE: $header={$value['value']}\n");
}
print "\n";
}
// if CURL was used for the call, http headers have been processed,
// and dechunking + reinflating have been carried out
if(!$headers_processed)
{
// Decode chunked encoding sent by http 1.1 servers
if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked')
{
if(!$data = decode_chunked($data))
{
error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to rebuild the chunked data received from server');
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);
return $r;
}
}
// Decode gzip-compressed stuff
// code shamelessly inspired from nusoap library by Dietrich Ayala
if(isset($GLOBALS['_xh']['headers']['content-encoding']))
{
$GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']);
if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip')
{
// if decoding works, use it. else assume data wasn't gzencoded
if(function_exists('gzinflate'))
{
if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data))
{
$data = $degzdata;
if($this->debug)
print "---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---"; } elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10))) { $data = $degzdata; if($this->debug) print "
---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---"; } else { error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to decode the deflated data received from server'); $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']); return $r; } } else { error_log('XML-RPC: '.__METHOD__.': the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']); return $r; } } } } // end of 'if needed, de-chunk, re-inflate response' // real stupid hack to avoid PHP complaining about returning NULL by ref $r = null; $r =& $r; return $r; } /** * Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object. * @param string $data the xmlrpc response, eventually including http headers * @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding * @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals' * @return xmlrpcresp * @access public */ function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals') { if($this->debug) { //by maHo, replaced htmlspecialchars with htmlentities print "
---GOT---\n" . htmlentities($data) . "\n---END---\n"; } if($data == '') { error_log('XML-RPC: '.__METHOD__.': no response received from server.'); $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']); return $r; } $GLOBALS['_xh']=array(); $raw_data = $data; // parse the HTTP headers of the response, if present, and separate them from data if(substr($data, 0, 4) == 'HTTP') { $r =& $this->parseResponseHeaders($data, $headers_processed); if ($r) { // failed processing of HTTP response headers // save into response obj the full payload received, for debugging $r->raw_data = $data; return $r; } } else { $GLOBALS['_xh']['headers'] = array(); $GLOBALS['_xh']['cookies'] = array(); } if($this->debug) { $start = strpos($data, '', $start); $comments = substr($data, $start, $end-$start); print "
---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n";
}
}
// be tolerant of extra whitespace in response body
$data = trim($data);
/// @todo return an error msg if $data=='' ?
// be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts)
// idea from Luca Mariano ---PARSED---\n";
// somehow htmlentities chokes on var_export, and some full html string...
//print htmlentitites(var_export($GLOBALS['_xh']['value'], true));
print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true));
print "\n---END---";
}
// note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object.
$v =& $GLOBALS['_xh']['value'];
if($GLOBALS['_xh']['isf'])
{
/// @todo we should test here if server sent an int and a string,
/// and/or coerce them into such...
if ($return_type == 'xmlrpcvals')
{
$errno_v = $v->structmem('faultCode');
$errstr_v = $v->structmem('faultString');
$errno = $errno_v->scalarval();
$errstr = $errstr_v->scalarval();
}
else
{
$errno = $v['faultCode'];
$errstr = $v['faultString'];
}
if($errno == 0)
{
// FAULT returned, errno needs to reflect that
$errno = -1;
}
$r = new xmlrpcresp(0, $errno, $errstr);
}
else
{
$r=new xmlrpcresp($v, 0, '', $return_type);
}
}
$r->hdrs = $GLOBALS['_xh']['headers'];
$r->_cookies = $GLOBALS['_xh']['cookies'];
$r->raw_data = $raw_data;
return $r;
}
}
class xmlrpcval
{
var $me=array();
var $mytype=0;
var $_php_class=null;
/**
* @param mixed $val
* @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
*/
function __construct($val=-1, $type='')
{
/// @todo: optimization creep - do not call addXX, do it all inline.
/// downside: booleans will not be coerced anymore
if($val!==-1 || $type!='')
{
// optimization creep: inlined all work done by constructor
switch($type)
{
case '':
$this->mytype=1;
$this->me['string']=$val;
break;
case 'i4':
case 'int':
case 'double':
case 'string':
case 'boolean':
case 'dateTime.iso8601':
case 'base64':
case 'null':
$this->mytype=1;
$this->me[$type]=$val;
break;
case 'array':
$this->mytype=2;
$this->me['array']=$val;
break;
case 'struct':
$this->mytype=3;
$this->me['struct']=$val;
break;
default:
error_log("XML-RPC: ".__METHOD__.": not a known type ($type)");
}
/*if($type=='')
{
$type='string';
}
if($GLOBALS['xmlrpcTypes'][$type]==1)
{
$this->addScalar($val,$type);
}
elseif($GLOBALS['xmlrpcTypes'][$type]==2)
{
$this->addArray($val);
}
elseif($GLOBALS['xmlrpcTypes'][$type]==3)
{
$this->addStruct($val);
}*/
}
}
/**
* Add a single php value to an (unitialized) xmlrpcval
* @param mixed $val
* @param string $type
* @return int 1 or 0 on failure
*/
function addScalar($val, $type='string')
{
$typeof=@$GLOBALS['xmlrpcTypes'][$type];
if($typeof!=1)
{
error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)");
return 0;
}
// coerce booleans into correct values
// NB: we should either do it for datetimes, integers and doubles, too,
// or just plain remove this check, implemented on booleans only...
if($type==$GLOBALS['xmlrpcBoolean'])
{
if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
{
$val=true;
}
else
{
$val=false;
}
}
switch($this->mytype)
{
case 1:
error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value');
return 0;
case 3:
error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval');
return 0;
case 2:
// we're adding a scalar value to an array here
//$ar=$this->me['array'];
//$ar[]=new xmlrpcval($val, $type);
//$this->me['array']=$ar;
// Faster (?) avoid all the costly array-copy-by-val done here...
$this->me['array'][]=new xmlrpcval($val, $type);
return 1;
default:
// a scalar, so set the value and remember we're scalar
$this->me[$type]=$val;
$this->mytype=$typeof;
return 1;
}
}
/**
* Add an array of xmlrpcval objects to an xmlrpcval
* @param array $vals
* @return int 1 or 0 on failure
* @access public
*
* @todo add some checking for $vals to be an array of xmlrpcvals?
*/
function addArray($vals)
{
if($this->mytype==0)
{
$this->mytype=$GLOBALS['xmlrpcTypes']['array'];
$this->me['array']=$vals;
return 1;
}
elseif($this->mytype==2)
{
// we're adding to an array here
$this->me['array'] = array_merge($this->me['array'], $vals);
return 1;
}
else
{
error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
return 0;
}
}
/**
* Add an array of named xmlrpcval objects to an xmlrpcval
* @param array $vals
* @return int 1 or 0 on failure
* @access public
*
* @todo add some checking for $vals to be an array?
*/
function addStruct($vals)
{
if($this->mytype==0)
{
$this->mytype=$GLOBALS['xmlrpcTypes']['struct'];
$this->me['struct']=$vals;
return 1;
}
elseif($this->mytype==3)
{
// we're adding to a struct here
$this->me['struct'] = array_merge($this->me['struct'], $vals);
return 1;
}
else
{
error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
return 0;
}
}
// poor man's version of print_r ???
// DEPRECATED!
function dump($ar)
{
foreach($ar as $key => $val)
{
echo "$key => $val