'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 {}