Commit 8e8f453c225b2284286960940731d49d01407b12

Authored by Nathanael Jourdane
1 parent e7d7b0fd

VOTable parser: returns detailled error informations when querying a service with a bad adql query.

Showing 2 changed files with 45 additions and 79 deletions   Show diff stats
php/classes/EpnTapMgr.php
... ... @@ -6,13 +6,6 @@
6 6 class EpnTapMgr {
7 7 private $logEpnTap;
8 8  
9   - private function addLog($msg)
10   - {
11   - // fwrite($this->logEpnTap, date("h:i:s A") . ": " . $msg . "\n");
12   - error_log("INFO " . $msg);
13   - // print "test";
14   - }
15   -
16 9 private function dateToJD($gregorian_date) {
17 10 list($day, $month, $year, $hours, $minutes, $seconds) = preg_split('/[\s\/:]+/', $gregorian_date);
18 11 return GregorianToJD($month, $day, $year) + $hours/24 + $minutes/(24*60) + $seconds/(24*60*60);
... ... @@ -46,7 +39,7 @@ class EpnTapMgr {
46 39 $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode(preg_replace('/\s+/', ' ', $query)); // remove also multiple whitespaces
47 40  
48 41 $res = $votMgr->load($url);
49   - $this->addLog("Query URL: " . $url);
  42 + error_log("Query URL: " . $url);
50 43 $result = $votMgr->parseStream();
51 44 return $votMgr->getVotableError() ? array('error' => $votMgr->getVotableError()) : $result;
52 45 }
... ... @@ -54,7 +47,6 @@ class EpnTapMgr {
54 47 /* filter order: product type, target name, time min, time max */
55 48 public function getGranules($table_name, $access_url, $filter, $select, $limit, $offset) {
56 49 $query = "SELECT TOP {$limit} " . join(', ', $select) . " FROM {$table_name}.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]) . " OFFSET {$offset}";
57   - // return $query;
58 50 $result = $this->request($access_url, $query);
59 51 if(! array_key_exists("error", $result)) {
60 52 for ($i = 0 ; $i < sizeof($result) ; $i++) {
... ... @@ -67,10 +59,37 @@ class EpnTapMgr {
67 59 return $result;
68 60 }
69 61  
  62 + /* Return the list of available services by querying some usual registries. */
  63 + public function getServices() {
  64 + $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"];
  65 + $columns = ['short_name', 'res_title', 'ivoid', 'access_url', 'table_name', 'content_type', 'creator_seq', 'content_level', 'reference_url', 'created', 'updated'];
  66 + $getServicesQuery = "SELECT DISTINCT " . implode(', ', $columns) . " FROM rr.resource
  67 + NATURAL JOIN rr.res_schema NATURAL JOIN rr.res_table NATURAL JOIN rr.interface NATURAL JOIN rr.res_detail NATURAL JOIN rr.capability
  68 + WHERE standard_id='ivo://ivoa.net/std/tap' AND intf_type='vs:paramhttp' AND detail_xpath='/capability/dataModel/@ivo-id'
  69 + AND 1=ivo_nocasematch(detail_value, 'ivo://vopdc.obspm/std/EpnCore%') AND table_name LIKE '%.epn_core' ORDER BY short_name, table_name";
  70 +
  71 + for($i=0; $i<count($registriesURL); $i++) {
  72 + $services = $this->request($registriesURL[$i], $getServicesQuery);
  73 + if(! array_key_exists("error", $services)) {
  74 + for($j=0; $j<count($services); $j++) {
  75 + $services[$j]['id'] = $this->generateServiceId($services[$j]);
  76 + }
  77 + return $services;
  78 + } else if($i === count($registriesURL)-1) {
  79 + error_log("Can not access any of these services : " . implode(', ', $registriesURL) . ".");
  80 + return;
  81 + }
  82 + }
  83 + }
  84 +
  85 + /* Generate a unique service identifier from the service ivoid and the table name. */
  86 + public function generateServiceId($service) {
  87 + return str_replace(['ivo://', '.epn_core'], '', $service['ivoid'] . '/' . $service['table_name']);
  88 + }
  89 +
70 90 /* filter order: product type, target name, time min, time max */
71 91 public function getNbRows($table_name, $access_url, $filter) {
72 92 $query = "SELECT COUNT(*) AS nb_rows FROM {$table_name}.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]);
73   - // return $query;
74 93 return $this->request($access_url, $query)[0]['nb_rows'];
75 94 }
76 95  
... ...
php/classes/VOTableMgr.php
... ... @@ -4,9 +4,8 @@
4 4 * @version $Id: VOTableMgr.php 2916 2015-05-19 13:08:33Z elena $
5 5 */
6 6  
7   -//set DEBUG_MODE to TRUE to have some log information in user data dir
8   -define("DEBUG_MODE", TRUE);
9   -
  7 +//set DEBUG_MODE to TRUE to have some log information
  8 +define("DEBUG_MODE", FALSE);
10 9  
11 10 class VOTableMgr {
12 11 private $xml, $xp;
... ... @@ -16,14 +15,8 @@ class VOTableMgr {
16 15 private $is_little_endian;
17 16 private $votable_error = false;
18 17  
19   - function addLog($msg) {
20   - if (DEBUG_MODE) {
21   - error_log("INFO " . $msg);
22   - }
23   - }
24   -
25 18 function load($fileName) {
26   - $this->addLog("File name " . $fileName);
  19 + // error_log("Loading " . $fileName);
27 20 $this->is_little_endian = array_values(unpack('L1L', pack('V', 1)))[0] == 1;
28 21  
29 22 // see http://php.net/manual/en/domdocument.load.php#91384
... ... @@ -31,35 +24,28 @@ class VOTableMgr {
31 24 'http' => array(
32 25 'method' => 'GET',
33 26 'timeout' => '5',
34   - 'user_agent' => 'PHP libxml agent'
  27 + 'user_agent' => 'PHP libxml agent',
  28 + // If the query is wrong, epn-tap service returns an HTTP error code 400, along with xml containing some usefull informations.
  29 + 'ignore_errors' => true
35 30 )
36 31 );
37 32 $context = stream_context_create($options);
38 33 libxml_set_streams_context($context);
39   -
40 34 $this->xml = new DomDocument();
41   - $res = $this->xml->load($fileName);
42 35  
43   - if(!$res) {
44   - $this->votable_error = "Can not load the XML file. Maybe the service is not accessible.";
45   - $this->addLog("Can not load XML.");
  36 + try {
  37 + $res = $this->xml->load($fileName);
  38 + } catch (Exception $e) {
  39 + $this->votable_error = $e->message;
46 40 return false;
47 41 }
48 42  
49 43 $this->checkIDAttribute();
50   - /*if ($this->xml->namespaceURI == '')
51   - {
52   - $this->addLog("File don't have a namespace defined\n");
53   - if (!$this->xml->createAttributeNS('http://www.ivoa.net/xml/VOTable/v1.1','xmlns'))
54   - $this->addLog("Cannot create namespace attribute\n");
55   - }
56   - $this->addLog($this->xml->namespaceURI."\n");*/
57 44  
58 45 $rootNamespace = $this->xml->lookupNamespaceUri($this->xml->namespaceURI);
59 46 $this->xp = new domxpath($this->xml);
60 47 $this->xp->registerNameSpace('x', $rootNamespace);
61 48  
62   - $this->addLog($fileName . " loaded.");
63 49 return true;
64 50 }
65 51  
... ... @@ -69,11 +55,13 @@ class VOTableMgr {
69 55  
70 56 function isValidSchema() {
71 57 if ($this->votable_error != false) {
  58 + error_log("There is an error on the VOTable: " . $this->votable_error);
72 59 return false;
73 60 }
74 61  
75 62 if (!$this->xml) {
76 63 $this->votable_error = "The returned file is not XML.";
  64 + error_log("There is an error on the VOTable: " . $this->votable_error);
77 65 return false;
78 66 }
79 67  
... ... @@ -81,6 +69,7 @@ class VOTableMgr {
81 69 foreach($infos as $info) {
82 70 if($info->getAttribute('value') == 'ERROR') {
83 71 $this->votable_error = $info->textContent;
  72 + error_log("There is an error on the VOTable: " . $this->votable_error);
84 73 return false;
85 74 }
86 75 }
... ... @@ -92,9 +81,6 @@ class VOTableMgr {
92 81 libxml_use_internal_errors(true);
93 82  
94 83 $vers = $this->getVersion();
95   -
96   - $this->addLog("VOTable version : ".$vers."\n");
97   -
98 84 $result = FALSE;
99 85  
100 86 switch ($vers)
... ... @@ -128,8 +114,7 @@ class VOTableMgr {
128 114 break;
129 115 }
130 116 $msg .= ($error->message." - In line : ".$error->line." - Of file : ".$error->file."\n");
131   -
132   - $this->addLog($msg);
  117 + error_log($msg);
133 118 }
134 119  
135 120 libxml_use_internal_errors(false);
... ... @@ -270,6 +255,7 @@ class VOTableMgr {
270 255 public function parseStream() {
271 256 if (! $this->isValidSchema()) {
272 257 return null;
  258 + // TODO: check this
273 259 }
274 260 $data = Array();
275 261 $fields = $this->xp->query($this->queryFields());
... ... @@ -292,8 +278,6 @@ class VOTableMgr {
292 278 $col_id = $n_value % $nb_columns;
293 279 $field_node = $fields[$col_id];
294 280  
295   - // echo "c=$this->c, n_value=$n_value, nb_columns=$nb_columns, col_id=$col_id, column_name=" . $field_node->getAttribute("ID") . "\n";
296   -
297 281 if($col_id == 0) {
298 282 $row = Array();
299 283 }
... ... @@ -302,7 +286,6 @@ class VOTableMgr {
302 286 array_push($data, $row);
303 287 }
304 288 $n_value+=1;
305   - // echo "Char pos: $this->c\n";
306 289 }
307 290 return $data;
308 291 }
... ... @@ -312,41 +295,6 @@ class VOTableMgr {
312 295 return "$day/$month/$year";
313 296 }
314 297  
315   - # because unpack for floats is hardware dependant
316   - // private function big_endian_unpack ($format, $data) {
317   - // $ar = unpack ($format, $data);
318   - // $vals = array_values ($ar);
319   - // echo "vals: " . json_encode($vals) . "\n";
320   - // $f = explode ('/', $format);
321   - // $i = 0;
322   - // foreach ($f as $f_k => $f_v) {
323   - // $repeater = intval (substr ($f_v, 1));
324   - //
325   - // if ($repeater == 0) {
326   - // $repeater = 1;
327   - // }
328   - // if ($f_v{1} == '*') {
329   - // $repeater = count ($ar) - $i;
330   - // }
331   - // if ($f_v{0} != 'd') {
332   - // $i += $repeater; continue;
333   - // }
334   - // $j = $i + $repeater;
335   - //
336   - // for ($a = $i; $a < $j; ++$a) {
337   - // $p = pack ('d', $vals[$i]);
338   - // $p = strrev ($p);
339   - // ++$i;
340   - // }
341   - // }
342   - // $a = 0;
343   - // foreach ($ar as $ar_k => $ar_v) {
344   - // $ar[$ar_k] = $vals[$a];
345   - // ++$a;
346   - // }
347   - // return $ar;
348   - // }
349   -
350 298 private function process_datablock($field_node) {
351 299 $data_type = $field_node->getAttribute("datatype");
352 300 $row_size = $this->get_row_size($field_node);
... ... @@ -390,11 +338,10 @@ class VOTableMgr {
390 338 break;
391 339 default:
392 340 $res = NULL;
393   - $this->addLog("Unknown character: $data_type");
  341 + error_log("Unknown character: $data_type");
394 342 break;
395 343 }
396 344 $this->c+=$row_size;
397   - // echo $field_node->getAttribute("ID") . "($data_type $row_size) = " . json_encode($res) . "\n";
398 345 return $res;
399 346 }
400 347  
... ...