2014-01-16 16:56:24 +01:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* ManiaPlanet dedicated server Xml-RPC client
|
|
|
|
*
|
|
|
|
* @license http://www.gnu.org/licenses/lgpl.html LGPL License 3
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Maniaplanet\DedicatedServer\Xmlrpc;
|
|
|
|
|
2014-04-19 00:32:34 +02:00
|
|
|
if(extension_loaded('xmlrpc'))
|
2014-01-16 16:56:24 +01:00
|
|
|
{
|
2014-04-19 00:32:34 +02:00
|
|
|
abstract class Request
|
2014-01-16 16:56:24 +01:00
|
|
|
{
|
2014-04-19 01:59:49 +02:00
|
|
|
private static $options = array(
|
|
|
|
'encoding' => 'utf-8',
|
2014-06-12 15:39:50 +02:00
|
|
|
'escaping' => 'markup',
|
2014-04-19 01:59:49 +02:00
|
|
|
'verbosity' => 'no_white_space'
|
|
|
|
);
|
|
|
|
|
2014-04-19 00:32:34 +02:00
|
|
|
/**
|
|
|
|
* @param string $method
|
|
|
|
* @param mixed[] $args
|
|
|
|
* @return string
|
|
|
|
*/
|
2014-05-08 19:38:15 +02:00
|
|
|
static function encode($method, $args, $escape=true)
|
2014-01-16 16:56:24 +01:00
|
|
|
{
|
2014-05-08 19:38:15 +02:00
|
|
|
$opts = self::$options;
|
|
|
|
if(!$escape)
|
|
|
|
$opts['escaping'] = array();
|
|
|
|
return xmlrpc_encode_request($method, $args, $opts);
|
2014-01-16 16:56:24 +01:00
|
|
|
}
|
|
|
|
|
2014-04-19 00:32:34 +02:00
|
|
|
/**
|
|
|
|
* @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();
|
2014-01-16 16:56:24 +01:00
|
|
|
|
2014-04-19 00:32:34 +02:00
|
|
|
if($method === null)
|
|
|
|
{
|
2014-05-08 19:38:15 +02:00
|
|
|
if(is_array($value) && xmlrpc_is_fault($value))
|
2014-04-19 00:32:34 +02:00
|
|
|
return array('fault', $value);
|
|
|
|
return array('response', $value);
|
|
|
|
}
|
|
|
|
return array('call', array($method, $value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
abstract class Request
|
2014-01-16 16:56:24 +01:00
|
|
|
{
|
2014-04-19 00:32:34 +02:00
|
|
|
const DATE_FORMAT = 'Ymd\TH:i:s';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $method
|
|
|
|
* @param mixed[] $args
|
|
|
|
* @return string
|
|
|
|
*/
|
2014-05-08 19:38:15 +02:00
|
|
|
static function encode($method, $args, $escape=true)
|
2014-04-19 00:32:34 +02:00
|
|
|
{
|
2014-05-08 19:38:15 +02:00
|
|
|
$xml = '<?xml version="1.0" encoding="utf-8"?><methodCall><methodName>'.self::escape($method, $escape).'</methodName>';
|
|
|
|
if(!$args)
|
|
|
|
return $xml.'<params/></methodCall>';
|
|
|
|
|
|
|
|
$xml .= '<params>';
|
2014-04-19 00:32:34 +02:00
|
|
|
foreach($args as $arg)
|
2014-05-08 19:38:15 +02:00
|
|
|
$xml .= '<param><value>'.self::encodeValue($arg, $escape).'</value></param>';
|
|
|
|
return $xml.'</params></methodCall>';
|
2014-04-19 00:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param mixed $v
|
|
|
|
* @return string
|
|
|
|
*/
|
2014-05-08 19:38:15 +02:00
|
|
|
private static function encodeValue($v, $escape=true)
|
2014-04-19 00:32:34 +02:00
|
|
|
{
|
|
|
|
switch(gettype($v))
|
|
|
|
{
|
|
|
|
case 'boolean':
|
2014-06-12 15:39:50 +02:00
|
|
|
return '<boolean>'.((int) $v).'</boolean>';
|
2014-04-19 00:32:34 +02:00
|
|
|
case 'integer':
|
2014-06-12 15:39:50 +02:00
|
|
|
return '<int>'.$v.'</int>';
|
2014-04-19 00:32:34 +02:00
|
|
|
case 'double':
|
2014-06-12 15:39:50 +02:00
|
|
|
return '<double>'.$v.'</double>';
|
2014-04-19 00:32:34 +02:00
|
|
|
case 'string':
|
2014-05-08 19:38:15 +02:00
|
|
|
case 'NULL':
|
|
|
|
if(!$v)
|
|
|
|
return '<string/>';
|
|
|
|
return '<string>'.self::escape($v, $escape).'</string>';
|
2014-04-19 00:32:34 +02:00
|
|
|
case 'object':
|
|
|
|
if($v instanceof Base64)
|
2014-05-08 19:38:15 +02:00
|
|
|
{
|
|
|
|
if(!$v->scalar)
|
|
|
|
return '<base64/>';
|
2014-06-12 15:39:50 +02:00
|
|
|
return '<base64>'.base64_encode($v->scalar).'</base64>';
|
2014-05-08 19:38:15 +02:00
|
|
|
}
|
2014-04-19 00:32:34 +02:00
|
|
|
if($v instanceof \DateTime)
|
2014-06-12 15:39:50 +02:00
|
|
|
return '<dateTime.iso8601>'.$v->format(self::DATE_FORMAT).'</dateTime.iso8601>';
|
2014-04-19 00:32:34 +02:00
|
|
|
$v = get_object_vars($v);
|
2014-05-08 19:38:15 +02:00
|
|
|
// fallthrough
|
2014-04-19 00:32:34 +02:00
|
|
|
case 'array':
|
2014-05-08 19:38:15 +02:00
|
|
|
// empty array case
|
|
|
|
if(!$v)
|
|
|
|
return '<array><data/></array>';
|
2014-06-12 15:39:50 +02:00
|
|
|
$return = '';
|
2014-04-19 00:32:34 +02:00
|
|
|
// pure array case
|
2014-04-20 18:00:40 +02:00
|
|
|
if(array_keys($v) === range(0, count($v) - 1))
|
2014-04-19 00:32:34 +02:00
|
|
|
{
|
|
|
|
foreach($v as $item)
|
2014-05-08 19:38:15 +02:00
|
|
|
$return .= '<value>'.self::encodeValue($item, $escape).'</value>';
|
2014-04-19 00:32:34 +02:00
|
|
|
return '<array><data>'.$return.'</data></array>';
|
|
|
|
}
|
|
|
|
// else it's a struct
|
|
|
|
foreach($v as $name => $value)
|
2014-05-08 19:38:15 +02:00
|
|
|
$return .= '<member><name>'.self::escape($name, $escape).'</name><value>'.self::encodeValue($value, $escape).'</value></member>';
|
2014-04-19 00:32:34 +02:00
|
|
|
return '<struct>'.$return.'</struct>';
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2014-05-08 19:38:15 +02:00
|
|
|
/**
|
|
|
|
* @param string $str
|
|
|
|
* @param bool $escape
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
private static function escape($str, $escape=true)
|
|
|
|
{
|
|
|
|
if($escape)
|
2014-06-12 15:39:50 +02:00
|
|
|
return '<![CDATA['.str_replace(']]>', ']]]]><![CDATA[>', $str).']]>';
|
2014-05-08 19:38:15 +02:00
|
|
|
return $str;
|
|
|
|
}
|
|
|
|
|
2014-04-19 00:32:34 +02:00
|
|
|
/**
|
|
|
|
* @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':
|
2014-05-08 19:38:15 +02:00
|
|
|
return (bool) (int) $elt;
|
2014-04-19 00:32:34 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2014-01-16 16:56:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-19 00:32:34 +02:00
|
|
|
class ParseException extends Exception {}
|