'utf-8',
'escaping' => 'markup',
'verbosity' => 'no_white_space'
);
/**
* @param string $method
* @param mixed[] $args
* @return string
*/
static function encode($method, $args, $escape=true)
{
$opts = self::$options;
if(!$escape)
$opts['escaping'] = array();
return xmlrpc_encode_request($method, $args, $opts);
}
/**
* @param string $message
* @return mixed
* @throws ParseException
*/
static function decode($message)
{
$value = xmlrpc_decode_request($message, $method, 'utf-8');
if($value === null)
throw new ParseException();
if($method === null)
{
if(is_array($value) && xmlrpc_is_fault($value))
return array('fault', $value);
return array('response', $value);
}
return array('call', array($method, $value));
}
}
}
else
{
abstract class Request
{
const DATE_FORMAT = 'Ymd\TH:i:s';
/**
* @param string $method
* @param mixed[] $args
* @return string
*/
static function encode($method, $args, $escape=true)
{
$xml = ''.self::escape($method, $escape).'';
if(!$args)
return $xml.'';
$xml .= '';
foreach($args as $arg)
$xml .= ''.self::encodeValue($arg, $escape).'';
return $xml.'';
}
/**
* @param mixed $v
* @return string
*/
private static function encodeValue($v, $escape=true)
{
switch(gettype($v))
{
case 'boolean':
return ''.((int) $v).'';
case 'integer':
return ''.$v.'';
case 'double':
return ''.$v.'';
case 'string':
case 'NULL':
if(!$v)
return '';
return ''.self::escape($v, $escape).'';
case 'object':
if($v instanceof Base64)
{
if(!$v->scalar)
return '';
return ''.base64_encode($v->scalar).'';
}
if($v instanceof \DateTime)
return ''.$v->format(self::DATE_FORMAT).'';
$v = get_object_vars($v);
// fallthrough
case 'array':
// empty array case
if(!$v)
return '';
$return = '';
// pure array case
if(array_keys($v) === range(0, count($v) - 1))
{
foreach($v as $item)
$return .= ''.self::encodeValue($item, $escape).'';
return ''.$return.'';
}
// else it's a struct
foreach($v as $name => $value)
$return .= ''.self::escape($name, $escape).''.self::encodeValue($value, $escape).'';
return ''.$return.'';
}
return '';
}
/**
* @param string $str
* @param bool $escape
* @return string
*/
private static function escape($str, $escape=true)
{
if($escape)
return '', ']]]]>', $str).']]>';
return $str;
}
/**
* @param string $message
* @return mixed
* @throws ParseException
*/
static function decode($message)
{
$xml = @simplexml_load_string($message);
if(!$xml)
throw new ParseException();
if($xml->getName() == 'methodResponse')
{
if($xml->fault)
return array('fault', self::decodeValue($xml->fault->value));
return array('response', self::decodeValue($xml->params->param->value));
}
$params = array();
foreach($xml->params->param as $param)
$params[] = self::decodeValue($param->value);
return array('call', array((string) $xml->methodName, $params));
}
/**
* @param \SimpleXMLElement $elt
* @return mixed
*/
private static function decodeValue($elt)
{
$elt = $elt->children();
$elt = $elt[0];
switch($elt->getName())
{
case 'boolean':
return (bool) (int) $elt;
case 'i4':
case 'int':
return (int) $elt;
case 'double':
return (double) $elt;
case 'string':
return (string) $elt;
case 'base64':
return new Base64(base64_decode($elt));
case 'dateTime.iso8601':
return \DateTime::createFromFormat(self::DATE_FORMAT, (string) $elt);
case 'array':
$arr = array();
foreach($elt->data->value as $v)
$arr[] = self::decodeValue($v);
return $arr;
case 'struct':
$struct = array();
foreach($elt as $member)
$struct[(string) $member->name] = self::decodeValue($member->value);
return $struct;
}
}
}
}
class ParseException extends Exception {}