debug ? $resp :
array(
'faultCode' => empty($resp['faultCode']) ? -1 : $resp['faultCode'],
'faultString' => empty($resp['faultString']) ? 'Unknown error.' : $resp['faultString'],
);
$xml = '' . $this->dataToXML($fault) . '';
}
else
$xml = '' . $this->dataToXML($resp) . '';
$xml = <<
$xml
EOF;
return $xml;
}
private function &dataToXML(&$data)
{
if (is_array($data))
{
$is_assoc = false;
$n = 0;
foreach ($data as $k => $v)
{
if (!is_integer($k) || "$k" != "$n")
{
$is_assoc = true;
break;
}
$n++;
}
if ($is_assoc)
{
$xml = '';
foreach ($data as $k => $v)
$xml .= '' . htmlspecialchars($k) . '' .
$this->dataToXML($v) . '';
$xml .= '';
}
else
{
$xml = '';
foreach ($data as $v)
$xml .= '' . $this->dataToXML($v) . '';
$xml .= '';
}
}
elseif (is_object($data))
{
switch (get_class($data))
{
case 'DateTime':
$xml = '' .
htmlspecialchars($data->format(DATE_ATOM)) .
'';
break;
case 'BinaryData':
$xml = '' . $data->getBase64() . '';
break;
default:
throw new Exception("Unknown object type.");
}
}
else
{
if (is_float($data))
$xml = '' . htmlspecialchars($data) . '';
elseif (is_integer($data))
$xml = '' . htmlspecialchars($data) . '';
else
$xml = '' . htmlspecialchars($data) . '';
}
return $xml;
}
public function &parseCall(&$rawData, &$method)
{
$doc = new DOMDocument;
$doc->loadXML($rawData, LIBXML_NOBLANKS | LIBXML_NOENT | LIBXML_NONET);
if (!$doc)
throw new Exception("XML parse error.");
$this->xpath = new DOMXPath($doc);
$method = $this->xpath->query('/methodCall/methodName')->item(0)->nodeValue;
if (!$method)
throw new Exception("Method parse error.");
$tmpNodes = $this->xpath->query('/methodCall/params/param/value/*')->item(0);
$argv = $this->parseData($tmpNodes);
$this->xpath = null;
return $argv;
}
private function &parseData(&$node)
{
switch ($node->nodeName)
{
case 'string':
$value = $node->nodeValue;
break;
case 'boolean':
case 'i4':
case 'int':
$value = (int)$node->nodeValue;
break;
case 'double':
$value = (double)$node->nodeValue;
break;
case 'base64':
$value = new BinaryData($node->nodeValue, 'base64');
break;
case 'dateTime.iso8601':
$value = new DateTime($node->nodeValue);
break;
case 'array':
$nodes = $this->xpath->query('data/value/*', $node);
$value = array();
for ($i = 0; $i < $nodes->length; $i++)
if ($nodes->item($i)->nodeType == XML_ELEMENT_NODE)
$value[] = $this->parseData($nodes->item($i));
break;
case 'struct':
$nodes = $this->xpath->query('member', $node);
$value = array();
for ($i = 0; $i < $nodes->length; $i++)
if ($nodes->item($i)->nodeType == XML_ELEMENT_NODE)
{
$name = $this->xpath->query('name', $nodes->item($i))->item(0)->nodeValue;
$tmpNodes = $this->xpath->query('value/*', $nodes->item($i))->item(0);
$value[$name] = $this->parseData($tmpNodes);
}
break;
default:
throw new Exception('Unknow data type.');
}
return $value;
}
public function &call(&$rawData)
{
try
{
$argv = $this->parseCall($rawData, $rpcMethod);
$method_parts = explode('.', $rpcMethod);
foreach ($method_parts as $part)
if (!preg_match('/^\w+$/', $part))
throw new Exception('Wrong method name.');
if (count($method_parts) != 3)
throw new Exception('Wrong method name.');
$file = $this->classesPath . $method_parts[0] . '.php';
$class = $this->classPrefix . $method_parts[1];
$method = $this->funcPrefix . $method_parts[2];
define('RPC_MODULE', $method_parts[0]);
define('RPC_CLASS', $method_parts[1]);
define('RPC_METHOD', $method_parts[2]);
if (!file_exists($file))
throw new Exception('Class file not found.');
eval("include_once('$file');");
if (!class_exists($class))
throw new Exception('Class not found.');
$methods = get_class_methods($class);
if (!in_array($method, $methods))
throw new Exception('Method not found.');
$resp = call_user_func(array($class, $method), $rpcMethod, $argv, $this);
}
catch (Exception $e)
{
$resp = array(
'faultCode' => $e->getCode(),
'faultString' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine()
);
}
return $this->responseToXML($resp);
}
}
class BinaryData
{
private $data;
public function __construct(&$data, $type = 'binary')
{
switch ($type)
{
case 'binary':
$this->setBinary($data);
break;
case 'base64':
$this->setBase64($data);
break;
default:
throw new Exception('Unknown binary format.');
}
}
public function setBinary(&$bin)
{
$this->data = $bin;
}
public function setBase64(&$b64)
{
$this->data = base64_decode($b64);
}
public function getBinary()
{
return $data;
}
public function getBase64()
{
return base64_encode($data);
}
}
?>