<?php
header('Content-Type: application/octet-stream');
error_reporting(E_ERROR | E_PARSE);
$data = 'OK:';

function err($error)
{
	die("err: $error");
}

function myerr($err, $conn)
{
	if ($conn == null) {
		$e = mysqli_connect_error();
		$c = mysqli_connect_errno();
	} else {
		$e = mysqli_error($conn);
		$c = mysqli_errno($conn);
		mysqli_query($conn, 'ROLLBACK');
	}
	if ($e == '') $e = $err;
	if ($e == '') $e = 'unknown mysql error';
	if ($c) $e = $c."#".$e;
	err($e);
}

function pgerr($err, $conn)
{
	if ($conn == null) {
		$e = '';
	} else {
		$e = pg_last_error($conn);
		pg_free_result(pg_query($conn, 'ROLLBACK'));
	}
	if ($e == '') $e = $err;
	if ($e == '') $e = 'unknown pgsql error';
	err($e);
}


function dump($val)
{
	global $data;
	$len = strlen($val);
	if ($len < 255)
		$data .= chr($len);
	else
		$data .= "\xFF".pack('V', $len);
	$data .= $val;
	if (strlen($data) > 100000) {
		echo $data;
		$data = '';
	}

}

if (!array_key_exists('server', $_POST)) {
	 header('Content-Type: text/html');
	 echo "<html><head><title>EmsProxy v2.3</title></head><body><h1>EmsProxy v2.3</h1>emsproxy.php script is installed correctly.</body></html>";
	 exit;
}

function exception_error_handler($errno, $errstr, $errfile, $errline) {
	throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}

array_key_exists('server', $_POST) and array_key_exists('host', $_POST) and array_key_exists('port', $_POST) and array_key_exists('user', $_POST) and array_key_exists('password', $_POST) and array_key_exists('dbname', $_POST) or err("malformed request");

$commit = array_key_exists('commit', $_POST);

if ($_POST['server'] == 'mysql') {

	$port = $socket = $_POST['port'];
	$host = $_POST['host'];
	if (is_numeric($port))
		$socket = null;
	else {
		if (substr($socket, 0, 1) != '/') {
			$socket = "\\\\.\\pipe\\$socket";
			$host = '.';
		} else
			$host = 'localhost';
		$port = null;
	}

	mysqli_report(MYSQLI_REPORT_OFF);
	$conn = mysqli_connect($host, $_POST['user'], $_POST['password'], null, $port, $socket) or myerr('unknown connect error', null);
	if ($_POST['dbname'] != '')
		mysqli_select_db($conn, $_POST['dbname']) or myerr('database not found', $conn);
	if (array_key_exists('charset', $_POST) && $_POST['charset'] != '')
		mysqli_query($conn, '/*!40101 SET NAMES \'' . $_POST['charset'] . '\' */') or myerr('can not set character set', $conn);
	$result = FALSE;
	mysqli_query($conn, 'BEGIN') or myerr('unknown query execution error', $conn);
	for ($rn = 1; $rn < 1000; ++$rn) {
		if (!array_key_exists('r'.$rn, $_POST))
			break;
		$data = 'OK:';
		$req = $_POST['r'.$rn];
		if ($req == 'connect') {
			dump(mysqli_get_server_info($conn));
			dump(mysqli_get_client_info($conn));
			dump(mysqli_get_proto_info($conn));
			dump(mysqli_get_host_info($conn));
		} else {
			$result = mysqli_query($conn, $req) or myerr('unknown query execution error', $conn);
			if ($result === TRUE) {
				dump(0);
				dump(mysqli_affected_rows($conn));
			} else {
				$width = mysqli_num_fields($result);
				$height = mysqli_num_rows($result);
				dump($width);
				dump($height);
				for ($i = 0; $i < $width; ++$i) {
					$properties = mysqli_fetch_field_direct($result, $i);
					dump($properties->name);
					dump($properties->type);
					dump($properties->flags);
					dump($properties->length);
				}
				for ($i = 0; $i < $height; ++$i) {
					$row = mysqli_fetch_row($result);
					for ($j = 0; $j < $width; ++$j)
						if (is_null($row[$j]))
							dump('');
						else
							dump(' '.$row[$j]);
				}
				mysqli_free_result($result);
			}
		}
	}
	mysqli_query($conn, $commit ? 'COMMIT' : 'ROLLBACK') or myerr('unknown query execution error', $conn);

} elseif ($_POST['server'] == 'pgsql') {

	$conn_str = '';
	if ($_POST['host'] != '') $conn_str .= "host=$_POST[host]";
	if ($_POST['port'] != '') $conn_str .= " port=$_POST[port]";
	if ($_POST['dbname'] != '') $conn_str .= " dbname=$_POST[dbname]";
	if ($_POST['user'] != '') $conn_str .= " user=$_POST[user]";
	if ($_POST['password'] != '') $conn_str .= " password=$_POST[password]";

	set_error_handler("exception_error_handler");
	try {
		$conn = @pg_connect($conn_str);
	} catch (Exception $e) {
		pgerr(html_entity_decode($e->getMessage()), null);
	}
	restore_error_handler();

	if (!$commit || array_key_exists('r2', $_POST))
		pg_free_result(pg_query($conn, 'BEGIN'));
	$result = FALSE;
	for ($rn = 1; $rn < 1000; ++$rn) {
		if (!array_key_exists('r'.$rn, $_POST))
			break;
		$data = 'OK:';
		$req = $_POST['r'.$rn];
		if ($req == 'connect') {
			dump(0);
			dump(0);
			dump(0);
		} elseif (substr($req, 0, 11) == 'blob_create') {
			list($oid) = sscanf($req, 'blob_create %u');
			pg_free_result(pg_query($conn, $commit ? 'COMMIT' : 'ROLLBACK'));
			pg_free_result(pg_query($conn, 'BEGIN'));
			$oid = pg_lo_create($conn) or pgerr('lo_create failed', $conn);
			pg_free_result(pg_query($conn, 'COMMIT'));
			pg_free_result(pg_query($conn, 'BEGIN'));
			dump($oid);
		} elseif (substr($req, 0, 11) == 'blob_delete') {
			list($oid) = sscanf($req, 'blob_delete %u');
			$oid = pg_lo_unlink($conn, $oid) or pgerr('lo_unlink failed', $conn);
		} elseif (substr($req, 0, 10) == 'blob_write') {
			list($oid) = sscanf($req, 'blob_write %s ');
			$bin = substr($req, 12+strlen($oid));
			$obj = pg_lo_open($conn, $oid,'w') or pgerr('lo_open failed', $conn);
			$res = pg_lo_write($obj, $bin) or pgerr('lo_write failed', $conn);
			pg_lo_close($obj);
			dump($res);
		} elseif (substr($req, 0, 9) == 'blob_read') {
			list($oid) = sscanf($req, 'blob_read %u');
			$obj = pg_lo_open($conn, $oid, 'r') or pgerr('lo_open failed', $conn);
			pg_lo_seek($obj, 0, PGSQL_SEEK_END);
			$len = pg_lo_tell($obj);
			pg_lo_seek($obj, 0, PGSQL_SEEK_SET);
			$res = pg_lo_read($obj, $len) or pgerr('lo_read failed', $conn);
			pg_lo_close($obj);
			dump($res);
		} else {
			$result = pg_query($conn, $req) or pgerr("error at request: $req", $conn);
			if (pg_result_status($result) == PGSQL_COMMAND_OK) {
				dump(0);
				dump(pg_affected_rows($result));
				dump(pg_last_oid($result));
				pg_free_result($result);
			} elseif (pg_result_status($result) == PGSQL_EMPTY_QUERY) {
				dump(0);
				dump(0);
				pg_free_result($result);
			} elseif (pg_result_status($result) == PGSQL_TUPLES_OK) {
				$width = pg_num_fields($result);
				$height = pg_num_rows($result);
				dump($width);
				dump($height);
				for ($i = 0; $i < $width; ++$i) {
					$type = pg_field_type($result, $i);
					dump(pg_field_name($result, $i));
					dump($type);
					dump(pg_field_size($result, $i));
				}
				for ($i = 0; $i < $height; ++$i) {
					$row = pg_fetch_row($result);
					for ($j = 0; $j < $width; ++$j)
						if (is_null($row[$j]))
							dump('');
						else
							dump(' '.$row[$j]);
				}
				pg_free_result($result);
			} else {
				$e = pg_result_error($result);
				pg_free_result($result);
				err($e);
			}
		}
	}
	pg_free_result(pg_query($conn, $commit ? 'COMMIT' : 'ROLLBACK'));

} else {
	err("server type '$_POST[server] is not supported");
}
if ($data != '') echo $data;
?>
