PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/elgg/mod/foafssl/arc/store/ARC2_StoreEndpoint.php

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