PageRenderTime 77ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/arc/store/ARC2_StoreEndpoint.php

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