PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/arc2/ARC2_Class.php

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