5 * @author Benjamin Nowack
6 * @license <http://arc.semsol.org/license>
7 * @homepage <http://arc.semsol.org/>
14 class ARC2_StoreEndpoint extends ARC2_Store {
16 function __construct($a = '', &$caller) {
17 parent::__construct($a, $caller);
20 function ARC2_StoreEndpoint($a = '', &$caller) {
21 $this->__construct($a, $caller);
26 $this->headers = array('http' => 'HTTP/1.1 200 OK', 'vary' => 'Vary: Accept');
27 $this->read_key = $this->v('endpoint_read_key', '', $this->a);
28 $this->write_key = $this->v('endpoint_write_key', '', $this->a);
29 $this->a['store_allow_extension_functions'] = $this->v('store_allow_extension_functions', 0, $this->a);
30 $this->allow_sql = $this->v('endpoint_enable_sql_output', 0, $this->a);
36 function getQueryString($mthd = '') {
38 if (!$mthd || ($mthd == 'post')) {
39 $r = @file_get_contents('php://input');
41 $r = !$r ?$this->v1('QUERY_STRING', '', $_SERVER) : $r;
45 function p($name='', $mthd = '', $multi = '', $default = '') {
46 $mthd = strtolower($mthd);
48 $qs = $this->getQueryString($mthd);
49 if (preg_match_all('/\&' . $name . '=([^\&]+)/', $qs, $m)){
50 foreach ($m[1] as $i => $val) {
51 $m[1][$i] = stripslashes($val);
55 return $default ? $default : array();
57 $args = array_merge($_GET, $_POST);
58 $r = isset($args[$name]) ? $args[$name] : $default;
59 return is_array($r) ? $r : stripslashes($r);
64 function getFeatures() {
65 return $this->v1('endpoint_features', array(), $this->a);
68 function setHeader($k, $v) {
69 $this->headers[$k] = $v;
72 function sendHeaders() {
73 if (!isset($this->is_dump) || !$this->is_dump) {
74 $this->setHeader('content-length', 'Content-Length: ' . strlen($this->getResult()));
75 foreach ($this->headers as $k => $v) {
81 function getResult() {
87 function handleRequest($auto_setup = 0) {
88 if (!$this->isSetUp()) {
91 return $this->handleRequest(0);
94 $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
95 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
96 $this->result = 'Missing configuration or the endpoint store was not set up yet.';
99 elseif (($img = $this->p('img'))) {
100 $this->handleImgRequest($img);
102 elseif (($q = $this->p('query'))) {
103 $this->checkProcesses();
104 $this->handleQueryRequest($q);
105 if ($this->p('show_inline')) {
106 $this->query_result = '
107 <div class="results">
108 ' . ($this->p('output') != 'htmltab' ? '<pre>' . htmlspecialchars($this->getResult()) . '</pre>' : $this->getResult()) . '
111 $this->handleEmptyRequest();
115 $this->handleEmptyRequest();
119 function go($auto_setup = 0) {
120 $this->handleRequest($auto_setup);
121 $this->sendHeaders();
122 echo $this->getResult();
127 function handleImgRequest($img) {
128 $this->setHeader('content-type', 'Content-type: image/gif');
130 'bg_body' => base64_decode('R0lGODlhAQBkAMQAAPf39/Hx8erq6vPz8/Ly8u/v7+np6fT09Ovr6/b29u3t7ejo6Pz8/Pv7+/39/fr6+vj4+P7+/vn5+f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAGQAAAUp4GIIiFIExHAkAAC9cAxJdG3TT67vTe//jKBQ6Cgaj5GkcpmcOJ/QZwgAOw=='),
132 $this->result = isset($imgs[$img]) ? $imgs[$img] : '';
133 $this->sendHeaders();
134 echo $this->getResult();
140 function handleEmptyRequest() {
141 /* service description */
143 'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 'html' => 'HTML'
145 if ($this->getResultFormat($formats, 'html') != 'HTML') {
146 $this->handleServiceDescriptionRequest();
149 $this->setHeader('content-type', 'Content-type: text/html; charset=utf-8');
150 $this->result = $this->getHTMLFormDoc();
156 function handleServiceDescriptionRequest() {
158 PREFIX void: <http://rdfs.org/ns/void#>
160 <> void:sparqlEndpoint <> .
166 $this->handleQueryRequest($q);
171 function checkProcesses() {
172 if (method_exists($this->caller, 'checkSPARQLEndpointProcesses')) {
173 $sub_r = $this->caller->checkSPARQLEndpointProcesses();
179 function handleQueryRequest($q) {
180 if (preg_match('/^dump/i', $q)) {
181 $infos = array('query' => array('type' => 'dump'));
185 ARC2::inc('SPARQLPlusParser');
186 $p = & new ARC2_SPARQLPlusParser($this->a, $this);
188 $infos = $p->getQueryInfos();
191 if ($errors = $this->getErrors()) {
192 $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
193 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
194 $this->result = join("\n", $errors);
197 $qt = $infos['query']['type'];
198 /* wrong read key? */
199 if ($this->read_key && ($this->p('key') != $this->read_key) && preg_match('/^(select|ask|construct|describe|dump)$/', $qt)) {
200 $this->setHeader('http', 'HTTP/1.1 401 Access denied');
201 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
202 $this->result = 'Access denied. Missing or wrong "key" parameter.';
205 /* wrong write key? */
206 if ($this->write_key && ($this->p('key') != $this->write_key) && preg_match('/^(load|insert|delete|update)$/', $qt)) {
207 $this->setHeader('http', 'HTTP/1.1 401 Access denied');
208 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
209 $this->result = 'Access denied. Missing or wrong "key" parameter.';
212 /* non-allowed query type? */
213 if (!in_array($qt, $this->getFeatures())) {
214 $this->setHeader('http', 'HTTP/1.1 401 Access denied');
215 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
216 $this->result = 'Access denied for "' .$qt. '" query';
219 /* load/insert/delete via GET */
220 if (in_array($qt, array('load', 'insert', 'delete')) && isset($_GET['query'])) {
221 $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
222 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
223 $this->result = 'Query type "' .$qt. '" not supported via GET';
226 /* unsupported query type */
227 if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
228 $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
229 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
230 $this->result = 'Unsupported query type "' .$qt. '"';
234 $infos = $this->adjustQueryInfos($infos);
236 $r = array('result' => $this->runQuery($infos, $qt));
238 $r['query_time'] = $t2 - $t1;
240 if ($errors = $this->getErrors()) {
241 $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
242 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
243 $this->result = 'Error: ' . join("\n", $errors);
247 $m = 'get' . ucfirst($qt) . 'ResultDoc';
248 if (method_exists($this, $m)) {
249 $this->result = $this->$m($r);
252 $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
253 $this->result = 'Result serializer not available, dumping raw data:' . "\n" . print_r($r, 1);
259 function adjustQueryInfos($infos) {
261 if ($max_l = $this->v('endpoint_max_limit', 0, $this->a)) {
262 if ($this->v('limit', $max_l + 1, $infos['query']) > $max_l) {
263 $infos['query']['limit'] = $max_l;
266 /* default-graph-uri / named-graph-uri */
267 $dgs = $this->p('default-graph-uri', '', 1);
268 $ngs = $this->p('named-graph-uri', '', 1);
269 if (count(array_merge($dgs, $ngs))) {
271 foreach ($dgs as $g) {
272 $ds[] = array('graph' => $this->calcURI($g), 'named' => 0);
274 foreach ($ngs as $g) {
275 $ds[] = array('graph' => $this->calcURI($g), 'named' => 1);
277 $infos['query']['dataset'] = $ds;
279 /* infos result format */
280 if (($this->p('format') == 'infos') || ($this->p('output') == 'infos')) {
281 $infos['result_format'] = 'structure';
283 /* sql result format */
284 if (($this->p('format') == 'sql') || ($this->p('output') == 'sql')) {
285 $infos['result_format'] = 'sql';
292 function getResultFormat($formats, $default) {
295 if (($v = $this->p('format')) || ($v = $this->p('output'))) {
299 $vals = explode(',', $_SERVER['HTTP_ACCEPT']);
302 foreach ($vals as $val) {
303 if (preg_match('/(rdf\+n3|x\-turtle|rdf\+xml|sparql\-results\+xml|sparql\-results\+json|json)/', $val, $m)) {
305 if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
306 $o_vals[$m[1]] = 1 * $sub_m[1];
311 foreach ($o_vals as $val => $prio) {
317 foreach ($prefs as $pref) {
318 if (isset($formats[$pref])) {
319 return $formats[$pref];
326 function getSelectResultDoc($r) {
328 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
329 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
330 'php_ser' => 'PHPSER', 'plain' => 'Plain',
331 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
333 'htmltab' => 'HTMLTable',
336 if ($f = $this->getResultFormat($formats, 'xml')) {
337 $m = 'get' . $f . 'SelectResultDoc';
338 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
343 function getSPARQLXMLSelectResultDoc($r) {
344 $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
345 $vars = $r['result']['variables'];
346 $rows = $r['result']['rows'];
347 $dur = $r['query_time'];
351 '<?xml version="1.0"?>' .
352 $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
355 $r .= $nl . ' <head>';
356 $r .= $nl . ' <!-- query time: '. round($dur, 4) .' sec -->';
357 if (is_array($vars)) {
358 foreach ($vars as $var) {
359 $r .= $nl . ' <variable name="' .$var. '"/>';
362 $r .= $nl . ' </head>';
364 $r .= $nl . ' <results>';
365 if (is_array($rows)) {
366 foreach ($rows as $row) {
367 $r .= $nl . ' <result>';
368 foreach ($vars as $var) {
369 if (isset($row[$var])) {
370 $r .= $nl . ' <binding name="' .$var. '">';
371 if ($row[$var . ' type'] == 'uri') {
372 $r .= $nl . ' <uri>' .htmlspecialchars($row[$var]). '</uri>';
374 elseif ($row[$var . ' type'] == 'bnode') {
375 $r .= $nl . ' <bnode>' .substr($row[$var], 2). '</bnode>';
378 $dt = isset($row[$var . ' datatype']) ? ' datatype="' .htmlspecialchars($row[$var . ' datatype']). '"' : '';
379 $lang = isset($row[$var . ' lang']) ? ' xml:lang="' .htmlspecialchars($row[$var . ' lang']). '"' : '';
380 $r .= $nl . ' <literal' . $dt . $lang . '>' .htmlspecialchars($row[$var]). '</literal>';
382 $r .= $nl . ' </binding>';
385 $r .= $nl . ' </result>';
388 $r .= $nl . ' </results>';
390 $r .= $nl . '</sparql>';
394 function getSPARQLJSONSelectResultDoc($r) {
395 $con = $this->getDBCon();
396 $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
397 $vars = $r['result']['variables'];
398 $rows = $r['result']['rows'];
399 $dur = $r['query_time'];
404 $r .= $nl . ' "head": {';
405 $r .= $nl . ' "vars": [';
407 foreach ($vars as $var) {
408 $r .= $first_var ? $nl : ',' . $nl;
409 $r .= ' "' .$var. '"';
415 $r .= $nl . ' "results": {';
416 $r .= $nl . ' "bindings": [';
418 foreach ($rows as $row) {
419 $r .= $first_row ? $nl : ',' . $nl;
422 foreach ($vars as $var) {
423 if (isset($row[$var])) {
424 $r .= $first_var ? $nl : ',' . $nl . $nl;
425 $r .= ' "' .$var. '": {';
426 if ($row[$var . ' type'] == 'uri') {
427 $r .= $nl . ' "type": "uri",';
428 $r .= $nl . ' "value": "' .mysql_real_escape_string($row[$var], $con). '"';
430 elseif ($row[$var . ' type'] == 'bnode') {
431 $r .= $nl . ' "type": "bnode",';
432 $r .= $nl . ' "value": "' . substr($row[$var], 2) . '"';
435 $dt = isset($row[$var . ' datatype']) ? ',' . $nl .' "datatype": "' .mysql_real_escape_string($row[$var . ' datatype'], $con). '"' : '';
436 $lang = isset($row[$var . ' lang']) ? ',' . $nl .' "xml:lang": "' .mysql_real_escape_string($row[$var . ' lang'], $con). '"' : '';
437 $type = $dt ? 'typed-literal' : 'literal';
438 $r .= $nl . ' "type": "' . $type . '",';
439 $r .= $nl . ' "value": "' . $this->jsonEscape($row[$var]) . '"';
453 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
454 $r = $v . '(' . $r . ')';
459 function getPHPSERSelectResultDoc($r) {
460 $this->setHeader('content-type', 'Content-Type: text/plain');
461 return serialize($r);
464 function getPlainSelectResultDoc($r) {
465 $this->setHeader('content-type', 'Content-Type: text/plain');
466 return print_r($r['result'], 1);
469 function getHTMLTableSelectResultDoc($r) {
470 $this->setHeader('content-type', 'Content-Type: text/html; charset=utf-8');
471 $vars = $r['result']['variables'];
472 $rows = $r['result']['rows'];
473 $dur = $r['query_time'];
474 if ($this->p('show_inline')) return '<table>' . $this->getHTMLTableRows($rows, $vars) . '</table>';
475 return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
476 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
477 ' .$this->getHTMLDocHead() . '
480 ' . $this->getHTMLTableRows($rows, $vars) . '
487 function getHTMLTableRows($rows, $vars) {
489 foreach ($rows as $row) {
492 foreach ($vars as $var) {
493 $hr .= $r ? '' : '<th>' . htmlspecialchars($var) . '</th>';
494 $rr .= '<td>' . @htmlspecialchars($row[$var]) . '</td>';
496 $r .= $hr ? '<tr>' . $hr . '</tr>' : '';
497 $r .= '<tr>' . $rr . '</tr>';
499 return $r ? $r : '<em>No results found</em>';
502 function getTSVSelectResultDoc($r) {
503 $this->setHeader('content-type', 'Content-Type: text/plain; charset=utf-8');
504 $vars = $r['result']['variables'];
505 $rows = $r['result']['rows'];
506 $dur = $r['query_time'];
507 return $this->getTSVRows($rows, $vars);
510 function getTSVRows($rows, $vars) {
514 foreach ($rows as $row) {
517 foreach ($vars as $var) {
518 $hr .= $r ? '' : ($hr ? $delim . $var : $var);
519 $val = isset($row[$var]) ? str_replace($delim, $esc_delim, $row[$var]) : '';
520 $rr .= $rr ? $delim . $val : $val;
522 $r .= $hr . "\n" . $rr;
524 return $r ? $r : 'No results found';
529 function getAskResultDoc($r) {
531 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
532 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
534 'php_ser' => 'PHPSER',
535 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
538 if ($f = $this->getResultFormat($formats, 'xml')) {
539 $m = 'get' . $f . 'AskResultDoc';
540 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
545 function getSPARQLXMLAskResultDoc($r) {
546 $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
547 $r_val = $r['result'] ? 'true' : 'false';
548 $dur = $r['query_time'];
551 '<?xml version="1.0"?>' .
552 $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
554 $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
556 $nl . ' <boolean>' .$r_val. '</boolean>' .
561 function getSPARQLJSONAskResultDoc($r) {
562 $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
563 $r_val = $r['result'] ? 'true' : 'false';
564 $dur = $r['query_time'];
570 $nl . ' "boolean" : ' . $r_val .
573 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
574 $r = $v . '(' . $r . ')';
579 function getPHPSERAskResultDoc($r) {
580 $this->setHeader('content-type', 'Content-Type: text/plain');
581 return serialize($r);
584 function getPlainAskResultDoc($r) {
585 $this->setHeader('content-type', 'Content-Type: text/plain');
586 return $r['result'] ? 'true' : 'false';
591 function getConstructResultDoc($r) {
593 'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
594 'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
595 'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
596 'php_ser' => 'PHPSER',
597 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
600 if ($f = $this->getResultFormat($formats, 'rdfxml')) {
601 $m = 'get' . $f . 'ConstructResultDoc';
602 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
607 function getRDFXMLConstructResultDoc($r) {
608 $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
609 $index = $r['result'];
610 $ser = ARC2::getRDFXMLSerializer($this->a);
611 $dur = $r['query_time'];
612 return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
615 function getTurtleConstructResultDoc($r) {
616 $this->setHeader('content-type', 'Content-Type: application/x-turtle');
617 $index = $r['result'];
618 $ser = ARC2::getTurtleSerializer($this->a);
619 $dur = $r['query_time'];
620 return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
623 function getRDFJSONConstructResultDoc($r) {
624 $this->setHeader('content-type', 'Content-Type: application/json');
625 $index = $r['result'];
626 $ser = ARC2::getRDFJSONSerializer($this->a);
627 $dur = $r['query_time'];
628 $r = $ser->getSerializedIndex($index);
629 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
630 $r = $v . '(' . $r . ')';
635 function getPHPSERConstructResultDoc($r) {
636 $this->setHeader('content-type', 'Content-Type: text/plain');
637 return serialize($r);
640 function getPlainConstructResultDoc($r) {
641 $this->setHeader('content-type', 'Content-Type: text/plain');
642 return print_r($r['result'], 1);
647 function getDescribeResultDoc($r) {
649 'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
650 'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
651 'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
652 'php_ser' => 'PHPSER',
653 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
656 if ($f = $this->getResultFormat($formats, 'rdfxml')) {
657 $m = 'get' . $f . 'DescribeResultDoc';
658 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
663 function getRDFXMLDescribeResultDoc($r) {
664 $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
665 $index = $r['result'];
666 $ser = ARC2::getRDFXMLSerializer($this->a);
667 $dur = $r['query_time'];
668 return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
671 function getTurtleDescribeResultDoc($r) {
672 $this->setHeader('content-type', 'Content-Type: application/x-turtle');
673 $index = $r['result'];
674 $ser = ARC2::getTurtleSerializer($this->a);
675 $dur = $r['query_time'];
676 return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
679 function getRDFJSONDescribeResultDoc($r) {
680 $this->setHeader('content-type', 'Content-Type: application/json');
681 $index = $r['result'];
682 $ser = ARC2::getRDFJSONSerializer($this->a);
683 $dur = $r['query_time'];
684 $r = $ser->getSerializedIndex($index);
685 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
686 $r = $v . '(' . $r . ')';
691 function getPHPSERDescribeResultDoc($r) {
692 $this->setHeader('content-type', 'Content-Type: text/plain');
693 return serialize($r);
696 function getPlainDescribeResultDoc($r) {
697 $this->setHeader('content-type', 'Content-Type: text/plain');
698 return print_r($r['result'], 1);
703 function getDumpResultDoc() {
704 $this->headers = array();
710 function getLoadResultDoc($r) {
712 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
713 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
715 'php_ser' => 'PHPSER',
716 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
719 if ($f = $this->getResultFormat($formats, 'xml')) {
720 $m = 'get' . $f . 'LoadResultDoc';
721 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
726 function getSPARQLXMLLoadResultDoc($r) {
727 $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
728 $r_val = $r['result']['t_count'];
729 $dur = $r['query_time'];
732 '<?xml version="1.0"?>' .
733 $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
735 $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
737 $nl . ' <inserted>' .$r_val. '</inserted>' .
742 function getSPARQLJSONLoadResultDoc($r) {
743 $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
744 $r_val = $r['result']['t_count'];
745 $dur = $r['query_time'];
751 $nl . ' "inserted" : ' . $r_val .
754 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
755 $r = $v . '(' . $r . ')';
760 function getPHPSERLoadResultDoc($r) {
761 $this->setHeader('content-type', 'Content-Type: text/plain');
762 return serialize($r);
765 function getPlainLoadResultDoc($r) {
766 $this->setHeader('content-type', 'Content-Type: text/plain');
767 return print_r($r['result'], 1);
772 function getDeleteResultDoc($r) {
774 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
775 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
777 'php_ser' => 'PHPSER'
779 if ($f = $this->getResultFormat($formats, 'xml')) {
780 $m = 'get' . $f . 'DeleteResultDoc';
781 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
786 function getSPARQLXMLDeleteResultDoc($r) {
787 $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
788 $r_val = $r['result']['t_count'];
789 $dur = $r['query_time'];
792 '<?xml version="1.0"?>' .
793 $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
795 $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
797 $nl . ' <deleted>' .$r_val. '</deleted>' .
802 function getSPARQLJSONDeleteResultDoc($r) {
803 $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
804 $r_val = $r['result']['t_count'];
805 $dur = $r['query_time'];
811 $nl . ' "deleted" : ' . $r_val .
814 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
815 $r = $v . '(' . $r . ')';
820 function getPHPSERDeleteResultDoc($r) {
821 $this->setHeader('content-type', 'Content-Type: text/plain');
822 return serialize($r);
825 function getPlainDeleteResultDoc($r) {
826 $this->setHeader('content-type', 'Content-Type: text/plain');
827 return print_r($r['result'], 1);
832 function getInsertResultDoc($r) {
834 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
835 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
837 'php_ser' => 'PHPSER'
839 if ($f = $this->getResultFormat($formats, 'xml')) {
840 $m = 'get' . $f . 'InsertResultDoc';
841 return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
846 function getSPARQLXMLInsertResultDoc($r) {
847 $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
848 $r_val = $r['result']['t_count'];
849 $dur = $r['query_time'];
852 '<?xml version="1.0"?>' .
853 $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
855 $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
857 $nl . ' <inserted>' .$r_val. '</inserted>' .
862 function getSPARQLJSONInsertResultDoc($r) {
863 $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
864 $r_val = $r['result']['t_count'];
865 $dur = $r['query_time'];
871 $nl . ' "inserted" : ' . $r_val .
874 if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
875 $r = $v . '(' . $r . ')';
880 function getPHPSERInsertResultDoc($r) {
881 $this->setHeader('content-type', 'Content-Type: text/plain');
882 return serialize($r);
885 function getPlainInsertResultDoc($r) {
886 $this->setHeader('content-type', 'Content-Type: text/plain');
887 return print_r($r['result'], 1);
892 function jsonEscape($v) {
893 if (function_exists('json_encode')) return trim(json_encode($v), '"');
894 $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
895 $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
896 return str_replace($from, $to, $v);
901 function getHTMLFormDoc() {
902 return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
903 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
904 ' . $this->getHTMLDocHead() . '
905 ' . $this->getHTMLDocBody() . '
910 function getHTMLDocHead() {
913 <title>' . $this->getHTMLDocTitle() . '</title>
914 <style type="text/css">
915 ' . $this->getHTMLDocCSS() . '
921 function getHTMLDocTitle() {
922 return $this->v('endpoint_title', 'ARC SPARQL+ Endpoint', $this->a);
925 function getHTMLDocHeading() {
926 return $this->v('endpoint_heading', 'ARC SPARQL+ Endpoint (v' . ARC2::getVersion() . ')', $this->a);
929 function getHTMLDocCSS() {
933 font-family: Trebuchet MS, Verdana, Geneva, sans-serif;
934 background: #fff url(?img=bg_body) top center repeat-x;
935 padding: 5px 20px 20px 20px;
938 h1 { font-size: 1.6em; font-weight: normal; }
939 a { color: #c00000; }
941 border: 1px dotted #eee;
958 border-top: 1px solid #ccc;
965 padding: 0px 10px 5px 20px;
968 border-top: 1px dotted #ddd;
971 .options dl dt.first {
975 padding: 5px 0px 7px 0px;
984 border: 1px solid #eee;
986 background-color: #fcfcfc;
989 return $this->v('endpoint_css', $default, $this->a);
992 function getHTMLDocBody() {
995 <h1>' . $this->getHTMLDocHeading() . '</h1>
998 <a href="?">This interface</a> implements
999 <a href="http://www.w3.org/TR/rdf-sparql-query/">SPARQL</a> and
1000 <a href="http://arc.semsol.org/docs/v2/sparql+">SPARQL+</a> via <a href="http://www.w3.org/TR/rdf-sparql-protocol/#query-bindings-http">HTTP Bindings</a>.
1003 Enabled operations: ' . join(', ', $this->getFeatures()) . '
1006 Max. number of results : ' . $this->v('endpoint_max_limit', '<em>unrestricted</em>', $this->a) . '
1009 ' . $this->getHTMLDocForm() .'
1010 ' . ($this->p('show_inline') ? $this->query_result : '') . '
1015 function getHTMLDocForm() {
1016 $q = $this->p('query') ? htmlspecialchars($this->p('query')) : "SELECT * WHERE {\n GRAPH ?g { ?s ?p ?o . }\n}\nLIMIT 10";
1018 <form id="sparql-form" action="?" enctype="application/x-www-form-urlencoded" method="' . ($_SERVER['REQUEST_METHOD'] == 'GET' ? 'get' : 'post' ) . '">
1019 <textarea id="query" name="query" rows="20" cols="80">' . $q . '</textarea>
1020 ' . $this->getHTMLDocOptions() . '
1021 <div class="form-buttons">
1022 <input type="submit" value="Send Query" />
1023 <input type="reset" value="Reset" />
1029 function getHTMLDocOptions() {
1030 $sel = $this->p('output');
1031 $sel_code = ' selected="selected"';
1033 <div class="options">
1036 <dt class="first">Output format (if supported by query type):</dt>
1038 <select id="output" name="output">
1039 <option value="" ' . (!$sel ? $sel_code : '') . '>default</option>
1040 <option value="xml" ' . ($sel == 'xml' ? $sel_code : '') . '>XML</option>
1041 <option value="json" ' . ($sel == 'json' ? $sel_code : '') . '>JSON</option>
1042 <option value="plain" ' . ($sel == 'plain' ? $sel_code : '') . '>Plain</option>
1043 <option value="php_ser" ' . ($sel == 'php_ser' ? $sel_code : '') . '>Serialized PHP</option>
1044 <option value="turtle" ' . ($sel == 'turtle' ? $sel_code : '') . '>Turtle</option>
1045 <option value="rdfxml" ' . ($sel == 'rdfxml' ? $sel_code : '') . '>RDF/XML</option>
1046 <option value="infos" ' . ($sel == 'infos' ? $sel_code : '') . '>Query Structure</option>
1047 ' . ($this->allow_sql ? '<option value="sql" ' . ($sel == 'sql' ? $sel_code : '') . '>SQL</option>' : '') . '
1048 <option value="htmltab" ' . ($sel == 'htmltab' ? $sel_code : '') . '>HTML Table</option>
1049 <option value="tsv" ' . ($sel == 'tsv' ? $sel_code : '') . '>TSV</option>
1053 <dt>jsonp/callback (for JSON results)</dt>
1055 <input type="text" id="jsonp" name="jsonp" value="' . htmlspecialchars($this->p('jsonp')) . '" />
1058 <dt>API key (if required)</dt>
1060 <input type="text" id="key" name="key" value="' . htmlspecialchars($this->p('key')) . '" />
1063 <dt>Show results inline: </dt>
1065 <input type="checkbox" name="show_inline" value="1" ' . ($this->p('show_inline') ? ' checked="checked"' : '') . ' />
1070 <div class="options-2">
1072 <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'get\'">GET</a>
1073 <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'post\'">POST</a>