PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/DemiBlog/lib/arc/store/ARC2_StoreEndpoint.php

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