epntap.php 8.67 KB
<?php

include(realpath(dirname(__FILE__) . "/config.php"));
include(CLASSPATH . "VOTableMgr.php");

$action = preg_replace("/[^a-zA-Z]+/", "", filter_var($_GET['action'], FILTER_SANITIZE_STRING));

switch ($action) {
	case 'resolver':
		$response = resolver();
		break;
	case 'getServices':
		$response = getServices();
		break;
	case 'getNbResults':
		$response = getNbResults();
		break;
	case 'getGranules':
		$response = getGranules();
		break;
	default:
		$response = ['success' => false, 'msg' => 'Unknown action: ' . $action];
		break;
}
echo json_encode($response);

function getParam($paramName, $default=null) {
	if(array_key_exists($paramName, $_GET)) {
		return filter_var($_GET[$paramName], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
	} else {
		return $default;
	}
}

function resolver() {
	$input = filter_var($_GET['input'], FILTER_SANITIZE_URL);
	$resolver_url = "http://voparis-registry.obspm.fr/ssodnet/1/autocomplete?q=%22$input%22";

	$response = ['success' => true, 'metaData' => ['root' => 'data', 'messageProperty' => 'msg']];
	try {
		$content = file_get_contents($resolver_url);
	} catch (Exception $e) {
		error_log('Resolver access error: ' . $e);
		$response['success'] = false;
		$response['msg'] = "Resolver unreachable on $resolver_url.";
	}
	try {
		$result = json_decode($content, true);
		$targets = array();
		foreach($result['hits'] as $e) {
			$aliases = '<li>' . join('</li><li>', $e['aliases']) . '</li>';
			$target = array('name' => $e['name'], 'type' => $e['type'], 'parent' => $e['parent'], 'aliases' => $aliases);
			array_push($targets, $target);
		}
		$response['data'] = $targets;
	} catch (Exception $e) {
		error_log('Resolver type error: ' . $e);
		$response['success'] = false;
		$response['msg'] = 'The resolver returned a bad result.';
	}
	return $response;
}

function request($access_url, $query) {
	$votMgr = new VOTableMgr;
	$params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery';
	$url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode(preg_replace('/\s+/', ' ', $query)); // remove also multiple whitespaces

	$votMgr->load($url);
	$data = $votMgr->parseStream();
	$error = $votMgr->getVotableError();

	$response = ['query' => $query, 'metaData' => ['root' => 'data', 'messageProperty' => 'msg']];
	if($error) {
		$response['success'] = false;
		$response['msg'] = $error;
	} else {
		$response['success'] = true;
		$response['data'] = $data;
	}
	return $response;
}

/* Return the list of available services by querying some usual registries. */
function getServices() {
	$registriesURL = ["http://registry.euro-vo.org/regtap/tap", "http://dc.zah.uni-heidelberg.de/tap", "http://gavo.aip.de/tap", "http://reg.g-vo.org/tap"];
	$columns = ['short_name', 'res_title', 'ivoid', 'access_url', 'table_name', 'content_type', 'creator_seq', 'content_level', 'reference_url', 'created', 'updated'];
	$query = "SELECT DISTINCT " . implode(', ', $columns) . " FROM rr.resource
			NATURAL JOIN rr.res_schema NATURAL JOIN rr.res_table NATURAL JOIN rr.interface NATURAL JOIN rr.res_detail NATURAL JOIN rr.capability
			WHERE standard_id='ivo://ivoa.net/std/tap' AND intf_type='vs:paramhttp' AND detail_xpath='/capability/dataModel/@ivo-id'
			AND 1=ivo_nocasematch(detail_value, 'ivo://vopdc.obspm/std/EpnCore%') AND table_name LIKE '%.epn_core' ORDER BY short_name, table_name";

	$regNumber = 0;
	for(; $regNumber<count($registriesURL) ; $regNumber++) {
		$response = request($registriesURL[$regNumber], $query);
		if($response['success']) {
			// Add several other parameters and remove AMDA
			for($j=0 ; $j<count($response['data']) ; $j++) {
				$response['data'][$j]['id'] = generateServiceId($response['data'][$j]);
				$response['data'][$j]['nb_results'] = -1;
				$response['data'][$j]['info'] = 'Please make a query.';
				if($response['data'][$j]['id'] == 'cdpp/amda/amdadb') {
					array_splice($response['data'], $j, 1);
					$j-=1;
				}
			}
			if(isset($lastErrorMesage)) {
				$response['msg'] = $lastErrorMesage;
			}
			break;
		} else {
			$lastErrorMesage = 'Last tried registry (' . $registriesURL[$regNumber] . ') returned this error: ' . $response['msg'] . '.';
		}
	}
	if(!$response['success']) {
		$response['msg'] = 'Can not access any of these registries: ' . implode(', ', $registriesURL) . ', last error message is ' . $lastErrorMesage;
	}
	return $response;
}

function getNbResults() {
	$query = "SELECT COUNT(*) AS nb_rows FROM " . getParam('tableName') . createFilter(getParam('targetName'), getParam('productTypes'), getParam('timeMin'), getParam('timeMax'));
	$response = request(getParam('url'), $query);
	if($response['success']) {
		$response['success'] = false;
		$response['msg'] = 'The service returned a bad value, can not get the number of results.';
		if(count($response['data']) < 1) {
			error_log('getNbResults error: Too few returned raws.');
		} else if(count($response['data']) > 1) {
			error_log('getNbResults error: Too many returned raws.');
		} else if(!array_key_exists(0, $response['data'])) {
			error_log('getNbResults error: cant find raw item 0');
		} else if(is_null($response['data'][0])) {
			error_log('getNbResults error: The returned raw is null.');
		} else if(!array_key_exists("nb_rows", $response['data'][0])) {
			error_log('getNbResults error: cant find nb_rows.');
		} else if(!is_numeric($response['data'][0]['nb_rows'])) {
			error_log('getNbResults error: The returned value is not a number.');
		} else {
			$response['success'] = true;
			$response['data'] = (int)($response['data'][0]['nb_rows']);
			$response['msg'] = 'The service returned ' . ($response['data'] == 0 ? 'no' : $response['data']) . ' result' . ($response['data'] > 1 ? 's' : '') . ' for the given query.';
		}
	}
	return $response;
}

function getGranules() {
	$sort = is_null(getParam('sort')) ? '' : "ORDER BY " . getParam('sort') . " " . getParam('dir');
	$filter = createFilter(getParam('targetName'), getParam('productTypes'), getParam('timeMin'), getParam('timeMax'));
	$query = "SELECT TOP " . getParam('limit') . " * FROM " . getParam('tableName') . " $filter $sort OFFSET " . getParam('start');
	// error_log('getGranules query: ' . $query);
	$response = request(getParam('url'), $query);
	if($response['success']) {
		$visibleColumns = ['granule_gid', 'obs_id', 'dataproduct_type', 'time_min', 'time_max', 'instrument_name', 'processing_level', 'access_estsize', 'thumbnail_url', 'access_url']; // rest are hidden
		$names = ['granule_gid' => 'GID', 'dataproduct_type' => 'Type', 'processing_level' => 'Proc. lvl', 'access_estsize' => 'Size', 'access_url' => 'URL']; // default: pretty printed key name
		$renderers = ['dataproduct_type' => 'type', 'time_min' => 'date', 'time_max' => 'date', 'processing_level' => 'proc_lvl',
			'access_estsize' => 'size', 'thumbnail_url' => 'img', 'access_url' => 'link', 'access_format' => 'format']; // default: text
		$widths = ['obs_id' => 75, 'time_min' => 75, 'time_max' => 75, 'instrument_name' => 75, 'processing_level' => 60]; // default: 50

		$fields = array();
		$columns = array();
		foreach($response['data'][0] as $key => $value) {
			$fields[] = ['name' => $key, 'type' => 'string'];
			$columns[] = [
				'dataIndex' => $key,
				'text' => array_key_exists($key, $names) ? $names[$key] : ucfirst(str_replace('_', ' ', $key)),
				'width' => array_key_exists($key, $widths) ? $widths[$key] : 50,
				'hidden' => !in_array($key, $visibleColumns),
				'filterable' => true,
				// 'filter' => ['type' => 'list', 'options' => ['Image', 'Map']],
				'renderer' => 'granule.' . (array_key_exists($key, $renderers) ? $renderers[$key] : 'text')
			];
		}

		$response['total'] = (int)getParam('nbRes');
		$response['metaData']['fields'] = $fields;
		$response['metaData']['columns'] = $columns;
		$response['metaData']['metaHash'] = md5(serialize($response['metaData']));
	}
	return $response;
}

// ----- utils -----

function createFilter($targetName, $productTypes, $timeMin, $timeMax) {
	$filter = array();
	if($targetName) {
		array_push($filter, "target_name = '$targetName'");
	}
	if($productTypes) {
		array_push($filter, "dataproduct_type IN ('" . join("', '", explode(';', $productTypes)) . "')");
	}
	if($timeMin) {
		array_push($filter, "time_max >= " . dateToJD($timeMin));
	}
	if($timeMax) {
		array_push($filter, "time_min <= " . dateToJD($timeMax));
	}
	return (count($filter) > 0 ? ' WHERE ' . join(' AND ', $filter) : '');
}

/* Generate a unique service identifier from the service ivoid and the table name. */
function generateServiceId($service) {
	return str_replace(['ivo://', '.epn_core'], '', $service['ivoid'] . '/' . $service['table_name']);
}

function dateToJD($gregorian_date) {
	list($day, $month, $year, $hours, $minutes, $seconds) = preg_split('/[\s\/:]+/', $gregorian_date);
	return GregorianToJD($month, $day, $year) + $hours/24 + $minutes/(24*60) + $seconds/(24*60*60);
}
?>