PageRenderTime 100ms CodeModel.GetById 44ms RepoModel.GetById 0ms app.codeStats 1ms

/common/arc2/store/ARC2_StoreEndpoint.php

https://github.com/tematres/TemaTres-Vocabulary-Server
PHP | 1083 lines | 948 code | 81 blank | 54 comment | 88 complexity | 271e797f33f6f9e3a7c07565bddb93e9 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-3.0
  1. <?php
  2. /**
  3. * ARC2 SPARQL Endpoint
  4. *
  5. * @author Benjamin Nowack
  6. * @license <http://arc.semsol.org/license>
  7. * @homepage <http://arc.semsol.org/>
  8. * @package ARC2
  9. * @version 2010-11-16
  10. */
  11. ARC2::inc('Store');
  12. class ARC2_StoreEndpoint extends ARC2_Store {
  13. function __construct($a, &$caller) {
  14. parent::__construct($a, $caller);
  15. }
  16. function __init() {
  17. parent::__init();
  18. $this->headers = array('http' => 'HTTP/1.1 200 OK', 'vary' => 'Vary: Accept');
  19. $this->read_key = $this->v('endpoint_read_key', '', $this->a);
  20. $this->write_key = $this->v('endpoint_write_key', '', $this->a);
  21. $this->timeout = $this->v('endpoint_timeout', 0, $this->a);
  22. $this->a['store_allow_extension_functions'] = $this->v('store_allow_extension_functions', 0, $this->a);
  23. $this->allow_sql = $this->v('endpoint_enable_sql_output', 0, $this->a);
  24. $this->result = '';
  25. }
  26. /* */
  27. function getQueryString($mthd = '') {
  28. $r = '';
  29. if (!$mthd || ($mthd == 'post')) {
  30. $r = @file_get_contents('php://input');
  31. }
  32. $r = !$r ?$this->v1('QUERY_STRING', '', $_SERVER) : $r;
  33. return $r;
  34. }
  35. function p($name='', $mthd = '', $multi = '', $default = '') {
  36. $mthd = strtolower($mthd);
  37. if($multi){
  38. $qs = $this->getQueryString($mthd);
  39. if (preg_match_all('/\&' . $name . '=([^\&]+)/', $qs, $m)){
  40. foreach ($m[1] as $i => $val) {
  41. $m[1][$i] = stripslashes($val);
  42. }
  43. return $m[1];
  44. }
  45. return $default ? $default : array();
  46. }
  47. $args = array_merge($_GET, $_POST);
  48. $r = isset($args[$name]) ? $args[$name] : $default;
  49. return is_array($r) ? $r : stripslashes($r);
  50. }
  51. /* */
  52. function getFeatures() {
  53. return $this->v1('endpoint_features', array(), $this->a);
  54. }
  55. function setHeader($k, $v) {
  56. $this->headers[$k] = $v;
  57. }
  58. function sendHeaders() {
  59. if (!isset($this->is_dump) || !$this->is_dump) {
  60. $this->setHeader('content-length', 'Content-Length: ' . strlen($this->getResult()));
  61. foreach ($this->headers as $k => $v) {
  62. header($v);
  63. }
  64. }
  65. }
  66. function getResult() {
  67. return $this->result;
  68. }
  69. /* */
  70. function handleRequest($auto_setup = 0) {
  71. if (!$this->isSetUp()) {
  72. if ($auto_setup) {
  73. $this->setUp();
  74. return $this->handleRequest(0);
  75. }
  76. else {
  77. $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
  78. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  79. $this->result = 'Missing configuration or the endpoint store was not set up yet. '.MSG__need2setup_endpoint;
  80. }
  81. }
  82. elseif (($img = $this->p('img'))) {
  83. $this->handleImgRequest($img);
  84. }
  85. elseif (($q = $this->p('query'))) {
  86. $this->checkProcesses();
  87. $this->handleQueryRequest($q);
  88. if ($this->p('show_inline')) {
  89. $this->query_result = '
  90. <div class="results">
  91. ' . ($this->p('output') != 'htmltab' ? '<pre>' . htmlspecialchars($this->getResult()) . '</pre>' : $this->getResult()) . '
  92. </div>
  93. ';
  94. $this->handleEmptyRequest(1);
  95. }
  96. }
  97. else {
  98. $this->handleEmptyRequest();
  99. }
  100. }
  101. //DAF
  102. function go($auto_setup = 0,$params=array()) {
  103. $this->handleRequest($auto_setup,$params);
  104. $this->sendHeaders();
  105. echo $this->getResult();
  106. }
  107. /* */
  108. function handleImgRequest($img) {
  109. $this->setHeader('content-type', 'Content-type: image/gif');
  110. $imgs = array(
  111. 'bg_body' => base64_decode('R0lGODlhAQBkAMQAAPf39/Hx8erq6vPz8/Ly8u/v7+np6fT09Ovr6/b29u3t7ejo6Pz8/Pv7+/39/fr6+vj4+P7+/vn5+f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAGQAAAUp4GIIiFIExHAkAAC9cAxJdG3TT67vTe//jKBQ6Cgaj5GkcpmcOJ/QZwgAOw=='),
  112. );
  113. $this->result = isset($imgs[$img]) ? $imgs[$img] : '';
  114. $this->sendHeaders();
  115. echo $this->getResult();
  116. exit;
  117. }
  118. /* */
  119. function handleEmptyRequest($force = 0) {
  120. /* service description */
  121. $formats = array(
  122. 'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 'html' => 'HTML'
  123. );
  124. if (!$force && $this->getResultFormat($formats, 'html') != 'HTML') {
  125. $this->handleServiceDescriptionRequest();
  126. }
  127. else {
  128. $this->setHeader('content-type', 'Content-type: text/html; charset=utf-8');
  129. $this->result = $this->getHTMLFormDoc();
  130. }
  131. }
  132. /* */
  133. function handleServiceDescriptionRequest() {
  134. $q = '
  135. PREFIX void: <http://rdfs.org/ns/void#>
  136. CONSTRUCT {
  137. <> void:sparqlEndpoint <> .
  138. }
  139. WHERE {
  140. ?s ?p ?o .
  141. } LIMIT 1
  142. ';
  143. $this->handleQueryRequest($q);
  144. }
  145. /* */
  146. function checkProcesses() {
  147. if (method_exists($this->caller, 'checkSPARQLEndpointProcesses')) {
  148. $sub_r = $this->caller->checkSPARQLEndpointProcesses();
  149. }
  150. elseif ($this->timeout) {
  151. $this->killDBProcesses('', $this->timeout);
  152. }
  153. }
  154. /* */
  155. function handleQueryRequest($q) {
  156. if (preg_match('/^dump/i', $q)) {
  157. $infos = array('query' => array('type' => 'dump'));
  158. $this->is_dump = 1;
  159. }
  160. else {
  161. ARC2::inc('SPARQLPlusParser');
  162. $p = new ARC2_SPARQLPlusParser($this->a, $this);
  163. $p->parse($q);
  164. $infos = $p->getQueryInfos();
  165. }
  166. /* errors? */
  167. if ($errors = $this->getErrors()) {
  168. $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
  169. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  170. $this->result = htmlspecialchars(join("\n", $errors));
  171. return true;
  172. }
  173. $qt = $infos['query']['type'];
  174. /* wrong read key? */
  175. if ($this->read_key && ($this->p('key') != $this->read_key) && preg_match('/^(select|ask|construct|describe|dump)$/', $qt)) {
  176. $this->setHeader('http', 'HTTP/1.1 401 Access denied');
  177. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  178. $this->result = 'Access denied. Missing or wrong "key" parameter.';
  179. return true;
  180. }
  181. /* wrong write key? */
  182. if ($this->write_key && ($this->p('key') != $this->write_key) && preg_match('/^(load|insert|delete|update)$/', $qt)) {
  183. $this->setHeader('http', 'HTTP/1.1 401 Access denied');
  184. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  185. $this->result = 'Access denied. Missing or wrong "key" parameter.';
  186. return true;
  187. }
  188. /* non-allowed query type? */
  189. if (!in_array($qt, $this->getFeatures())) {
  190. $this->setHeader('http', 'HTTP/1.1 401 Access denied');
  191. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  192. $this->result = 'Access denied for "' .$qt. '" query';
  193. return true;
  194. }
  195. /* load/insert/delete via GET */
  196. if (in_array($qt, array('load', 'insert', 'delete')) && isset($_GET['query'])) {
  197. $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
  198. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  199. $this->result = 'Query type "' .$qt. '" not supported via GET';
  200. return true;
  201. }
  202. /* unsupported query type */
  203. if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
  204. $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
  205. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  206. $this->result = 'Unsupported query type "' .$qt. '"';
  207. return true;
  208. }
  209. /* adjust infos */
  210. $infos = $this->adjustQueryInfos($infos);
  211. $t1 = ARC2::mtime();
  212. $r = array('result' => $this->runQuery($infos, $qt));
  213. $t2 = ARC2::mtime();
  214. $r['query_time'] = $t2 - $t1;
  215. /* query errors? */
  216. if ($errors = $this->getErrors()) {
  217. $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
  218. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  219. $this->result = 'Error: ' . join("\n", $errors);
  220. return true;
  221. }
  222. /* result */
  223. $m = 'get' . ucfirst($qt) . 'ResultDoc';
  224. if (method_exists($this, $m)) {
  225. $this->result = $this->$m($r);
  226. }
  227. else {
  228. $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
  229. $this->result = 'Result serializer not available, dumping raw data:' . "\n" . print_r($r, 1);
  230. }
  231. }
  232. /* */
  233. function adjustQueryInfos($infos) {
  234. /* limit */
  235. if ($max_l = $this->v('endpoint_max_limit', 0, $this->a)) {
  236. if ($this->v('limit', $max_l + 1, $infos['query']) > $max_l) {
  237. $infos['query']['limit'] = $max_l;
  238. }
  239. }
  240. /* default-graph-uri / named-graph-uri */
  241. $dgs = $this->p('default-graph-uri', '', 1);
  242. $ngs = $this->p('named-graph-uri', '', 1);
  243. if (count(array_merge($dgs, $ngs))) {
  244. $ds = array();
  245. foreach ($dgs as $g) {
  246. $ds[] = array('graph' => $this->calcURI($g), 'named' => 0);
  247. }
  248. foreach ($ngs as $g) {
  249. $ds[] = array('graph' => $this->calcURI($g), 'named' => 1);
  250. }
  251. $infos['query']['dataset'] = $ds;
  252. }
  253. /* infos result format */
  254. if (($this->p('format') == 'infos') || ($this->p('output') == 'infos')) {
  255. $infos['result_format'] = 'structure';
  256. }
  257. /* sql result format */
  258. if (($this->p('format') == 'sql') || ($this->p('output') == 'sql')) {
  259. $infos['result_format'] = 'sql';
  260. }
  261. return $infos;
  262. }
  263. /* */
  264. function getResultFormat($formats, $default) {
  265. $prefs = array();
  266. /* arg */
  267. if (($v = $this->p('format')) || ($v = $this->p('output'))) {
  268. $prefs[] = $v;
  269. }
  270. /* accept header */
  271. $vals = explode(',', $_SERVER['HTTP_ACCEPT']);
  272. if ($vals) {
  273. $o_vals = array();
  274. foreach ($vals as $val) {
  275. if (preg_match('/(rdf\+n3|x\-turtle|rdf\+xml|sparql\-results\+xml|sparql\-results\+json|json)/', $val, $m)) {
  276. $o_vals[$m[1]] = 1;
  277. if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
  278. $o_vals[$m[1]] = 1 * $sub_m[1];
  279. }
  280. }
  281. }
  282. arsort($o_vals);
  283. foreach ($o_vals as $val => $prio) {
  284. $prefs[] = $val;
  285. }
  286. }
  287. /* default */
  288. $prefs[] = $default;
  289. foreach ($prefs as $pref) {
  290. if (isset($formats[$pref])) {
  291. return $formats[$pref];
  292. }
  293. }
  294. }
  295. /* SELECT */
  296. function getSelectResultDoc($r) {
  297. $formats = array(
  298. 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
  299. 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
  300. 'php_ser' => 'PHPSER', 'plain' => 'Plain',
  301. 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
  302. 'infos' => 'Plain',
  303. 'htmltab' => 'HTMLTable',
  304. 'tsv' => 'TSV',
  305. );
  306. if ($f = $this->getResultFormat($formats, 'xml')) {
  307. $m = 'get' . $f . 'SelectResultDoc';
  308. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  309. }
  310. return '';
  311. }
  312. function getSPARQLXMLSelectResultDoc($r) {
  313. $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
  314. $vars = $r['result']['variables'];
  315. $rows = $r['result']['rows'];
  316. $dur = $r['query_time'];
  317. $nl = "\n";
  318. /* doc */
  319. $r = '' .
  320. '<?xml version="1.0"?>' .
  321. $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
  322. '';
  323. /* head */
  324. $r .= $nl . ' <head>';
  325. $r .= $nl . ' <!-- query time: '. round($dur, 4) .' sec -->';
  326. if (is_array($vars)) {
  327. foreach ($vars as $var) {
  328. $r .= $nl . ' <variable name="' .$var. '"/>';
  329. }
  330. }
  331. $r .= $nl . ' </head>';
  332. /* results */
  333. $r .= $nl . ' <results>';
  334. if (is_array($rows)) {
  335. foreach ($rows as $row) {
  336. $r .= $nl . ' <result>';
  337. foreach ($vars as $var) {
  338. if (isset($row[$var])) {
  339. $r .= $nl . ' <binding name="' .$var. '">';
  340. if ($row[$var . ' type'] == 'uri') {
  341. $r .= $nl . ' <uri>' .htmlspecialchars($row[$var]). '</uri>';
  342. }
  343. elseif ($row[$var . ' type'] == 'bnode') {
  344. $r .= $nl . ' <bnode>' .substr($row[$var], 2). '</bnode>';
  345. }
  346. else {
  347. $dt = isset($row[$var . ' datatype']) ? ' datatype="' .htmlspecialchars($row[$var . ' datatype']). '"' : '';
  348. $lang = isset($row[$var . ' lang']) ? ' xml:lang="' .htmlspecialchars($row[$var . ' lang']). '"' : '';
  349. $r .= $nl . ' <literal' . $dt . $lang . '>' .htmlspecialchars($row[$var]). '</literal>';
  350. }
  351. $r .= $nl . ' </binding>';
  352. }
  353. }
  354. $r .= $nl . ' </result>';
  355. }
  356. }
  357. $r .= $nl . ' </results>';
  358. /* /doc */
  359. $r .= $nl . '</sparql>';
  360. return $r;
  361. }
  362. function getSPARQLJSONSelectResultDoc($r) {
  363. $con = $this->getDBCon();
  364. $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
  365. $vars = $r['result']['variables'];
  366. $rows = $r['result']['rows'];
  367. $dur = $r['query_time'];
  368. $nl = "\n";
  369. /* doc */
  370. $r = '{';
  371. /* head */
  372. $r .= $nl . ' "head": {';
  373. $r .= $nl . ' "vars": [';
  374. $first_var = 1;
  375. foreach ($vars as $var) {
  376. $r .= $first_var ? $nl : ',' . $nl;
  377. $r .= ' "' .$var. '"';
  378. $first_var = 0;
  379. }
  380. $r .= $nl . ' ]';
  381. $r .= $nl . ' },';
  382. /* results */
  383. $r .= $nl . ' "results": {';
  384. $r .= $nl . ' "bindings": [';
  385. $first_row = 1;
  386. foreach ($rows as $row) {
  387. $r .= $first_row ? $nl : ',' . $nl;
  388. $r .= ' {';
  389. $first_var = 1;
  390. foreach ($vars as $var) {
  391. if (isset($row[$var])) {
  392. $r .= $first_var ? $nl : ',' . $nl . $nl;
  393. $r .= ' "' .$var. '": {';
  394. if ($row[$var . ' type'] == 'uri') {
  395. $r .= $nl . ' "type": "uri",';
  396. $r .= $nl . ' "value": "' .mysql_real_escape_string($row[$var], $con). '"';
  397. }
  398. elseif ($row[$var . ' type'] == 'bnode') {
  399. $r .= $nl . ' "type": "bnode",';
  400. $r .= $nl . ' "value": "' . substr($row[$var], 2) . '"';
  401. }
  402. else {
  403. $dt = isset($row[$var . ' datatype']) ? ',' . $nl .' "datatype": "' .mysql_real_escape_string($row[$var . ' datatype'], $con). '"' : '';
  404. $lang = isset($row[$var . ' lang']) ? ',' . $nl .' "xml:lang": "' .mysql_real_escape_string($row[$var . ' lang'], $con). '"' : '';
  405. $type = $dt ? 'typed-literal' : 'literal';
  406. $r .= $nl . ' "type": "' . $type . '",';
  407. $r .= $nl . ' "value": "' . $this->jsonEscape($row[$var]) . '"';
  408. $r .= $dt . $lang;
  409. }
  410. $r .= $nl . ' }';
  411. $first_var = 0;
  412. }
  413. }
  414. $r .= $nl . ' }';
  415. $first_row = 0;
  416. }
  417. $r .= $nl . ' ]';
  418. $r .= $nl . ' }';
  419. /* /doc */
  420. $r .= $nl . '}';
  421. if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
  422. $r = $v . '(' . $r . ')';
  423. }
  424. return $r;
  425. }
  426. function getPHPSERSelectResultDoc($r) {
  427. $this->setHeader('content-type', 'Content-Type: text/plain');
  428. return serialize($r);
  429. }
  430. function getPlainSelectResultDoc($r) {
  431. $this->setHeader('content-type', 'Content-Type: text/plain');
  432. return print_r($r['result'], 1);
  433. }
  434. function getHTMLTableSelectResultDoc($r) {
  435. $this->setHeader('content-type', 'Content-Type: text/html; charset=utf-8');
  436. $vars = $r['result']['variables'];
  437. $rows = $r['result']['rows'];
  438. $dur = $r['query_time'];
  439. if ($this->p('show_inline')) return '<table>' . $this->getHTMLTableRows($rows, $vars) . '</table>';
  440. return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  441. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  442. ' .$this->getHTMLDocHead() . '
  443. <body>
  444. <table>
  445. ' . $this->getHTMLTableRows($rows, $vars) . '
  446. </table>
  447. </body>
  448. </html>
  449. ';
  450. }
  451. function getHTMLTableRows($rows, $vars) {
  452. $r = '';
  453. foreach ($rows as $row) {
  454. $hr = '';
  455. $rr = '';
  456. foreach ($vars as $var) {
  457. $hr .= $r ? '' : '<th>' . htmlspecialchars($var) . '</th>';
  458. $rr .= '<td>' . @htmlspecialchars($row[$var]) . '</td>';
  459. }
  460. $r .= $hr ? '<tr>' . $hr . '</tr>' : '';
  461. $r .= '<tr>' . $rr . '</tr>';
  462. }
  463. return $r ? $r : '<em>No results found</em>';
  464. }
  465. function getTSVSelectResultDoc($r) {
  466. $this->setHeader('content-type', 'Content-Type: text/plain; charset=utf-8');
  467. $vars = $r['result']['variables'];
  468. $rows = $r['result']['rows'];
  469. $dur = $r['query_time'];
  470. return $this->getTSVRows($rows, $vars);
  471. }
  472. function getTSVRows($rows, $vars) {
  473. $r = '';
  474. $delim = "\t";
  475. $esc_delim = "\\t";
  476. foreach ($rows as $row) {
  477. $hr = '';
  478. $rr = '';
  479. foreach ($vars as $var) {
  480. $hr .= $r ? '' : ($hr ? $delim . $var : $var);
  481. $val = isset($row[$var]) ? str_replace($delim, $esc_delim, $row[$var]) : '';
  482. $rr .= $rr ? $delim . $val : $val;
  483. }
  484. $r .= $hr . "\n" . $rr;
  485. }
  486. return $r ? $r : 'No results found';
  487. }
  488. /* ASK */
  489. function getAskResultDoc($r) {
  490. $formats = array(
  491. 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
  492. 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
  493. 'plain' => 'Plain',
  494. 'php_ser' => 'PHPSER',
  495. 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
  496. 'infos' => 'Plain',
  497. );
  498. if ($f = $this->getResultFormat($formats, 'xml')) {
  499. $m = 'get' . $f . 'AskResultDoc';
  500. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  501. }
  502. return '';
  503. }
  504. function getSPARQLXMLAskResultDoc($r) {
  505. $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
  506. $r_val = $r['result'] ? 'true' : 'false';
  507. $dur = $r['query_time'];
  508. $nl = "\n";
  509. return '' .
  510. '<?xml version="1.0"?>' .
  511. $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
  512. $nl . ' <head>' .
  513. $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
  514. $nl . ' </head>' .
  515. $nl . ' <boolean>' .$r_val. '</boolean>' .
  516. $nl . '</sparql>' .
  517. '';
  518. }
  519. function getSPARQLJSONAskResultDoc($r) {
  520. $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
  521. $r_val = $r['result'] ? 'true' : 'false';
  522. $dur = $r['query_time'];
  523. $nl = "\n";
  524. $r = '' .
  525. $nl . '{' .
  526. $nl . ' "head": {' .
  527. $nl . ' },' .
  528. $nl . ' "boolean" : ' . $r_val .
  529. $nl . '}' .
  530. '';
  531. if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
  532. $r = $v . '(' . $r . ')';
  533. }
  534. return $r;
  535. }
  536. function getPHPSERAskResultDoc($r) {
  537. $this->setHeader('content-type', 'Content-Type: text/plain');
  538. return serialize($r);
  539. }
  540. function getPlainAskResultDoc($r) {
  541. $this->setHeader('content-type', 'Content-Type: text/plain');
  542. return $r['result'] ? 'true' : 'false';
  543. }
  544. /* CONSTRUCT */
  545. function getConstructResultDoc($r) {
  546. $formats = array(
  547. 'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
  548. 'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
  549. 'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
  550. 'php_ser' => 'PHPSER',
  551. 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
  552. 'infos' => 'Plain',
  553. );
  554. if ($f = $this->getResultFormat($formats, 'rdfxml')) {
  555. $m = 'get' . $f . 'ConstructResultDoc';
  556. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  557. }
  558. return '';
  559. }
  560. function getRDFXMLConstructResultDoc($r) {
  561. $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
  562. $index = $r['result'];
  563. $ser = ARC2::getRDFXMLSerializer($this->a);
  564. $dur = $r['query_time'];
  565. return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
  566. }
  567. function getTurtleConstructResultDoc($r) {
  568. $this->setHeader('content-type', 'Content-Type: application/x-turtle');
  569. $index = $r['result'];
  570. $ser = ARC2::getTurtleSerializer($this->a);
  571. $dur = $r['query_time'];
  572. return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
  573. }
  574. function getRDFJSONConstructResultDoc($r) {
  575. $this->setHeader('content-type', 'Content-Type: application/json');
  576. $index = $r['result'];
  577. $ser = ARC2::getRDFJSONSerializer($this->a);
  578. $dur = $r['query_time'];
  579. $r = $ser->getSerializedIndex($index);
  580. if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
  581. $r = $v . '(' . $r . ')';
  582. }
  583. return $r;
  584. }
  585. function getPHPSERConstructResultDoc($r) {
  586. $this->setHeader('content-type', 'Content-Type: text/plain');
  587. return serialize($r);
  588. }
  589. function getPlainConstructResultDoc($r) {
  590. $this->setHeader('content-type', 'Content-Type: text/plain');
  591. return print_r($r['result'], 1);
  592. }
  593. /* DESCRIBE */
  594. function getDescribeResultDoc($r) {
  595. $formats = array(
  596. 'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
  597. 'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
  598. 'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
  599. 'php_ser' => 'PHPSER',
  600. 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
  601. 'infos' => 'Plain'
  602. );
  603. if ($f = $this->getResultFormat($formats, 'rdfxml')) {
  604. $m = 'get' . $f . 'DescribeResultDoc';
  605. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  606. }
  607. return '';
  608. }
  609. function getRDFXMLDescribeResultDoc($r) {
  610. $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
  611. $index = $r['result'];
  612. $ser = ARC2::getRDFXMLSerializer($this->a);
  613. $dur = $r['query_time'];
  614. return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
  615. }
  616. function getTurtleDescribeResultDoc($r) {
  617. $this->setHeader('content-type', 'Content-Type: application/x-turtle');
  618. $index = $r['result'];
  619. $ser = ARC2::getTurtleSerializer($this->a);
  620. $dur = $r['query_time'];
  621. return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
  622. }
  623. function getRDFJSONDescribeResultDoc($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 . ')';
  631. }
  632. return $r;
  633. }
  634. function getPHPSERDescribeResultDoc($r) {
  635. $this->setHeader('content-type', 'Content-Type: text/plain');
  636. return serialize($r);
  637. }
  638. function getPlainDescribeResultDoc($r) {
  639. $this->setHeader('content-type', 'Content-Type: text/plain');
  640. return print_r($r['result'], 1);
  641. }
  642. /* DUMP */
  643. function getDumpResultDoc() {
  644. $this->headers = array();
  645. return '';
  646. }
  647. /* LOAD */
  648. function getLoadResultDoc($r) {
  649. $formats = array(
  650. 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
  651. 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
  652. 'plain' => 'Plain',
  653. 'php_ser' => 'PHPSER',
  654. 'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
  655. 'infos' => 'Plain',
  656. );
  657. if ($f = $this->getResultFormat($formats, 'xml')) {
  658. $m = 'get' . $f . 'LoadResultDoc';
  659. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  660. }
  661. return '';
  662. }
  663. function getSPARQLXMLLoadResultDoc($r) {
  664. $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
  665. $r_val = $r['result']['t_count'];
  666. $dur = $r['query_time'];
  667. $nl = "\n";
  668. return '' .
  669. '<?xml version="1.0"?>' .
  670. $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
  671. $nl . ' <head>' .
  672. $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
  673. $nl . ' </head>' .
  674. $nl . ' <inserted>' .$r_val. '</inserted>' .
  675. $nl . '</sparql>' .
  676. '';
  677. }
  678. function getSPARQLJSONLoadResultDoc($r) {
  679. $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
  680. $r_val = $r['result']['t_count'];
  681. $dur = $r['query_time'];
  682. $nl = "\n";
  683. $r = '' .
  684. $nl . '{' .
  685. $nl . ' "head": {' .
  686. $nl . ' },' .
  687. $nl . ' "inserted" : ' . $r_val .
  688. $nl . '}' .
  689. '';
  690. if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
  691. $r = $v . '(' . $r . ')';
  692. }
  693. return $r;
  694. }
  695. function getPHPSERLoadResultDoc($r) {
  696. $this->setHeader('content-type', 'Content-Type: text/plain');
  697. return serialize($r);
  698. }
  699. function getPlainLoadResultDoc($r) {
  700. $this->setHeader('content-type', 'Content-Type: text/plain');
  701. return print_r($r['result'], 1);
  702. }
  703. /* DELETE */
  704. function getDeleteResultDoc($r) {
  705. $formats = array(
  706. 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
  707. 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
  708. 'plain' => 'Plain',
  709. 'php_ser' => 'PHPSER'
  710. );
  711. if ($f = $this->getResultFormat($formats, 'xml')) {
  712. $m = 'get' . $f . 'DeleteResultDoc';
  713. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  714. }
  715. return '';
  716. }
  717. function getSPARQLXMLDeleteResultDoc($r) {
  718. $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
  719. $r_val = $r['result']['t_count'];
  720. $dur = $r['query_time'];
  721. $nl = "\n";
  722. return '' .
  723. '<?xml version="1.0"?>' .
  724. $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
  725. $nl . ' <head>' .
  726. $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
  727. $nl . ' </head>' .
  728. $nl . ' <deleted>' .$r_val. '</deleted>' .
  729. $nl . '</sparql>' .
  730. '';
  731. }
  732. function getSPARQLJSONDeleteResultDoc($r) {
  733. $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
  734. $r_val = $r['result']['t_count'];
  735. $dur = $r['query_time'];
  736. $nl = "\n";
  737. $r = '' .
  738. $nl . '{' .
  739. $nl . ' "head": {' .
  740. $nl . ' },' .
  741. $nl . ' "deleted" : ' . $r_val .
  742. $nl . '}' .
  743. '';
  744. if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
  745. $r = $v . '(' . $r . ')';
  746. }
  747. return $r;
  748. }
  749. function getPHPSERDeleteResultDoc($r) {
  750. $this->setHeader('content-type', 'Content-Type: text/plain');
  751. return serialize($r);
  752. }
  753. function getPlainDeleteResultDoc($r) {
  754. $this->setHeader('content-type', 'Content-Type: text/plain');
  755. return print_r($r['result'], 1);
  756. }
  757. /* INSERT */
  758. function getInsertResultDoc($r) {
  759. $formats = array(
  760. 'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
  761. 'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
  762. 'plain' => 'Plain',
  763. 'php_ser' => 'PHPSER'
  764. );
  765. if ($f = $this->getResultFormat($formats, 'xml')) {
  766. $m = 'get' . $f . 'InsertResultDoc';
  767. return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
  768. }
  769. return '';
  770. }
  771. function getSPARQLXMLInsertResultDoc($r) {
  772. $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
  773. $r_val = $r['result']['t_count'];
  774. $dur = $r['query_time'];
  775. $nl = "\n";
  776. return '' .
  777. '<?xml version="1.0"?>' .
  778. $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
  779. $nl . ' <head>' .
  780. $nl . ' <!-- query time: '. round($dur, 4) .' sec -->' .
  781. $nl . ' </head>' .
  782. $nl . ' <inserted>' .$r_val. '</inserted>' .
  783. $nl . '</sparql>' .
  784. '';
  785. }
  786. function getSPARQLJSONInsertResultDoc($r) {
  787. $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
  788. $r_val = $r['result']['t_count'];
  789. $dur = $r['query_time'];
  790. $nl = "\n";
  791. $r = '' .
  792. $nl . '{' .
  793. $nl . ' "head": {' .
  794. $nl . ' },' .
  795. $nl . ' "inserted" : ' . $r_val .
  796. $nl . '}' .
  797. '';
  798. if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
  799. $r = $v . '(' . $r . ')';
  800. }
  801. return $r;
  802. }
  803. function getPHPSERInsertResultDoc($r) {
  804. $this->setHeader('content-type', 'Content-Type: text/plain');
  805. return serialize($r);
  806. }
  807. function getPlainInsertResultDoc($r) {
  808. $this->setHeader('content-type', 'Content-Type: text/plain');
  809. return print_r($r['result'], 1);
  810. }
  811. /* */
  812. function jsonEscape($v) {
  813. if (function_exists('json_encode')) return trim(json_encode($v), '"');
  814. $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
  815. $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
  816. return str_replace($from, $to, $v);
  817. }
  818. /* */
  819. function getHTMLFormDoc() {
  820. return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  821. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  822. ' . $this->getHTMLDocHead() . '
  823. ' . $this->getHTMLDocBody() . '
  824. </html>
  825. ';
  826. }
  827. function getHTMLDocHead($params=array()) {
  828. return '
  829. <head>
  830. <title>' . $this->getHTMLDocTitle() . '</title>
  831. <style type="text/css">
  832. ' . $this->getHTMLDocCSS() . '
  833. </style>
  834. </head>
  835. ';
  836. }
  837. function getHTMLDocTitle() {
  838. return $this->v('endpoint_title', $_SESSION["CFGTitulo"].' SPARQL+ Endpoint', $this->a);
  839. }
  840. function getHTMLDocHeading() {
  841. return $this->v('endpoint_heading', '<a href="'.$_SESSION["CFGURL"].'" title="'.$_SESSION["CFGTitulo"].'">'.$_SESSION["CFGTitulo"].'</a>: SPARQL+ Endpoint', $this->a);
  842. }
  843. function getHTMLDocCSS() {
  844. $default = '
  845. body {
  846. font-size: 14px;
  847. font-family: Trebuchet MS, Verdana, Geneva, sans-serif;
  848. background: #fff url(?img=bg_body) top center repeat-x;
  849. padding: 5px 20px 20px 20px;
  850. color: #666;
  851. }
  852. h1 { font-size: 1.6em; font-weight: normal; }
  853. a { color: #c00000; }
  854. th, td {
  855. border: 1px dotted #eee;
  856. padding: 2px 4px;
  857. }
  858. #sparql-form {
  859. margin-bottom: 30px;
  860. }
  861. #query {
  862. float: left;
  863. width: 60%;
  864. display: block;
  865. height: 265px;
  866. margin-bottom: 10px;
  867. }
  868. .options {
  869. float: right;
  870. font-size: 0.9em;
  871. width: 35%;
  872. border-top: 1px solid #ccc;
  873. }
  874. .options h3 {
  875. margin: 5px;
  876. }
  877. .options dl{
  878. margin: 0px;
  879. padding: 0px 10px 5px 20px;
  880. }
  881. .options dl dt {
  882. border-top: 1px dotted #ddd;
  883. padding-top: 10px;
  884. }
  885. .options dl dt.first {
  886. border: none;
  887. }
  888. .options dl dd {
  889. padding: 5px 0px 7px 0px;
  890. }
  891. .options-2 {
  892. clear: both;
  893. margin: 10px 0px;
  894. }
  895. .form-buttons {
  896. }
  897. .results {
  898. border: 1px solid #eee;
  899. padding: 5px;
  900. background-color: #fcfcfc;
  901. }
  902. ';
  903. return $this->v('endpoint_css', $default, $this->a);
  904. }
  905. function getHTMLDocBody() {
  906. //DAF DATE of last update endpoint
  907. $ARRAYlastUpdateEndpoint=fetchlastUpdateEndpoint();
  908. return '
  909. <body>
  910. <h1>' . $this->getHTMLDocHeading() . '</h1>
  911. <div class="intro">
  912. <p>
  913. <a href="?">This interface</a> implements
  914. <a href="http://www.w3.org/TR/rdf-sparql-query/">SPARQL</a> and
  915. <a href="https://github.com/semsol/arc2/wiki/SPARQL%2B">SPARQL+</a> via <a href="http://www.w3.org/TR/rdf-sparql-protocol/#query-bindings-http">HTTP Bindings</a>.
  916. </p>
  917. <p>
  918. Enabled operations: ' . join(', ', $this->getFeatures()) . '
  919. </p>
  920. <p>
  921. '.MSG__dateUpdatedEndpoint.': '.$ARRAYlastUpdateEndpoint["value"].'
  922. </p>
  923. <p>
  924. Max. number of results : ' . $this->v('endpoint_max_limit', '<em>unrestricted</em>', $this->a) . '
  925. </p>
  926. </div>
  927. ' . $this->getHTMLDocForm() .'
  928. ' . ($this->p('show_inline') ? $this->query_result : '') . '
  929. </body>
  930. ';
  931. }
  932. function getHTMLDocForm() {
  933. $q = $this->p('query') ? htmlspecialchars($this->p('query')) : "PREFIX skos: <http://www.w3.org/2004/02/skos/core#> \n SELECT * WHERE {\n GRAPH ?g { ?s ?p ?o . }\n}\nLIMIT 10";
  934. return '
  935. <form id="sparql-form" action="?" enctype="application/x-www-form-urlencoded" method="post">
  936. <textarea id="query" name="query" rows="20" cols="80">' . $q . '</textarea>
  937. ' . $this->getHTMLDocOptions() . '
  938. <div class="form-buttons">
  939. <input type="submit" value="Send Query" />
  940. <input type="reset" value="Reset" />
  941. </div>
  942. </form>
  943. ';
  944. }
  945. function getHTMLDocOptions() {
  946. $sel = $this->p('output');
  947. $sel_code = ' selected="selected"';
  948. return '
  949. <div class="options">
  950. <h3>Options</h3>
  951. <dl>
  952. <dt class="first">Output format (if supported by query type):</dt>
  953. <dd>
  954. <select id="output" name="output">
  955. <option value="" ' . (!$sel ? $sel_code : '') . '>default</option>
  956. <option value="xml" ' . ($sel == 'xml' ? $sel_code : '') . '>XML</option>
  957. <option value="json" ' . ($sel == 'json' ? $sel_code : '') . '>JSON</option>
  958. <option value="plain" ' . ($sel == 'plain' ? $sel_code : '') . '>Plain</option>
  959. <option value="php_ser" ' . ($sel == 'php_ser' ? $sel_code : '') . '>Serialized PHP</option>
  960. <option value="turtle" ' . ($sel == 'turtle' ? $sel_code : '') . '>Turtle</option>
  961. <option value="rdfxml" ' . ($sel == 'rdfxml' ? $sel_code : '') . '>RDF/XML</option>
  962. <option value="infos" ' . ($sel == 'infos' ? $sel_code : '') . '>Query Structure</option>
  963. ' . ($this->allow_sql ? '<option value="sql" ' . ($sel == 'sql' ? $sel_code : '') . '>SQL</option>' : '') . '
  964. <option value="htmltab" ' . ($sel == 'htmltab' ? $sel_code : '') . '>HTML Table</option>
  965. <option value="tsv" ' . ($sel == 'tsv' ? $sel_code : '') . '>TSV</option>
  966. </select>
  967. </dd>
  968. <dt>jsonp/callback (for JSON results)</dt>
  969. <dd>
  970. <input type="text" id="jsonp" name="jsonp" value="' . htmlspecialchars($this->p('jsonp')) . '" />
  971. </dd>
  972. <dt><label for="show_inline">Show results inline</label>: </dt>
  973. <dd>
  974. <input type="checkbox" id="show_inline" name="show_inline" value="1" ' . ($this->p('show_inline') ? ' checked="checked"' : '') . ' />
  975. </dd>
  976. </dl>
  977. </div>
  978. <div class="options-2">
  979. Change HTTP method:
  980. <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'get\'">GET</a>
  981. <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'post\'">POST</a>
  982. </div>
  983. ';
  984. }
  985. /* */
  986. }