PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/store/ARC2_RemoteStoreEndpoint.php

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