<?php
// $Id: rpc_encoder.php,v 1.1 2004/07/11 10:28:46 Farsus Exp $
// -------------------------------------------------------------------------//
//			                 RUNCMS                                         //
//                                                                          //
//	 reliable - Unique - Nocost &  Simplicity & ease off use                //
//                       < http://www.runcms.org >                          //
// -------------------------------------------------------------------------//
// Original Author: i-Tech (Half-Dead)
// Author Website : http://www.i-Technology.NET
// License Type   : LGPL: See /manual/LICENSES/LGPL.txt
// ------------------------------------------------------------------------- //

//------------------------------------------------------------------------------------------//
/**
* Encodes php values types into xml data to send.
* @author Half-Dead
* @copyright ©2002 {@link http://www.e-xoops.com www.e-xoops.com} :: {@link http://www.topsite-toplist.com www.topsite-toplist.com}
* @version 1.2b
* @package phpRPC
*/
class rpc_Encoder {

	var $params;
	var $type;

/**
* Contains the <methodName>, if any.
* @var string
*/
	var $methodName;

	var $escaping;
	var $encoding;
	var $debug;
	var $logfile;


//------------------------------------------------------------------------------------------//
/**
* Initializes the encoder.
* Usage:
* $rpc_encoder = new rpc_Encoder($methodName);
* @param string $methodName The <methodName> of the outgoing call.
*/
function rpc_Encoder($methodName = 'null') {
global $phprpc_encoding, $phprpc_escaping, $phprpc_debug;

	$this->type       = 'none';
	$this->methodName = $methodName;

	$this->escaping   = $phprpc_escaping;
	$this->encoding   = $phprpc_encoding;
	$this->debug      = $phprpc_debug;
	$this->logfile    = './cache/logfile.txt';
}


//------------------------------------------------------------------------------------------//
/**
* Adds a <params> tags
* Usually not needed
*/
function start_params() {
	$this->params[] = '    <params>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a </params> tags
* Usually not needed
*/
function end_params() {
	$this->params[] = '    </params>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a <param> tag
* Usually not needed
*/
function start_param() {
	$this->params[] = '      <param>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a </param> tag
* Usually not needed
*/
function end_param() {
	$this->params[] = '      </param>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Default way of adding params.
* $rpc_encoder->add_param($type, $value, $name);
*
* Works in exactly the same way as add_value() does,
* except that values are enclosed in <param> tags.
* @param string	$type		Type of value to add
* @param mixed	$value		The data to add
* @param string	$name	Optional struct member name: results in a member/name pair
* @see add_value()
*/
function add_param($type, $value='', $name='') {
	$this->start_param();
	$this->add_value($type, $value, $name);
	$this->end_param();
}


//------------------------------------------------------------------------------------------//
/**
* Adds a <struct> tag
* Usually not needed
*/
function start_struct() {
	$this->params[] = '    <value>' . "\n";
	$this->params[] = '      <struct>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a </struct> tag
* Usually not needed
*/
function end_struct() {
	$this->params[] = '      </struct>' . "\n";
	$this->params[] = '    </value>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a <array> tag
* Usually not needed
*/
function start_array() {
	$this->params[] = '      <value>' . "\n";
	$this->params[] = '        <array>' . "\n";
	$this->params[] = '          <data>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a </array> tag
* Usually not needed
*/
function end_array() {
	$this->params[] = '          </data>' . "\n";
	$this->params[] = '        </array>' . "\n";
	$this->params[] = '      </value>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a <member><name> tag
* Usually not needed
* @param string $name Name of the member object
*/
function start_member($name) {
	$this->params[] = '      <member>' . "\n";
	$this->params[] = '         <name>' . trim($name) . '</name>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* Adds a </member> tag
* Usually not needed
*/
function end_member() {
	$this->params[] = '      </member>' . "\n";
}


//------------------------------------------------------------------------------------------//
/**
* @access private
*/
function encode_string($string) {

switch($this->escaping) {

case "CDATA":
$string = "<![CDATA[" .trim($string). "]]>";
return $string;
break;

case "NUMERIC":
$string = numeric_escape($string);
$string = xml_quote($string, 1);
return $string;
break;

default:
$string = "<![CDATA[" .trim($string). "]]>";
return $string;
break;
}
}


//------------------------------------------------------------------------------------------//
/**
* Default way of adding values.
*
* $rpc_encoder->add_value($type, $value, $name);
*
* $type can of any of the following:
* i4, int, long, integer
* real, float, double
* bool, boolean
* b64, base64
* time, date, datetime, dateTime.iso8601 ($value is unix timestamp)
* file ($value is path to a file to include)
* array, struct, object
* string
* auto: will autodetermine the type of the $value
* Note: auto cannot detect time or base64 values.
*
* The above non standard types are for convienince,
* and are automaticly mapped to their xmlrpc standard counterparts.
*
* $type can also be non standard and used for custom needs.
* @param string	$type		Type of value to add
* @param mixed	$value		The data to add
* @param string	$name	Optional struct member name: results in a member/name pair
* @see add_param()
*/
function add_value($type, $value='', $name='') {

$type = strtolower($type);

switch($type) {

case "i4":
case "int":
case "long":
case "integer":
	$this->type = 'int';
break;

case "real":
case "float":
case "double":
	$this->type = 'double';
break;

case "bool":
case "boolean":
	($value == "1" || $value == "true") ? $value = 1 : $value = 0;
	$this->type = 'boolean';
break;

case "b64":
case "base64":
	$value = base64_encode($value);
	$this->type = 'base64';
break;

case "time":
case "date":
case "datetime":
case "dateTime.iso8601":
	$value = iso8601_encode($value);
	$this->type = 'dateTime.iso8601';
break;

case "file":
	$fp = fopen($value, "rb");
	$file = fread($fp, filesize($value));
	fclose($fp);
	$value = base64_encode($file);
	$this->type = 'base64';
break;

case "array":
case "struct":
case "object":
	$this->add_array($value, $name);
	$this->type = 'none';
break;

case "string":
	$this->type = 'string';
	$value = $this->encode_string($value);
break;

case "auto":
	$this->get_type($value);
	$this->add_value($this->type, $value, $name);
break;

default:
	$this->type = preg_replace("/[^a-z0-9]/i", "", $type);
	$value = $this->encode_string($value);
break;
} // End switch

if ($this->type != 'none' && $type != 'auto') {
	if ($name) { $this->start_member($name); }
	$this->params[] = '        <value><'.$this->type.'>'.trim($value).'</'.$this->type.'></value>' . "\n";
	if ($name) { $this->end_member(); }
}
}


//------------------------------------------------------------------------------------------//
/**
* @access private
*/
function add_array($array, $name='') {

if ($name) { $this->start_member($name); }

$this->start_array();

foreach ($array as $key => $value) {

switch(TRUE) {

case is_int($value):
	$this->type = 'int';
break;

case is_bool($value):
	$this->type = 'boolean';
break;

case is_float($value):
	$this->type = 'double';
break;

case is_array($value):
case is_object($value):
	$this->add_array($value);
	$this->type = 'none';
break;

default:
	$this->type = 'string';
	$value = $this->encode_string($value);
break;
}

if ($this->type != 'none') {
	if ( is_string($key) ) { $this->start_member($key); }
	$this->params[] = '        <value><'.$this->type.'>'.trim($value).'</'.$this->type.'></value>' . "\n";
	if ( is_string($key) ) { $this->end_member(); }
}

} // end while

$this->end_array();

if ($name) { $this->end_member(); }
}


//------------------------------------------------------------------------------------------//
/**
* @access private
*/
function get_type($value) {

switch (TRUE) {

case is_int($value):
	$this->type = 'int';
break;

case is_bool($value):
	$this->type = 'boolean';
break;

case is_float($value):
	$this->type = 'double';
break;

case is_array($value):
case is_object($value):
	$this->type = 'array';
break;

case is_file($value):
	$this->type = 'file';
break;

default:
	$this->type = 'string';
break;
} // End switch
}


//------------------------------------------------------------------------------------------//
/**
* Returns xml data.
*
* Mainly used when sending data to a distant server.
*
* Usage:
* $message = $rpc_encoder->return_call();
* $result  = $rpc_client->send($message);
* @return string Returns all encoded values so we can send the data.
*/
function return_call() {
global $rpc_decoder;

if ($this->methodName == 'null') {
	$payload  = '<?xml version="1.0" encoding="'.$this->encoding.'"?>' . "\n";
	$payload .= '  <methodResponse>' . "\n";
	$payload .= '    <params>' . "\n";
	if ($this->params != '') {
	$payload .= '      <param>' . "\n";
	$payload .=		implode('', $this->params);
	$payload .= '    </param>' . "\n";
	}
	$payload .= '  </params>' . "\n";
	$payload .= '</methodResponse>';

	if ( $this->debug == 1 ) {
		dump_data($payload, $rpc_decoder->methodName.'_methodResponse.xml');
		}

	header('User-Agent: phpRPC');
	header('Content-Type: text/xml');
	header('Content-Length: ' . strlen($payload));
	echo $payload;
	exit();

} else {
	$payload  = '<?xml version="1.0" encoding="'.$this->encoding.'"?>' . "\n";
	$payload .= '  <methodCall>' . "\n";
	$payload .= '    <methodName>' . trim($this->methodName) . '</methodName>' . "\n";
	$payload .= '      <params>' . "\n";
	if ($this->params != '') { $payload .= implode('', $this->params); }
	$payload .= '      </params>' . "\n";
	$payload .= '  </methodCall>';

	if ( $this->debug == 1 ) {
		dump_data($payload, $this->methodName.'_methodCall.xml');
		}

	return $payload;
	exit();
	}
}


//------------------------------------------------------------------------------------------//
/**
* Used to query a database and add the result to the output.
*
* Usage:
* $rpc_encoder->xmlQuery($sql);
* @param string $sql Queries a database against $sql and injects
* the result into an array/struct response.
*/
function xmlQuery($sql, $limit=0, $start=0) {
global $db;

$query = $db->query($sql, $limit, $start);

if ($query) {
	$num_rows = $db->num_rows($query);
	if ($num_rows != 0) {
		$this->start_array();
		while ($result = $db->fetch_array($query)) {
			$size = $db->num_fields($query);
			$this->start_struct();
			for ($i=0; $i<$size; $i++) {
				$fieldname = $db->field_name($query, $i);
				$this->add_value("auto", $result[$fieldname], $fieldname);
			}
			$this->end_struct();
		}
		$this->end_array();
	}
}
}
//------------------------------------------------------------------------------------------//
}
//------------------------------------------------------------------------------------------//
?>
