mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-17 04:00:45 +01:00
385 lines
12 KiB
PHP
385 lines
12 KiB
PHP
<?php
|
|
// by Edd Dumbill (C) 1999-2001
|
|
// <edd@usefulinc.com>
|
|
// xmlrpc.inc,v 1.18 2001/07/06 18:23:57 edmundd
|
|
|
|
// License is granted to use or modify this software ('XML-RPC for PHP')
|
|
// for commercial or non-commercial use provided the copyright of the author
|
|
// is preserved in any distributed or derivative work.
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
|
|
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
/* $Id$ */
|
|
|
|
class xmlrpcmsg
|
|
{
|
|
var $payload;
|
|
var $methodname;
|
|
var $params = array();
|
|
var $debug = 0;
|
|
|
|
function xmlrpcmsg($meth, $pars=0)
|
|
{
|
|
$this->methodname=$meth;
|
|
if(is_array($pars) && sizeof($pars)>0)
|
|
{
|
|
for($i=0; $i<sizeof($pars); $i++)
|
|
{
|
|
$this->addParam($pars[$i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function xml_header()
|
|
{
|
|
return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
|
|
}
|
|
|
|
function xml_footer()
|
|
{
|
|
return "</methodCall>\n";
|
|
}
|
|
|
|
function createPayload()
|
|
{
|
|
$this->payload=$this->xml_header();
|
|
$this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
|
|
// if(sizeof($this->params)) {
|
|
$this->payload.="<params>\n";
|
|
for($i=0; $i<sizeof($this->params); $i++)
|
|
{
|
|
$p=$this->params[$i];
|
|
$this->payload.="<param>\n" . $p->serialize() .
|
|
"</param>\n";
|
|
}
|
|
$this->payload.="</params>\n";
|
|
// }
|
|
$this->payload.=$this->xml_footer();
|
|
//$this->payload=str_replace("\n", "\r\n", $this->payload);
|
|
}
|
|
|
|
function method($meth='')
|
|
{
|
|
if($meth!='')
|
|
{
|
|
$this->methodname=$meth;
|
|
}
|
|
return $this->methodname;
|
|
}
|
|
|
|
function serialize()
|
|
{
|
|
$this->createPayload();
|
|
return $this->payload;
|
|
}
|
|
|
|
function addParam($par)
|
|
{
|
|
// add check: do not add to self params which are not xmlrpcvals
|
|
if(is_object($par) && (get_class($par) == 'xmlrpcval' || is_subclass_of($par, 'xmlrpcval')))
|
|
{
|
|
$this->params[]=$par;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function getParam($i) { return $this->params[$i]; }
|
|
function getNumParams() { return sizeof($this->params); }
|
|
|
|
function &parseResponseFile($fp)
|
|
{
|
|
$ipd='';
|
|
while($data=fread($fp, 32768))
|
|
{
|
|
$ipd.=$data;
|
|
}
|
|
//fclose($fp);
|
|
$r =& $this->parseResponse($ipd);
|
|
return $r;
|
|
}
|
|
|
|
function &parseResponse($data='', $headers_processed=false)
|
|
{
|
|
$parser = xml_parser_create($GLOBALS['xmlrpc_defencoding']);
|
|
|
|
$hdrfnd = 0;
|
|
if($this->debug)
|
|
{
|
|
//by maHo, replaced htmlspecialchars with htmlentities
|
|
print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
|
|
}
|
|
|
|
if($data == '')
|
|
{
|
|
error_log('No response received from server.');
|
|
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);
|
|
return $r;
|
|
}
|
|
// see if we got an HTTP 200 OK, else bomb
|
|
// but only do this if we're using the HTTP protocol.
|
|
if(ereg("^HTTP",$data))
|
|
{
|
|
// Strip HTTP 1.1 100 Continue header if present
|
|
while(ereg('^HTTP/1.1 1[0-9]{2} ', $data))
|
|
{
|
|
$pos = strpos($data, 'HTTP', 12);
|
|
// server sent a Continue header without any (valid) content following...
|
|
// give the client a chance to know it
|
|
if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
|
|
{
|
|
break;
|
|
}
|
|
$data = substr($data, $pos);
|
|
}
|
|
if(!ereg("^HTTP/[0-9\\.]+ 200 ", $data))
|
|
{
|
|
$errstr= substr($data, 0, strpos($data, "\n")-1);
|
|
error_log('HTTP error, got response: ' .$errstr);
|
|
$r=& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');
|
|
return $r;
|
|
}
|
|
}
|
|
|
|
$GLOBALS['_xh'][$parser] = array();
|
|
$GLOBALS['_xh'][$parser]['headers'] = array();
|
|
$GLOBALS['_xh'][$parser]['stack'] = array();
|
|
$GLOBALS['_xh'][$parser]['valuestack'] = array();
|
|
|
|
// separate HTTP headers from data
|
|
if(ereg("^HTTP", $data))
|
|
{
|
|
// be tolerant to usage of \n instead of \r\n to separate headers and data
|
|
// (even though it is not valid http)
|
|
$pos = strpos($data,"\r\n\r\n");
|
|
if($pos || is_int($pos))
|
|
{
|
|
$bd = $pos+4;
|
|
}
|
|
else
|
|
{
|
|
$pos = strpos($data,"\n\n");
|
|
if($pos || is_int($pos))
|
|
{
|
|
$bd = $pos+2;
|
|
}
|
|
else
|
|
{
|
|
// No separation between response headers and body: fault?
|
|
$bd = 0;
|
|
}
|
|
}
|
|
// be tolerant to line endings, and extra empty lines
|
|
$ar = split("\r?\n", trim(substr($data, 0, $pos)));
|
|
while(list(,$line) = @each($ar))
|
|
{
|
|
// take care of multi-line headers
|
|
$arr = explode(':',$line);
|
|
if(count($arr) > 1)
|
|
{
|
|
$header_name = strtolower(trim($arr[0]));
|
|
// TO DO: some headers (the ones that allow a CSV list of values)
|
|
// do allow many values to be passed using multiple header lines.
|
|
// We should add content to $GLOBALS['_xh'][$parser]['headers'][$header_name]
|
|
// instead of replacing it for those...
|
|
$GLOBALS['_xh'][$parser]['headers'][$header_name] = $arr[1];
|
|
for($i = 2; $i < count($arr); $i++)
|
|
{
|
|
$GLOBALS['_xh'][$parser]['headers'][$header_name] .= ':'.$arr[$i];
|
|
} // while
|
|
$GLOBALS['_xh'][$parser]['headers'][$header_name] = trim($GLOBALS['_xh'][$parser]['headers'][$header_name]);
|
|
}
|
|
elseif(isset($header_name))
|
|
{
|
|
$GLOBALS['_xh'][$parser]['headers'][$header_name] .= ' ' . trim($line);
|
|
}
|
|
}
|
|
$data = substr($data, $bd);
|
|
|
|
if($this->debug && count($GLOBALS['_xh'][$parser]['headers']))
|
|
{
|
|
print '<PRE>';
|
|
foreach($GLOBALS['_xh'][$parser]['headers'] as $header => $value)
|
|
{
|
|
print "HEADER: $header: $value\n";
|
|
}
|
|
print "</PRE>\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'][$parser]['headers']['transfer-encoding']) && $GLOBALS['_xh'][$parser]['headers']['transfer-encoding'] == 'chunked')
|
|
{
|
|
if(!$data = decode_chunked($data))
|
|
{
|
|
error_log('Errors occurred when trying to rebuild the chunked data received from server');
|
|
$r =& CreateObject('phpgwapi.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'][$parser]['headers']['content-encoding']))
|
|
{
|
|
if($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'gzip')
|
|
{
|
|
// if decoding works, use it. else assume data wasn't gzencoded
|
|
if(function_exists('gzinflate'))
|
|
{
|
|
if($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'deflate' && $degzdata = @gzinflate($data))
|
|
{
|
|
$data = $degzdata;
|
|
if($this->debug)
|
|
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
|
|
}
|
|
elseif($GLOBALS['_xh'][$parser]['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
|
|
{
|
|
$data = $degzdata;
|
|
if($this->debug)
|
|
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
|
|
}
|
|
else
|
|
{
|
|
error_log('Errors occurred when trying to decode the deflated data received from server');
|
|
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);
|
|
return $r;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
|
|
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);
|
|
return $r;
|
|
}
|
|
}
|
|
}
|
|
} // end of 'de-chunk, re-inflate response'
|
|
|
|
// be tolerant of extra whitespace in response body
|
|
$data = trim($data);
|
|
|
|
// be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
|
|
// idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
|
|
$bd = false;
|
|
$pos = strpos($data, '</methodResponse>');
|
|
while($pos || is_int($pos))
|
|
{
|
|
$bd = $pos+17;
|
|
$pos = strpos($data, '</methodResponse>', $bd);
|
|
}
|
|
if($bd)
|
|
{
|
|
$data = substr($data, 0, $bd);
|
|
}
|
|
|
|
$GLOBALS['_xh'][$parser]['isf']=0;
|
|
$GLOBALS['_xh'][$parser]['isf_reason']='';
|
|
$GLOBALS['_xh'][$parser]['ac']='';
|
|
$GLOBALS['_xh'][$parser]['qt']='';
|
|
|
|
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
|
|
// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
|
|
// the xml parser to give us back data in the expected charset
|
|
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
|
|
|
|
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
|
|
xml_set_character_data_handler($parser, 'xmlrpc_cd');
|
|
xml_set_default_handler($parser, 'xmlrpc_dh');
|
|
//$xmlrpc_value=new xmlrpcval;
|
|
|
|
if(!xml_parse($parser, $data, sizeof($data)))
|
|
{
|
|
// thanks to Peter Kocks <peter.kocks@baygate.com>
|
|
if((xml_get_current_line_number($parser)) == 1)
|
|
{
|
|
$errstr = 'XML error at line 1, check URL';
|
|
}
|
|
else
|
|
{
|
|
$errstr = sprintf('XML error: %s at line %d',
|
|
xml_error_string(xml_get_error_code($parser)),
|
|
xml_get_current_line_number($parser));
|
|
}
|
|
error_log($errstr);
|
|
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')');
|
|
xml_parser_free($parser);
|
|
if($this->debug)
|
|
{
|
|
print $errstr;
|
|
}
|
|
$r->hdrs = $GLOBALS['_xh'][$parser]['headers'];
|
|
return $r;
|
|
}
|
|
xml_parser_free($parser);
|
|
if($GLOBALS['_xh'][$parser]['isf'] > 1)
|
|
{
|
|
if ($this->debug)
|
|
{
|
|
///@todo echo something for user?
|
|
}
|
|
|
|
$r =& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'],
|
|
$GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh'][$parser]['isf_reason']);
|
|
}
|
|
elseif (!is_object($GLOBALS['_xh'][$parser]['value']))
|
|
{
|
|
// then something odd has happened
|
|
// and it's time to generate a client side error
|
|
// indicating something odd went on
|
|
$r=& CreateObject('phpgwapi.xmlrpcresp',0, $GLOBALS['xmlrpcerr']['invalid_return'],
|
|
$GLOBALS['xmlrpcstr']['invalid_return']);
|
|
}
|
|
else
|
|
{
|
|
if ($this->debug)
|
|
{
|
|
print "<PRE>---PARSED---\n" ;
|
|
var_dump($GLOBALS['_xh'][$parser]['value']);
|
|
print "\n---END---</PRE>";
|
|
} // note that using =& will raise an error if $GLOBALS['_xh'][$parser]['st'] does not generate an object.
|
|
|
|
$v = $GLOBALS['_xh'][$parser]['value'];
|
|
|
|
if($GLOBALS['_xh'][$parser]['isf'])
|
|
{
|
|
$errno_v = $v->structmem('faultCode');
|
|
$errstr_v = $v->structmem('faultString');
|
|
$errno = $errno_v->scalarval();
|
|
|
|
if($errno == 0)
|
|
{
|
|
// FAULT returned, errno needs to reflect that
|
|
$errno = -1;
|
|
}
|
|
|
|
$r =& CreateObject('phpgwapi.xmlrpcresp',$v, $errno, $errstr_v->scalarval());
|
|
}
|
|
else
|
|
{
|
|
$r=& CreateObject('phpgwapi.xmlrpcresp',$v);
|
|
}
|
|
}
|
|
|
|
$r->hdrs = $GLOBALS['_xh'][$parser]['headers'];
|
|
return $r;
|
|
}
|
|
}
|
|
?>
|