PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/common/arc2/ARC2_Class.php

https://github.com/tematres/TemaTres-Vocabulary-Server
PHP | 536 lines | 435 code | 59 blank | 42 comment | 90 complexity | 286f9962d9710872fa9260108e8c1dce MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-3.0
  1. <?php
  2. /**
  3. * ARC2 base class
  4. *
  5. * @author Benjamin Nowack
  6. * @license <http://arc.semsol.org/license>
  7. * @homepage <http://arc.semsol.org/>
  8. * @package ARC2
  9. */
  10. class ARC2_Class {
  11. function __construct($a, &$caller) {
  12. $this->a = is_array($a) ? $a : array();
  13. $this->caller = $caller;
  14. $this->__init();
  15. }
  16. function __init() {/* base, time_limit */
  17. if (!$_POST && isset($GLOBALS['HTTP_RAW_POST_DATA'])) parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $_POST); /* php5 bug */
  18. $this->inc_path = ARC2::getIncPath();
  19. $this->ns_count = 0;
  20. $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  21. $this->nsp = array($rdf => 'rdf');
  22. $this->used_ns = array($rdf);
  23. $this->ns = array_merge(array('rdf' => $rdf), $this->v('ns', array(), $this->a));
  24. $this->base = $this->v('base', ARC2::getRequestURI(), $this->a);
  25. $this->errors = array();
  26. $this->warnings = array();
  27. $this->adjust_utf8 = $this->v('adjust_utf8', 0, $this->a);
  28. $this->max_errors = $this->v('max_errors', 25, $this->a);
  29. $this->has_pcre_unicode = @preg_match('/\pL/u', 'test');/* \pL = block/point which is a Letter */
  30. }
  31. /* */
  32. function v($name, $default = false, $o = false) {/* value if set */
  33. if ($o === false) $o = $this;
  34. if (is_array($o)) {
  35. return isset($o[$name]) ? $o[$name] : $default;
  36. }
  37. return isset($o->$name) ? $o->$name : $default;
  38. }
  39. function v1($name, $default = false, $o = false) {/* value if 1 (= not empty) */
  40. if ($o === false) $o = $this;
  41. if (is_array($o)) {
  42. return (isset($o[$name]) && $o[$name]) ? $o[$name] : $default;
  43. }
  44. return (isset($o->$name) && $o->$name) ? $o->$name : $default;
  45. }
  46. function m($name, $a = false, $default = false, $o = false) {/* call method */
  47. if ($o === false) $o = $this;
  48. return method_exists($o, $name) ? $o->$name($a) : $default;
  49. }
  50. /* */
  51. function camelCase($v, $lc_first = 0, $keep_boundaries = 0) {
  52. $r = ucfirst($v);
  53. while (preg_match('/^(.*)[^a-z0-9](.*)$/si', $r, $m)) {
  54. /* don't fuse 2 upper-case chars */
  55. if ($keep_boundaries && $m[1]) {
  56. $boundary = substr($m[1], -1);
  57. if (strtoupper($boundary) == $boundary) $m[1] .= 'CAMELCASEBOUNDARY';
  58. }
  59. $r = $m[1] . ucfirst($m[2]);
  60. }
  61. $r = str_replace('CAMELCASEBOUNDARY', '_', $r);
  62. if ((strlen($r) > 1) && $lc_first && !preg_match('/[A-Z]/', $r[1])) $r = strtolower($r[0]) . substr($r, 1);
  63. return $r;
  64. }
  65. function deCamelCase($v, $uc_first = 0) {
  66. $r = str_replace('_', ' ', $v);
  67. $r = preg_replace_callback('/([a-z0-9])([A-Z])/', function($matches) {
  68. return $matches[1] . ' ' . strtolower($matches[2]);
  69. }, $r);
  70. return $uc_first ? ucfirst($r) : $r;
  71. }
  72. /**
  73. * Tries to extract a somewhat human-readable label from a URI.
  74. */
  75. function extractTermLabel($uri, $loops = 0) {
  76. list($ns, $r) = $this->splitURI($uri);
  77. /* encode apostrophe + s */
  78. $r = str_replace('%27s', '_apostrophes_', $r);
  79. /* normalize */
  80. $r = $this->deCamelCase($this->camelCase($r, 1, 1));
  81. /* decode apostrophe + s */
  82. $r = str_replace(' apostrophes ', "'s ", $r);
  83. /* typical RDF non-info URI */
  84. if (($loops < 1) && preg_match('/^(self|it|this|me|id)$/i', $r)) {
  85. return $this->extractTermLabel(preg_replace('/\#.+$/', '', $uri), $loops + 1);
  86. }
  87. /* trailing hash or slash */
  88. if ($uri && !$r && ($loops < 2)) {
  89. return $this->extractTermLabel(preg_replace('/[\#\/]$/', '', $uri), $loops + 1);
  90. }
  91. /* a de-camel-cased URL (will look like "www example com") */
  92. if (preg_match('/^www (.+ [a-z]{2,4})$/', $r, $m)) {
  93. return $this->getPrettyURL($uri);
  94. }
  95. return $r;
  96. }
  97. /**
  98. * Generates a less ugly in-your-face URL.
  99. */
  100. function getPrettyURL($r) {
  101. $r = rtrim($r, '/');
  102. $r = preg_replace('/^https?\:\/\/(www\.)?/', '', $r);
  103. return $r;
  104. }
  105. /* */
  106. function addError($v) {
  107. if (!in_array($v, $this->errors)) {
  108. $this->errors[] = $v;
  109. }
  110. if ($this->caller && method_exists($this->caller, 'addError')) {
  111. $glue = strpos($v, ' in ') ? ' via ' : ' in ';
  112. $this->caller->addError($v . $glue . get_class($this));
  113. }
  114. if (count($this->errors) > $this->max_errors) {
  115. die('Too many errors (limit: ' . $this->max_errors . '): ' . print_r($this->errors, 1));
  116. }
  117. return false;
  118. }
  119. function getErrors() {
  120. return $this->errors;
  121. }
  122. function getWarnings() {
  123. return $this->warnings;
  124. }
  125. function resetErrors() {
  126. $this->errors = array();
  127. if ($this->caller && method_exists($this->caller, 'resetErrors')) {
  128. $this->caller->resetErrors();
  129. }
  130. }
  131. /* */
  132. function splitURI($v) {
  133. return ARC2::splitURI($v);
  134. }
  135. /* */
  136. function getPName($v, $connector = ':') {
  137. /* is already a pname */
  138. $ns = $this->getPNameNamespace($v, $connector);
  139. if ($ns) {
  140. if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
  141. return $v;
  142. }
  143. /* new pname */
  144. $parts = $this->splitURI($v);
  145. if ($parts) {
  146. /* known prefix */
  147. foreach ($this->ns as $prefix => $ns) {
  148. if ($parts[0] == $ns) {
  149. if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
  150. return $prefix . $connector . $parts[1];
  151. }
  152. }
  153. /* new prefix */
  154. $prefix = $this->getPrefix($parts[0]);
  155. return $prefix . $connector . $parts[1];
  156. }
  157. return $v;
  158. }
  159. function getPNameNamespace($v, $connector = ':') {
  160. $re = '/^([a-z0-9\_\-]+)\:([a-z0-9\_\-\.\%]+)$/i';
  161. if ($connector != ':') {
  162. $connectors = array('\:', '\-', '\_', '\.');
  163. $chars = join('', array_diff($connectors, array($connector)));
  164. $re = '/^([a-z0-9' . $chars . ']+)\\' . $connector . '([a-z0-9\_\-\.\%]+)$/i';
  165. }
  166. if (!preg_match($re, $v, $m)) return 0;
  167. if (!isset($this->ns[$m[1]])) return 0;
  168. return $this->ns[$m[1]];
  169. }
  170. function setPrefix($prefix, $ns) {
  171. $this->ns[$prefix] = $ns;
  172. $this->nsp[$ns] = $prefix;
  173. return $this;
  174. }
  175. function getPrefix($ns) {
  176. if (!isset($this->nsp[$ns])) {
  177. $this->ns['ns' . $this->ns_count] = $ns;
  178. $this->nsp[$ns] = 'ns' . $this->ns_count;
  179. $this->ns_count++;
  180. }
  181. if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
  182. return $this->nsp[$ns];
  183. }
  184. function expandPName($v, $connector = ':') {
  185. $re = '/^([a-z0-9\_\-]+)\:([a-z0-9\_\-\.\%]+)$/i';
  186. if ($connector != ':') {
  187. $connectors = array(':', '-', '_', '.');
  188. $chars = '\\' . join('\\', array_diff($connectors, array($connector)));
  189. $re = '/^([a-z0-9' . $chars . ']+)\\' . $connector . '([a-z0-9\_\-\.\%]+)$/Ui';
  190. }
  191. if (preg_match($re, $v, $m) && isset($this->ns[$m[1]])) {
  192. return $this->ns[$m[1]] . $m[2];
  193. }
  194. return $v;
  195. }
  196. function expandPNames($index) {
  197. $r = array();
  198. foreach ($index as $s => $ps) {
  199. $s = $this->expandPName($s);
  200. $r[$s] = array();
  201. foreach ($ps as $p => $os) {
  202. $p = $this->expandPName($p);
  203. if (!is_array($os)) $os = array($os);
  204. foreach ($os as $i => $o) {
  205. if (!is_array($o)) {
  206. $o_val = $this->expandPName($o);
  207. $o_type = preg_match('/^[a-z]+\:[^\s\<\>]+$/si', $o_val) ? 'uri' : 'literal';
  208. $o = array('value' => $o_val, 'type' => $o_type);
  209. }
  210. $os[$i] = $o;
  211. }
  212. $r[$s][$p] = $os;
  213. }
  214. }
  215. return $r;
  216. }
  217. /* */
  218. function calcURI($path, $base = "") {
  219. /* quick check */
  220. if (preg_match("/^[a-z0-9\_]+\:/i", $path)) {/* abs path or bnode */
  221. return $path;
  222. }
  223. if (preg_match('/^\$\{.*\}/', $path)) {/* placeholder, assume abs URI */
  224. return $path;
  225. }
  226. if (preg_match("/^\/\//", $path)) {/* net path, assume http */
  227. return 'http:' . $path;
  228. }
  229. /* other URIs */
  230. $base = $base ? $base : $this->base;
  231. $base = preg_replace('/\#.*$/', '', $base);
  232. if ($path === true) {/* empty (but valid) URIref via turtle parser: <> */
  233. return $base;
  234. }
  235. $path = preg_replace("/^\.\//", '', $path);
  236. $root = preg_match('/(^[a-z0-9]+\:[\/]{1,3}[^\/]+)[\/|$]/i', $base, $m) ? $m[1] : $base; /* w/o trailing slash */
  237. $base .= ($base == $root) ? '/' : '';
  238. if (preg_match('/^\//', $path)) {/* leading slash */
  239. return $root . $path;
  240. }
  241. if (!$path) {
  242. return $base;
  243. }
  244. if (preg_match('/^([\#\?])/', $path, $m)) {
  245. return preg_replace('/\\' .$m[1]. '.*$/', '', $base) . $path;
  246. }
  247. if (preg_match('/^(\&)(.*)$/', $path, $m)) {/* not perfect yet */
  248. return preg_match('/\?/', $base) ? $base . $m[1] . $m[2] : $base . '?' . $m[2];
  249. }
  250. if (preg_match("/^[a-z0-9]+\:/i", $path)) {/* abs path */
  251. return $path;
  252. }
  253. /* rel path: remove stuff after last slash */
  254. $base = substr($base, 0, strrpos($base, '/')+1);
  255. /* resolve ../ */
  256. while (preg_match('/^(\.\.\/)(.*)$/', $path, $m)) {
  257. $path = $m[2];
  258. $base = ($base == $root.'/') ? $base : preg_replace('/^(.*\/)[^\/]+\/$/', '\\1', $base);
  259. }
  260. return $base . $path;
  261. }
  262. /* */
  263. function calcBase($path) {
  264. $r = $path;
  265. $r = preg_replace('/\#.*$/', '', $r);/* remove hash */
  266. $r = preg_replace('/^\/\//', 'http://', $r);/* net path (//), assume http */
  267. if (preg_match('/^[a-z0-9]+\:/', $r)) {/* scheme, abs path */
  268. while (preg_match('/^(.+\/)(\.\.\/.*)$/U', $r, $m)) {
  269. $r = $this->calcURI($m[1], $m[2]);
  270. }
  271. return $r;
  272. }
  273. return 'file://' . realpath($r);/* real path */
  274. }
  275. /* */
  276. function getResource($uri, $store_or_props = '') {
  277. $res = ARC2::getResource($this->a);
  278. $res->setURI($uri);
  279. if (is_array($store_or_props)) {
  280. $res->setProps($store_or_props);
  281. }
  282. else {
  283. $res->setStore($store_or_props);
  284. }
  285. return $res;
  286. }
  287. function toIndex($v) {
  288. if (is_array($v)) {
  289. if (isset($v[0]) && isset($v[0]['s'])) return ARC2::getSimpleIndex($v, 0);
  290. return $v;
  291. }
  292. $parser = ARC2::getRDFParser($this->a);
  293. if ($v && !preg_match('/\s/', $v)) {/* assume graph URI */
  294. $parser->parse($v);
  295. }
  296. else {
  297. $parser->parse('', $v);
  298. }
  299. return $parser->getSimpleIndex(0);
  300. }
  301. function toTriples($v) {
  302. if (is_array($v)) {
  303. if (isset($v[0]) && isset($v[0]['s'])) return $v;
  304. return ARC2::getTriplesFromIndex($v);
  305. }
  306. $parser = ARC2::getRDFParser($this->a);
  307. if ($v && !preg_match('/\s/', $v)) {/* assume graph URI */
  308. $parser->parse($v);
  309. }
  310. else {
  311. $parser->parse('', $v);
  312. }
  313. return $parser->getTriples();
  314. }
  315. /* */
  316. function toNTriples($v, $ns = '', $raw = 0) {
  317. ARC2::inc('NTriplesSerializer');
  318. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  319. $ser = new ARC2_NTriplesSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  320. return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
  321. }
  322. function toTurtle($v, $ns = '', $raw = 0) {
  323. ARC2::inc('TurtleSerializer');
  324. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  325. $ser = new ARC2_TurtleSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  326. return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
  327. }
  328. function toRDFXML($v, $ns = '', $raw = 0) {
  329. ARC2::inc('RDFXMLSerializer');
  330. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  331. $ser = new ARC2_RDFXMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  332. return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
  333. }
  334. function toRDFJSON($v, $ns = '') {
  335. ARC2::inc('RDFJSONSerializer');
  336. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  337. $ser = new ARC2_RDFJSONSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  338. return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
  339. }
  340. function toRSS10($v, $ns = '') {
  341. ARC2::inc('RSS10Serializer');
  342. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  343. $ser = new ARC2_RSS10Serializer(array_merge($this->a, array('ns' => $ns)), $this);
  344. return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
  345. }
  346. function toLegacyXML($v, $ns = '') {
  347. ARC2::inc('LegacyXMLSerializer');
  348. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  349. $ser = new ARC2_LegacyXMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  350. return $ser->getSerializedArray($v);
  351. }
  352. function toLegacyJSON($v, $ns = '') {
  353. ARC2::inc('LegacyJSONSerializer');
  354. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  355. $ser = new ARC2_LegacyJSONSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  356. return $ser->getSerializedArray($v);
  357. }
  358. function toLegacyHTML($v, $ns = '') {
  359. ARC2::inc('LegacyHTMLSerializer');
  360. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  361. $ser = new ARC2_LegacyHTMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
  362. return $ser->getSerializedArray($v);
  363. }
  364. function toHTML($v, $ns = '', $label_store = '') {
  365. ARC2::inc('MicroRDFSerializer');
  366. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  367. $conf = array_merge($this->a, array('ns' => $ns));
  368. if ($label_store) $conf['label_store'] = $label_store;
  369. $ser = new ARC2_MicroRDFSerializer($conf, $this);
  370. return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
  371. }
  372. /* */
  373. function getFilledTemplate($t, $vals, $g = '') {
  374. $parser = ARC2::getTurtleParser();
  375. $parser->parse($g, $this->getTurtleHead() . $t);
  376. return $parser->getSimpleIndex(0, $vals);
  377. }
  378. function getTurtleHead() {
  379. $r = '';
  380. $ns = $this->v('ns', array(), $this->a);
  381. foreach ($ns as $k => $v) {
  382. $r .= "@prefix " . $k . ": <" .$v. "> .\n";
  383. }
  384. return $r;
  385. }
  386. function completeQuery($q, $ns = '') {
  387. if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
  388. $added_prefixes = array();
  389. $prologue = '';
  390. foreach ($ns as $k => $v) {
  391. $k = rtrim($k, ':');
  392. if (in_array($k, $added_prefixes)) continue;
  393. if (preg_match('/(^|\s)' . $k . ':/s', $q) && !preg_match('/PREFIX\s+' . $k . '\:/is', $q)) {
  394. $prologue .= "\n" . 'PREFIX ' . $k . ': <' . $v . '>';
  395. }
  396. $added_prefixes[] = $k;
  397. }
  398. return $prologue . "\n" . $q;
  399. }
  400. /* */
  401. function toUTF8($str) {
  402. return $this->adjust_utf8 ? ARC2::toUTF8($str) : $str;
  403. }
  404. function toDataURI($str) {
  405. return 'data:text/plain;charset=utf-8,' . rawurlencode($str);
  406. }
  407. function fromDataURI($str) {
  408. return str_replace('data:text/plain;charset=utf-8,', '', rawurldecode($str));
  409. }
  410. /* prevent SQL injections via SPARQL REGEX */
  411. function checkRegex($str) {
  412. return addslashes($str); // @@todo extend
  413. }
  414. /* Microdata methods */
  415. function getMicrodataAttrs($id, $type = '') {
  416. $type = $type ? $this->expandPName($type) : $this->expandPName('owl:Thing');
  417. return 'itemscope="" itemtype="' . htmlspecialchars($type) . '" itemid="' . htmlspecialchars($id) . '"';
  418. }
  419. function mdAttrs($id, $type = '') {
  420. return $this->getMicrodataAttrs($id, $type);
  421. }
  422. /* central DB query hook */
  423. function queryDB($sql, $con, $log_errors = 0) {
  424. $t1 = ARC2::mtime();
  425. $r = mysqli_query( $con, $sql);
  426. if (0) {
  427. $t2 = ARC2::mtime() - $t1;
  428. $call_obj = $this;
  429. $call_path = '';
  430. while ($call_obj) {
  431. $call_path = get_class($call_obj) . ' / ' . $call_path;
  432. $call_obj = isset($call_obj->caller) ? $call_obj->caller : false;
  433. }
  434. echo "\n" . $call_path . " needed " . $t2 . ' secs for ' . str_replace("\n" , ' ', $sql);;
  435. }
  436. $er = mysqli_error($con);
  437. if ($log_errors && !empty($er)) $this->addError($er);
  438. return $r;
  439. }
  440. /**
  441. * Shortcut method to create an RDF/XML backup dump from an RDF Store object.
  442. */
  443. function backupStoreData($store, $target_path, $offset = 0) {
  444. $limit = 10;
  445. $q = '
  446. SELECT DISTINCT ?s WHERE {
  447. ?s ?p ?o .
  448. }
  449. ORDER BY ?s
  450. LIMIT ' . $limit . '
  451. ' . ($offset ? 'OFFSET ' . $offset : '') . '
  452. ';
  453. $rows = $store->query($q, 'rows');
  454. $tc = count($rows);
  455. $full_tc = $tc + $offset;
  456. $mode = $offset ? 'ab' : 'wb';
  457. $fp = fopen($target_path, $mode);
  458. foreach ($rows as $row) {
  459. $index = $store->query('DESCRIBE <' . $row['s'] . '>', 'raw');
  460. if ($index) {
  461. $doc = $this->toRDFXML($index);
  462. fwrite($fp, $doc . "\n\n");
  463. }
  464. }
  465. fclose($fp);
  466. if ($tc == 10) {
  467. set_time_limit(300);
  468. $this->backupStoreData($store, $target_path, $offset + $limit);
  469. }
  470. return $full_tc;
  471. }
  472. }