'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'] = []; } 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 ['fault', $value]; } return ['response', $value]; } return ['call', [$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': if (strlen($v) === 0) { return ''; } return '' . self::escape($v, $escape) . ''; case 'NULL': return ''; 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 ['fault', self::decodeValue($xml->fault->value)]; } return ['response', self::decodeValue($xml->params->param->value)]; } $params = []; foreach ($xml->params->param as $param) { $params[] = self::decodeValue($param->value); } return ['call', [(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 = []; foreach ($elt->data->value as $v) { $arr[] = self::decodeValue($v); } return $arr; case 'struct': $struct = []; foreach ($elt as $member) { $struct[(string)$member->name] = self::decodeValue($member->value); } return $struct; } } } } class ParseException extends Exception { }