mdAttrs($s, $main_type) . '>
-
+
+ public function getSerializedIndex($index, $res = '')
+ {
+ $r = '';
+ $n = "\n";
+ if ($res) {
+ $index = [$res => $index[$res]];
+ }
+ //return Trice::dump($index);
+ $types = $this->v($this->expandPName('rdf:type'), [], $index);
+ $main_type = $types ? $types[0]['value'] : '';
+ foreach ($index as $s => $ps) {
+ /* node */
+ $r .= '
+
mdAttrs($s, $main_type).'>
+
';
- /* arcs */
- foreach ($ps as $p => $os) {
- $p_cls = strtolower($this->getPName($p));
- $p_cls = str_replace(':', '-', $p_cls);
- $r .= '
-
-
' . ucfirst($this->getLabel($p)) . ':
+ /* arcs */
+ foreach ($ps as $p => $os) {
+ $p_cls = strtolower($this->getPName($p));
+ $p_cls = str_replace(':', '-', $p_cls);
+ $r .= '
+
+
'.ucfirst($this->getLabel($p)).':
';
- $oc = count($os);
- foreach ($os as $i => $o) {
- $val = $this->getObjectValue($o, $p);
- $cls = '';
- if ($i == 0) $cls .= ($cls ? ' ' : '') . 'first';
- if ($i == $oc - 1) $cls .= ($cls ? ' ' : '') . 'last';
- $r .= $n . '- ' . $val . '
';
- }
- $r .= '
+ $oc = count($os);
+ foreach ($os as $i => $o) {
+ $val = $this->getObjectValue($o, $p);
+ $cls = '';
+ if (0 == $i) {
+ $cls .= ($cls ? ' ' : '').'first';
+ }
+ if ($i == $oc - 1) {
+ $cls .= ($cls ? ' ' : '').'last';
+ }
+ $r .= $n.'- '.$val.'
';
+ }
+ $r .= '
';
- }
- /* /node */
- $r .= '
+ }
+ /* /node */
+ $r .= '
';
+ }
+
+ return $r;
}
- return $r;
- }
-
- function getObjectValue($o, $p) {
- if ($o['type'] == 'uri') {
- if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
- return $this->getImageObjectValue($o, $p);
- }
- return $this->getURIObjectValue($o, $p);
- }
- if ($o['type'] == "bnode") {
- return $this->getBNodeObjectValue($o, $p);
+
+ public function getObjectValue($o, $p)
+ {
+ if ('uri' == $o['type']) {
+ if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
+ return $this->getImageObjectValue($o, $p);
+ }
+
+ return $this->getURIObjectValue($o, $p);
+ }
+ if ('bnode' == $o['type']) {
+ return $this->getBNodeObjectValue($o, $p);
+ }
+
+ return $this->getLiteralObjectValue($o, $p);
}
- return $this->getLiteralObjectValue($o, $p);
- }
-
- function getImageObjectValue($o, $p) {
- return '
';
- }
-
- function getURIObjectValue($o, $p) {
- $id = htmlspecialchars($o['value']);
- $label = $this->getObjectLabel($o['value']);
- /* differing href */
- $href = htmlspecialchars($this->v('href', $o['value'], $o));
- if ($id != $href) {
- return '
' . $label . '';
+
+ public function getImageObjectValue($o, $p)
+ {
+ return '
';
}
- return '
' . $label . '';
- //$label = $o['value'];
+
+ public function getURIObjectValue($o, $p)
+ {
+ $id = htmlspecialchars($o['value']);
+ $label = $this->getObjectLabel($o['value']);
+ /* differing href */
+ $href = htmlspecialchars($this->v('href', $o['value'], $o));
+ if ($id != $href) {
+ return '
'.$label.'';
+ }
+
+ return '
'.$label.'';
+ //$label = $o['value'];
//$label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
- }
+ }
- function getBNodeObjectValue($o, $p) {
- return '
' . $o['value'] . '
';
- return '
An unnamed resource
';
- }
+ public function getBNodeObjectValue($o, $p)
+ {
+ return '
'.$o['value'].'
';
- function getLiteralObjectValue($o, $p) {
- return '
' . $o['value'] . '
';
- }
+ return '
An unnamed resource
';
+ }
- /* */
+ public function getLiteralObjectValue($o, $p)
+ {
+ return '
'.$o['value'].'
';
+ }
- function getObjectLabel($id) {
- $r = $this->extractTermLabel($id);
- if (!$this->label_store) return $r;
- $q = '
+ public function getObjectLabel($id)
+ {
+ $r = $this->extractTermLabel($id);
+ if (!$this->label_store) {
+ return $r;
+ }
+ $q = '
SELECT ?val WHERE {
- <' . $id . '> ?p ?val .
+ <'.$id.'> ?p ?val .
FILTER(REGEX(str(?p), "(label|title|name|summary)$"))
} LIMIT 1
';
- $row = $this->label_store->query($q, 'row');
- return $row ? $row['val'] : $r;
- }
+ $row = $this->label_store->query($q, 'row');
- /* */
-
+ return $row ? $row['val'] : $r;
+ }
}
-
diff --git a/serializers/ARC2_NTriplesSerializer.php b/serializers/ARC2_NTriplesSerializer.php
index 7c80d31a..61e8b6ec 100644
--- a/serializers/ARC2_NTriplesSerializer.php
+++ b/serializers/ARC2_NTriplesSerializer.php
@@ -1,163 +1,172 @@
- * @package ARC2
-*/
-
+ */
ARC2::inc('RDFSerializer');
-class ARC2_NTriplesSerializer extends ARC2_RDFSerializer {
-
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- $this->esc_chars = array();
- $this->raw = 0;
- }
-
- /* */
-
- function getTerm($v, $term = '') {
- // type detection
- if (!is_array($v) || empty($v['type'])) {
- // bnode
- if (preg_match('/^\_\:/', $v)) {
- return $this->getTerm(array('value' => $v, 'type' => 'bnode'));
- }
- // uri
- if (preg_match('/^[a-z0-9]+\:[^\s\"]*$/is' . ($this->has_pcre_unicode ? 'u' : ''), $v)) {
- return $this->getTerm(array('value' => $v, 'type' => 'uri'));
- }
- // fallback for non-unicode environments: subjects and predicates can't be literals.
- if (in_array($term, array('s', 'p'))) {
- return $this->getTerm(array('value' => $v, 'type' => 'uri'));
- }
- // assume literal
- return $this->getTerm(array('type' => 'literal', 'value' => $v));
+class ARC2_NTriplesSerializer extends ARC2_RDFSerializer
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
}
- if ($v['type'] == 'bnode') {
- return $v['value'];
- }
- elseif ($v['type'] == 'uri') {
- return '<' . $this->escape($v['value']) . '>';
+
+ public function __init()
+ {
+ parent::__init();
+ $this->esc_chars = [];
+ $this->raw = 0;
}
- // something went wrong
- elseif ($v['type'] != 'literal') {
- return $this->getTerm($v['value']);
+
+ public function getTerm($v, $term = '')
+ {
+ // type detection
+ if (!is_array($v) || empty($v['type'])) {
+ // bnode
+ if (preg_match('/^\_\:/', $v)) {
+ return $this->getTerm(['value' => $v, 'type' => 'bnode']);
+ }
+ // uri
+ if (preg_match('/^[a-z0-9]+\:[^\s\"]*$/is'.($this->has_pcre_unicode ? 'u' : ''), $v)) {
+ return $this->getTerm(['value' => $v, 'type' => 'uri']);
+ }
+ // fallback for non-unicode environments: subjects and predicates can't be literals.
+ if (in_array($term, ['s', 'p'])) {
+ return $this->getTerm(['value' => $v, 'type' => 'uri']);
+ }
+ // assume literal
+ return $this->getTerm(['type' => 'literal', 'value' => $v]);
+ }
+ if ('bnode' == $v['type']) {
+ return $v['value'];
+ } elseif ('uri' == $v['type']) {
+ return '<'.$this->escape($v['value']).'>';
+ }
+ // something went wrong
+ elseif ('literal' != $v['type']) {
+ return $this->getTerm($v['value']);
+ }
+ /* literal */
+ $quot = '"';
+ if ($this->raw && preg_match('/\"/', $v['value'])) {
+ $quot = "'";
+ if (preg_match('/\'/', $v['value'])) {
+ $quot = '"""';
+ if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
+ $quot = "'''";
+ $v['value'] = preg_replace("/'$/", "' ", $v['value']);
+ $v['value'] = preg_replace("/^'/", " '", $v['value']);
+ $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+ }
+ }
+ }
+ if ($this->raw && (1 == strlen($quot)) && preg_match('/[\x0d\x0a]/', $v['value'])) {
+ $quot = $quot.$quot.$quot;
+ }
+ $suffix = isset($v['lang']) && $v['lang'] ? '@'.$v['lang'] : '';
+ $suffix = isset($v['datatype']) && $v['datatype'] ? '^^'.$this->getTerm($v['datatype']) : $suffix;
+ //return $quot . "object" . utf8_encode($v['value']) . $quot . $suffix;
+ return $quot.$this->escape($v['value']).$quot.$suffix;
}
- /* literal */
- $quot = '"';
- if ($this->raw && preg_match('/\"/', $v['value'])) {
- $quot = "'";
- if (preg_match('/\'/', $v['value'])) {
- $quot = '"""';
- if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
- $quot = "'''";
- $v['value'] = preg_replace("/'$/", "' ", $v['value']);
- $v['value'] = preg_replace("/^'/", " '", $v['value']);
- $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+
+ public function getSerializedIndex($index, $raw = 0)
+ {
+ $this->raw = $raw;
+ $r = '';
+ $nl = "\n";
+ foreach ($index as $s => $ps) {
+ $s = $this->getTerm($s, 's');
+ foreach ($ps as $p => $os) {
+ $p = $this->getTerm($p, 'p');
+ if (!is_array($os)) {/* single literal o */
+ $os = [['value' => $os, 'type' => 'literal']];
+ }
+ foreach ($os as $o) {
+ $o = $this->getTerm($o, 'o‚');
+ $r .= $r ? $nl : '';
+ $r .= $s.' '.$p.' '.$o.' .';
+ }
+ }
}
- }
+
+ return $r.$nl;
}
- if ($this->raw && (strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
- $quot = $quot . $quot . $quot;
+
+ public function escape($v)
+ {
+ $r = '';
+ // decode, if possible
+ $v = (false === strpos(utf8_decode(str_replace('?', '', $v)), '?')) ? utf8_decode($v) : $v;
+ if ($this->raw) {
+ return $v;
+ } // no further escaping wanted
+ // escape tabs and linefeeds
+ $v = str_replace(["\t", "\r", "\n"], ['\t', '\r', '\n'], $v);
+ // escape non-ascii-chars
+ $v = preg_replace_callback('/([^a-zA-Z0-9 \!\#\$\%\&\(\)\*\+\,\-\.\/\:\;\=\?\@\^\_\{\|\}]+)/', [$this, 'escapeChars'], $v);
+
+ return $v;
}
- $suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
- $suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype']) : $suffix;
- //return $quot . "object" . utf8_encode($v['value']) . $quot . $suffix;
- return $quot . $this->escape($v['value']) . $quot . $suffix;
- }
-
- function getSerializedIndex($index, $raw = 0) {
- $this->raw = $raw;
- $r = '';
- $nl = "\n";
- foreach ($index as $s => $ps) {
- $s = $this->getTerm($s, 's');
- foreach ($ps as $p => $os) {
- $p = $this->getTerm($p, 'p');
- if (!is_array($os)) {/* single literal o */
- $os = array(array('value' => $os, 'type' => 'literal'));
+
+ public function escapeChars($matches)
+ {
+ $v = $matches[1];
+ $r = '';
+ // loop through mb chars
+ if (function_exists('mb_strlen')) {
+ for ($i = 0, $i_max = mb_strlen($v, 'UTF-8'); $i < $i_max; ++$i) {
+ $c = mb_substr($v, $i, 1, 'UTF-8');
+ if (!isset($this->esc_chars[$c])) {
+ $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c, 1));
+ }
+ $r .= $this->esc_chars[$c];
+ }
}
- foreach ($os as $o) {
- $o = $this->getTerm($o, 'o‚');
- $r .= $r ? $nl : '';
- $r .= $s . ' ' . $p . ' ' . $o . ' .';
+ // fall back to built-in JSON functionality, if available
+ elseif (function_exists('json_encode')) {
+ $r = json_encode($v);
+ if ('null' == $r) {
+ $r = json_encode(utf8_encode($v));
+ }
+ // remove boundary quotes
+ if ('"' == substr($r, 0, 1)) {
+ $r = substr($r, 1);
+ }
+ if ('"' == substr($r, -1)) {
+ $r = substr($r, 0, -1);
+ }
+ // uppercase hex chars
+ $r = preg_replace_callback('/(\\\u)([0-9a-f]{4})', function ($matches) {
+ return $matches[1].strtoupper($matches[2]);
+ }, $r);
+ $r = preg_replace_callback('/(\\\U)([0-9a-f]{8})', function ($matches) {
+ return $matches[1].strtoupper($matches[2]);
+ }, $r);
}
- }
+ // escape byte-wise (may be wrong for mb chars and newer php versions)
+ else {
+ for ($i = 0, $i_max = strlen($v); $i < $i_max; ++$i) {
+ $c = $v[$i];
+ if (!isset($this->esc_chars[$c])) {
+ $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c));
+ }
+ $r .= $this->esc_chars[$c];
+ }
+ }
+
+ return $r;
}
- return $r . $nl;
- }
-
- /* */
- function escape($v) {
- $r = '';
- // decode, if possible
- $v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v;
- if ($this->raw) return $v;// no further escaping wanted
- // escape tabs and linefeeds
- $v = str_replace(array("\t", "\r", "\n"), array('\t', '\r', '\n'), $v);
- // escape non-ascii-chars
- $v = preg_replace_callback('/([^a-zA-Z0-9 \!\#\$\%\&\(\)\*\+\,\-\.\/\:\;\=\?\@\^\_\{\|\}]+)/', array($this, 'escapeChars'), $v);
- return $v;
- }
-
- function escapeChars($matches) {
- $v = $matches[1];
- $r = '';
- // loop through mb chars
- if (function_exists('mb_strlen')) {
- for ($i = 0, $i_max = mb_strlen($v, 'UTF-8'); $i < $i_max; $i++) {
- $c = mb_substr($v, $i, 1, 'UTF-8');
- if (!isset($this->esc_chars[$c])) {
- $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c, 1));
- }
- $r .= $this->esc_chars[$c];
- }
- }
- // fall back to built-in JSON functionality, if available
- else if (function_exists('json_encode')) {
- $r = json_encode($v);
- if ($r == 'null') $r = json_encode (utf8_encode($v));
- // remove boundary quotes
- if (substr($r, 0, 1) == '"') $r = substr($r, 1);
- if (substr($r, -1) == '"') $r = substr($r, 0, -1);
- // uppercase hex chars
- $r = preg_replace_callback('/(\\\u)([0-9a-f]{4})', function($matches) {
- return $matches[1] . strtoupper($matches[2]);
- }, $r);
- $r = preg_replace_callback('/(\\\U)([0-9a-f]{8})', function($matches) {
- return $matches[1] . strtoupper($matches[2]);
- }, $r);
- }
- // escape byte-wise (may be wrong for mb chars and newer php versions)
- else {
- for ($i = 0, $i_max = strlen($v); $i < $i_max; $i++) {
- $c = $v[$i];
- if (!isset($this->esc_chars[$c])) {
- $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c));
- }
- $r .= $this->esc_chars[$c];
- }
- }
- return $r;
- }
-
- /* */
-
- function getCharNo($c, $is_encoded = false) {
- $c_utf = $is_encoded ? $c : utf8_encode($c);
- $bl = strlen($c_utf);/* binary length */
- $r = 0;
- switch ($bl) {
+ public function getCharNo($c, $is_encoded = false)
+ {
+ $c_utf = $is_encoded ? $c : utf8_encode($c);
+ $bl = strlen($c_utf); /* binary length */
+ $r = 0;
+ switch ($bl) {
case 1:/* 0####### (0-127) */
$r = ord($c_utf);
break;
@@ -171,26 +180,51 @@ function getCharNo($c, $is_encoded = false) {
$r = ((ord($c_utf[0]) - 240) * 262144) + ((ord($c_utf[1]) - 128) * 4096) + ((ord($c_utf[2]) - 128) * 64) + (ord($c_utf[3]) - 128);
break;
}
- return $r;
- }
- function getEscapedChar($c, $no) {/*see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
- if ($no < 9) return "\\u" . sprintf('%04X', $no); /* #x0-#x8 (0-8) */
- if ($no == 9) return '\t'; /* #x9 (9) */
- if ($no == 10) return '\n'; /* #xA (10) */
- if ($no < 13) return "\\u" . sprintf('%04X', $no); /* #xB-#xC (11-12) */
- if ($no == 13) return '\r'; /* #xD (13) */
- if ($no < 32) return "\\u" . sprintf('%04X', $no); /* #xE-#x1F (14-31) */
- if ($no < 34) return $c; /* #x20-#x21 (32-33) */
- if ($no == 34) return '\"'; /* #x22 (34) */
- if ($no < 92) return $c; /* #x23-#x5B (35-91) */
- if ($no == 92) return '\\'; /* #x5C (92) */
- if ($no < 127) return $c; /* #x5D-#x7E (93-126) */
- if ($no < 65536) return "\\u" . sprintf('%04X', $no); /* #x7F-#xFFFF (128-65535) */
- if ($no < 1114112) return "\\U" . sprintf('%08X', $no); /* #x10000-#x10FFFF (65536-1114111) */
- return ''; /* not defined => ignore */
- }
-
- /* */
-
+ return $r;
+ }
+
+ public function getEscapedChar($c, $no)
+ {/*see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
+ if ($no < 9) {
+ return '\\u'.sprintf('%04X', $no);
+ } /* #x0-#x8 (0-8) */
+ if (9 == $no) {
+ return '\t';
+ } /* #x9 (9) */
+ if (10 == $no) {
+ return '\n';
+ } /* #xA (10) */
+ if ($no < 13) {
+ return '\\u'.sprintf('%04X', $no);
+ } /* #xB-#xC (11-12) */
+ if (13 == $no) {
+ return '\r';
+ } /* #xD (13) */
+ if ($no < 32) {
+ return '\\u'.sprintf('%04X', $no);
+ } /* #xE-#x1F (14-31) */
+ if ($no < 34) {
+ return $c;
+ } /* #x20-#x21 (32-33) */
+ if (34 == $no) {
+ return '\"';
+ } /* #x22 (34) */
+ if ($no < 92) {
+ return $c;
+ } /* #x23-#x5B (35-91) */
+ if (92 == $no) {
+ return '\\';
+ } /* #x5C (92) */
+ if ($no < 127) {
+ return $c;
+ } /* #x5D-#x7E (93-126) */
+ if ($no < 65536) {
+ return '\\u'.sprintf('%04X', $no);
+ } /* #x7F-#xFFFF (128-65535) */
+ if ($no < 1114112) {
+ return '\\U'.sprintf('%08X', $no);
+ } /* #x10000-#x10FFFF (65536-1114111) */
+ return ''; /* not defined => ignore */
+ }
}
diff --git a/serializers/ARC2_POSHRDFSerializer.php b/serializers/ARC2_POSHRDFSerializer.php
index 5d4bcf7f..d33347a6 100755
--- a/serializers/ARC2_POSHRDFSerializer.php
+++ b/serializers/ARC2_POSHRDFSerializer.php
@@ -10,96 +10,110 @@ class: ARC2 POSH RDF Serializer
ARC2::inc('RDFSerializer');
-class ARC2_POSHRDFSerializer extends ARC2_RDFSerializer {
-
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- $this->content_header = 'text/html';
- }
-
- /* */
-
- function getLabel($res, $ps = '') {
- if (!$ps) $ps = array();
- foreach ($ps as $p => $os) {
- if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
- return $os[0]['value'];
- }
+class ARC2_POSHRDFSerializer extends ARC2_RDFSerializer
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
}
- if (preg_match('/^\_\:/', $res)) return "An unnamed resource";
- return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
- }
-
- function getSerializedIndex($index, $res = '') {
- $r = '';
- $n = "\n";
- if ($res) $index = array($res => $index[$res]);
- //return Trice::dump($index);
- foreach ($index as $s => $ps) {
- /* node */
- $r .= '
+
+ public function __init()
+ {
+ parent::__init();
+ $this->content_header = 'text/html';
+ }
+
+ public function getLabel($res, $ps = '')
+ {
+ if (!$ps) {
+ $ps = [];
+ }
+ foreach ($ps as $p => $os) {
+ if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
+ return $os[0]['value'];
+ }
+ }
+ if (preg_match('/^\_\:/', $res)) {
+ return 'An unnamed resource';
+ }
+
+ return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
+ }
+
+ public function getSerializedIndex($index, $res = '')
+ {
+ $r = '';
+ $n = "\n";
+ if ($res) {
+ $index = [$res => $index[$res]];
+ }
+ //return Trice::dump($index);
+ foreach ($index as $s => $ps) {
+ /* node */
+ $r .= '
-
+
';
- /* arcs */
- foreach ($ps as $p => $os) {
- $r .= '
+ /* arcs */
+ foreach ($ps as $p => $os) {
+ $r .= '
';
- }
- /* node */
- $r .= '
+ }
+ /* node */
+ $r .= '
';
+ }
+
+ return $r;
}
- return $r;
- }
-
- function getObjectValue($o) {
- if ($o['type'] == 'uri') {
- if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
- return $this->getImageObjectValue($o);
- }
- return $this->getURIObjectValue($o);
+
+ public function getObjectValue($o)
+ {
+ if ('uri' == $o['type']) {
+ if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
+ return $this->getImageObjectValue($o);
+ }
+
+ return $this->getURIObjectValue($o);
+ }
+ if ('bnode' == $o['type']) {
+ return $this->getBNodeObjectValue($o);
+ }
+
+ return $this->getLiteralObjectValue($o);
}
- if ($o['type'] == "bnode") {
- return $this->getBNodeObjectValue($o);
+
+ public function getImageObjectValue($o)
+ {
+ return '
';
}
- return $this->getLiteralObjectValue($o);
- }
-
- function getImageObjectValue($o) {
- return '
';
- }
-
- function getURIObjectValue($o) {
- $href = htmlspecialchars($o['value']);
- $label = $o['value'];
- $label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
- return '
' . $label . '';
- }
-
- function getBNodeObjectValue($o) {
- return '
An unnamed resource
';
- }
-
- function getLiteralObjectValue($o) {
- return '
' . $o['value'] . '
';
- }
-
- /* */
-}
+ public function getURIObjectValue($o)
+ {
+ $href = htmlspecialchars($o['value']);
+ $label = $o['value'];
+ $label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
+ return '
'.$label.'';
+ }
+
+ public function getBNodeObjectValue($o)
+ {
+ return '
An unnamed resource
';
+ }
+
+ public function getLiteralObjectValue($o)
+ {
+ return '
'.$o['value'].'
';
+ }
+}
diff --git a/serializers/ARC2_RDFJSONSerializer.php b/serializers/ARC2_RDFJSONSerializer.php
index 31f439ab..3997a55e 100644
--- a/serializers/ARC2_RDFJSONSerializer.php
+++ b/serializers/ARC2_RDFJSONSerializer.php
@@ -1,89 +1,92 @@
* @license W3C Software License and GPL
* @homepage
- * @package ARC2
-*/
-
+ */
ARC2::inc('RDFSerializer');
-class ARC2_RDFJSONSerializer extends ARC2_RDFSerializer {
-
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- $this->content_header = 'application/json';
- }
-
- /* */
-
- function getTerm($v, $term = 's') {
- if (!is_array($v)) {
- if (preg_match('/^\_\:/', $v)) {
- return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'bnode'), 'o') : '"' . $v . '"';
- }
- return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'uri'), 'o') : '"' . $v . '"';
- }
- if (!isset($v['type']) || ($v['type'] != 'literal')) {
- if ($term != 'o') {
- return $this->getTerm($v['value'], $term);
- }
- if (preg_match('/^\_\:/', $v['value'])) {
- return '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "bnode" }';
- }
- return '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "uri" }';
+class ARC2_RDFJSONSerializer extends ARC2_RDFSerializer
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
}
- /* literal */
- $r = '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "literal"';
- $suffix = isset($v['datatype']) ? ', "datatype" : "' . $v['datatype'] . '"' : '';
- $suffix = isset($v['lang']) ? ', "lang" : "' . $v['lang'] . '"' : $suffix;
- $r .= $suffix . ' }';
- return $r;
- }
- function jsonEscape($v) {
- if (function_exists('json_encode')) {
- return preg_replace('/^"(.*)"$/', '\\1', str_replace("\/","/",json_encode($v)));
+ public function __init()
+ {
+ parent::__init();
+ $this->content_header = 'application/json';
}
- $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f");
- $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f');
- return str_replace($from, $to, $v);
- }
-
- function getSerializedIndex($index, $raw = 0) {
- $r = '';
- $nl = "\n";
- foreach ($index as $s => $ps) {
- $r .= $r ? ',' . $nl . $nl : '';
- $r .= ' ' . $this->getTerm($s). ' : {';
- $first_p = 1;
- foreach ($ps as $p => $os) {
- $r .= $first_p ? $nl : ',' . $nl;
- $r .= ' ' . $this->getTerm($p). ' : [';
- $first_o = 1;
- if (!is_array($os)) {/* single literal o */
- $os = array(array('value' => $os, 'type' => 'literal'));
+
+ public function getTerm($v, $term = 's')
+ {
+ if (!is_array($v)) {
+ if (preg_match('/^\_\:/', $v)) {
+ return ('o' == $term) ? $this->getTerm(['value' => $v, 'type' => 'bnode'], 'o') : '"'.$v.'"';
+ }
+
+ return ('o' == $term) ? $this->getTerm(['value' => $v, 'type' => 'uri'], 'o') : '"'.$v.'"';
}
- foreach ($os as $o) {
- $r .= $first_o ? $nl : ',' . $nl;
- $r .= ' ' . $this->getTerm($o, 'o');
- $first_o = 0;
+ if (!isset($v['type']) || ('literal' != $v['type'])) {
+ if ('o' != $term) {
+ return $this->getTerm($v['value'], $term);
+ }
+ if (preg_match('/^\_\:/', $v['value'])) {
+ return '{ "value" : "'.$this->jsonEscape($v['value']).'", "type" : "bnode" }';
+ }
+
+ return '{ "value" : "'.$this->jsonEscape($v['value']).'", "type" : "uri" }';
}
- $first_p = 0;
- $r .= $nl . ' ]';
- }
- $r .= $nl . ' }';
+ /* literal */
+ $r = '{ "value" : "'.$this->jsonEscape($v['value']).'", "type" : "literal"';
+ $suffix = isset($v['datatype']) ? ', "datatype" : "'.$v['datatype'].'"' : '';
+ $suffix = isset($v['lang']) ? ', "lang" : "'.$v['lang'].'"' : $suffix;
+ $r .= $suffix.' }';
+
+ return $r;
}
- $r .= $r ? ' ' : '';
- return '{' . $nl . $r . $nl . '}';
- }
-
- /* */
+ public function jsonEscape($v)
+ {
+ if (function_exists('json_encode')) {
+ return preg_replace('/^"(.*)"$/', '\\1', str_replace("\/", '/', json_encode($v)));
+ }
+ $from = ['\\', "\r", "\t", "\n", '"', "\b", "\f"];
+ $to = ['\\\\', '\r', '\t', '\n', '\"', '\b', '\f'];
+
+ return str_replace($from, $to, $v);
+ }
+
+ public function getSerializedIndex($index, $raw = 0)
+ {
+ $r = '';
+ $nl = "\n";
+ foreach ($index as $s => $ps) {
+ $r .= $r ? ','.$nl.$nl : '';
+ $r .= ' '.$this->getTerm($s).' : {';
+ $first_p = 1;
+ foreach ($ps as $p => $os) {
+ $r .= $first_p ? $nl : ','.$nl;
+ $r .= ' '.$this->getTerm($p).' : [';
+ $first_o = 1;
+ if (!is_array($os)) {/* single literal o */
+ $os = [['value' => $os, 'type' => 'literal']];
+ }
+ foreach ($os as $o) {
+ $r .= $first_o ? $nl : ','.$nl;
+ $r .= ' '.$this->getTerm($o, 'o');
+ $first_o = 0;
+ }
+ $first_p = 0;
+ $r .= $nl.' ]';
+ }
+ $r .= $nl.' }';
+ }
+ $r .= $r ? ' ' : '';
+
+ return '{'.$nl.$r.$nl.'}';
+ }
}
diff --git a/serializers/ARC2_RDFSerializer.php b/serializers/ARC2_RDFSerializer.php
index b13a2c01..21aea982 100755
--- a/serializers/ARC2_RDFSerializer.php
+++ b/serializers/ARC2_RDFSerializer.php
@@ -1,53 +1,53 @@
- * @package ARC2
+ *
* @version 2010-11-16
-*/
-
+ */
ARC2::inc('Class');
-class ARC2_RDFSerializer extends ARC2_Class {
+class ARC2_RDFSerializer extends ARC2_Class
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
+ }
+
+ public function __init()
+ {
+ parent::__init();
+ foreach ($this->ns as $k => $v) {
+ $this->nsp[$v] = $k;
+ }
+ }
+
+ public function xgetPName($v)
+ {/* moved to merged getPName in ARC2_CLass */
+ if (preg_match('/^([a-z0-9\_\-]+)\:([a-z\_][a-z0-9\_\-]*)$/i', $v, $m) && isset($this->ns[$m[1]])) {
+ $this->used_ns = !in_array($this->ns[$m[1]], $this->used_ns) ? array_merge($this->used_ns, [$this->ns[$m[1]]]) : $this->used_ns;
+
+ return $v;
+ }
+ if (preg_match('/^(.*[\/\#])([a-z\_][a-z0-9\-\_]*)$/i', $v, $m)) {
+ return $this->getPrefix($m[1]).':'.$m[2];
+ }
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- foreach ($this->ns as $k => $v) {
- $this->nsp[$v] = $k;
+ return 0;
}
- }
-
- /* */
-
- function xgetPName($v) {/* moved to merged getPName in ARC2_CLass */
- if (preg_match('/^([a-z0-9\_\-]+)\:([a-z\_][a-z0-9\_\-]*)$/i', $v, $m) && isset($this->ns[$m[1]])) {
- $this->used_ns = !in_array($this->ns[$m[1]], $this->used_ns) ? array_merge($this->used_ns, array($this->ns[$m[1]])) : $this->used_ns;
- return $v;
+
+ public function getSerializedTriples($triples, $raw = 0)
+ {
+ $index = ARC2::getSimpleIndex($triples, 0);
+
+ return $this->getSerializedIndex($index, $raw);
}
- if (preg_match('/^(.*[\/\#])([a-z\_][a-z0-9\-\_]*)$/i', $v, $m)) {
- return $this->getPrefix($m[1]) . ':' . $m[2];
+
+ public function getSerializedIndex($index, $raw = 0)
+ {
+ return '';
}
- return 0;
- }
-
- /* */
-
- function getSerializedTriples($triples, $raw = 0) {
- $index = ARC2::getSimpleIndex($triples, 0);
- return $this->getSerializedIndex($index, $raw);
- }
-
- function getSerializedIndex($index, $raw = 0) {
- return '';
- }
-
- /* */
-
}
diff --git a/serializers/ARC2_RDFXMLSerializer.php b/serializers/ARC2_RDFXMLSerializer.php
index 8f5e4c7e..f7ebcabb 100644
--- a/serializers/ARC2_RDFXMLSerializer.php
+++ b/serializers/ARC2_RDFXMLSerializer.php
@@ -1,198 +1,233 @@
- * @package ARC2
+ *
* @version 2010-11-16
-*/
-
+ */
ARC2::inc('RDFSerializer');
-class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer {
-
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- $this->content_header = 'application/rdf+xml';
- $this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
- $this->default_ns = $this->v('serializer_default_ns', '', $this->a);
- $this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
- }
-
- /* */
-
- function getTerm($v, $type) {
- if (!is_array($v)) {/* uri or bnode */
- if (preg_match('/^\_\:(.*)$/', $v, $m)) {
- return ' rdf:nodeID="' . $m[1] . '"';
- }
- if ($type == 's') {
- return ' rdf:about="' . htmlspecialchars($v) . '"';
- }
- if ($type == 'p') {
- $pn = $this->getPName($v);
- return $pn ? $pn : 0;
- }
- if ($type == 'o') {
- $v = $this->expandPName($v);
- if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) return $this->getTerm(array('value' => $v, 'type' => 'literal'), $type);
- return ' rdf:resource="' . htmlspecialchars($v) . '"';
- }
- if ($type == 'datatype') {
- $v = $this->expandPName($v);
- return ' rdf:datatype="' . htmlspecialchars($v) . '"';
- }
- if ($type == 'lang') {
- return ' xml:lang="' . htmlspecialchars($v) . '"';
- }
- }
- if ($this->v('type', '', $v) != 'literal') {
- return $this->getTerm($v['value'], 'o');
+class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
}
- /* literal */
- $dt = isset($v['datatype']) ? $v['datatype'] : '';
- $lang = isset($v['lang']) ? $v['lang'] : '';
- if ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
- return ' rdf:parseType="Literal">' . $v['value'];
- }
- elseif ($dt) {
- return $this->getTerm($dt, 'datatype') . '>' . htmlspecialchars($v['value']);
+
+ public function __init()
+ {
+ parent::__init();
+ $this->content_header = 'application/rdf+xml';
+ $this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
+ $this->default_ns = $this->v('serializer_default_ns', '', $this->a);
+ $this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
}
- elseif ($lang) {
- return $this->getTerm($lang, 'lang') . '>' . htmlspecialchars($v['value']);
+
+ public function getTerm($v, $type)
+ {
+ if (!is_array($v)) {/* uri or bnode */
+ if (preg_match('/^\_\:(.*)$/', $v, $m)) {
+ return ' rdf:nodeID="'.$m[1].'"';
+ }
+ if ('s' == $type) {
+ return ' rdf:about="'.htmlspecialchars($v).'"';
+ }
+ if ('p' == $type) {
+ $pn = $this->getPName($v);
+
+ return $pn ? $pn : 0;
+ }
+ if ('o' == $type) {
+ $v = $this->expandPName($v);
+ if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) {
+ return $this->getTerm(['value' => $v, 'type' => 'literal'], $type);
+ }
+
+ return ' rdf:resource="'.htmlspecialchars($v).'"';
+ }
+ if ('datatype' == $type) {
+ $v = $this->expandPName($v);
+
+ return ' rdf:datatype="'.htmlspecialchars($v).'"';
+ }
+ if ('lang' == $type) {
+ return ' xml:lang="'.htmlspecialchars($v).'"';
+ }
+ }
+ if ('literal' != $this->v('type', '', $v)) {
+ return $this->getTerm($v['value'], 'o');
+ }
+ /* literal */
+ $dt = isset($v['datatype']) ? $v['datatype'] : '';
+ $lang = isset($v['lang']) ? $v['lang'] : '';
+ if ('http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral' == $dt) {
+ return ' rdf:parseType="Literal">'.$v['value'];
+ } elseif ($dt) {
+ return $this->getTerm($dt, 'datatype').'>'.htmlspecialchars($v['value']);
+ } elseif ($lang) {
+ return $this->getTerm($lang, 'lang').'>'.htmlspecialchars($v['value']);
+ }
+
+ return '>'.htmlspecialchars($this->v('value', '', $v));
}
- return '>' . htmlspecialchars($this->v('value', '', $v));
- }
- function getPName($v, $connector = ':') {
- if ($this->default_ns && (strpos($v, $this->default_ns) === 0)) {
- $pname = substr($v, strlen($this->default_ns));
- if (!preg_match('/\//', $pname)) return $pname;
+ public function getPName($v, $connector = ':')
+ {
+ if ($this->default_ns && (0 === strpos($v, $this->default_ns))) {
+ $pname = substr($v, strlen($this->default_ns));
+ if (!preg_match('/\//', $pname)) {
+ return $pname;
+ }
+ }
+
+ return parent::getPName($v, $connector);
}
- return parent::getPName($v, $connector);
- }
-
- function getHead() {
- $r = '';
- $nl = "\n";
- $r .= '';
- $r .= $nl . 'used_ns as $v) {
- $r .= $first_ns ? ' ' : $nl . ' ';
- foreach ($this->ns as $prefix => $ns) {
- if ($ns != $v) continue;
- $r .= 'xmlns:' . $prefix . '="' .$v. '"';
- break;
- }
- $first_ns = 0;
+
+ public function getHead()
+ {
+ $r = '';
+ $nl = "\n";
+ $r .= '';
+ $r .= $nl.'used_ns as $v) {
+ $r .= $first_ns ? ' ' : $nl.' ';
+ foreach ($this->ns as $prefix => $ns) {
+ if ($ns != $v) {
+ continue;
+ }
+ $r .= 'xmlns:'.$prefix.'="'.$v.'"';
+ break;
+ }
+ $first_ns = 0;
+ }
+ if ($this->default_ns) {
+ $r .= $first_ns ? ' ' : $nl.' ';
+ $r .= 'xmlns="'.$this->default_ns.'"';
+ }
+ $r .= '>';
+
+ return $r;
}
- if ($this->default_ns) {
- $r .= $first_ns ? ' ' : $nl . ' ';
- $r .= 'xmlns="' . $this->default_ns . '"';
+
+ public function getFooter()
+ {
+ $r = '';
+ $nl = "\n";
+ $r .= $nl.$nl.'';
+
+ return $r;
}
- $r .= '>';
- return $r;
- }
-
- function getFooter() {
- $r = '';
- $nl = "\n";
- $r .= $nl . $nl . '';
- return $r;
- }
-
- function getSerializedIndex($index, $raw = 0) {
- $r = '';
- $nl = "\n";
- foreach ($index as $raw_s => $ps) {
- $r .= $r ? $nl . $nl : '';
- $s = $this->getTerm($raw_s, 's');
- $tag = 'rdf:Description';
- list($tag, $ps) = $this->getNodeTag($ps);
- $sub_ps = 0;
- /* pretty containers */
- if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
- $tag = 'rdf:' . $ctag;
- list($ps, $sub_ps) = $this->splitContainerEntries($ps);
- }
- $r .= ' <' . $tag . '' .$s . '>';
- $first_p = 1;
- foreach ($ps as $p => $os) {
- if (!$os) continue;
- $p = $this->getTerm($p, 'p');
- if ($p) {
- $r .= $nl . str_pad('', 4);
- $first_o = 1;
- if (!is_array($os)) {/* single literal o */
- $os = array(array('value' => $os, 'type' => 'literal'));
- }
- foreach ($os as $o) {
- $o = $this->getTerm($o, 'o');
- $r .= $first_o ? '' : $nl . ' ';
- $r .= '<' . $p;
- $r .= $o;
- $r .= preg_match('/\>/', $o) ? '' . $p . '>' : '/>';
- $first_o = 0;
- }
- $first_p = 0;
+
+ public function getSerializedIndex($index, $raw = 0)
+ {
+ $r = '';
+ $nl = "\n";
+ foreach ($index as $raw_s => $ps) {
+ $r .= $r ? $nl.$nl : '';
+ $s = $this->getTerm($raw_s, 's');
+ $tag = 'rdf:Description';
+ list($tag, $ps) = $this->getNodeTag($ps);
+ $sub_ps = 0;
+ /* pretty containers */
+ if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
+ $tag = 'rdf:'.$ctag;
+ list($ps, $sub_ps) = $this->splitContainerEntries($ps);
+ }
+ $r .= ' <'.$tag.''.$s.'>';
+ $first_p = 1;
+ foreach ($ps as $p => $os) {
+ if (!$os) {
+ continue;
+ }
+ $p = $this->getTerm($p, 'p');
+ if ($p) {
+ $r .= $nl.str_pad('', 4);
+ $first_o = 1;
+ if (!is_array($os)) {/* single literal o */
+ $os = [['value' => $os, 'type' => 'literal']];
+ }
+ foreach ($os as $o) {
+ $o = $this->getTerm($o, 'o');
+ $r .= $first_o ? '' : $nl.' ';
+ $r .= '<'.$p;
+ $r .= $o;
+ $r .= preg_match('/\>/', $o) ? ''.$p.'>' : '/>';
+ $first_o = 0;
+ }
+ $first_p = 0;
+ }
+ }
+ $r .= $r ? $nl.' '.$tag.'>' : '';
+ if ($sub_ps) {
+ $r .= $nl.$nl.$this->getSerializedIndex([$raw_s => $sub_ps], 1);
+ }
}
- }
- $r .= $r ? $nl . ' ' . $tag . '>' : '';
- if ($sub_ps) $r .= $nl . $nl . $this->getSerializedIndex(array($raw_s => $sub_ps), 1);
- }
- if ($raw) {
- return $r;
+ if ($raw) {
+ return $r;
+ }
+
+ return $this->getHead().$nl.$nl.$r.$this->getFooter();
}
- return $this->getHead() . $nl . $nl . $r . $this->getFooter();
- }
-
- function getNodeTag($ps) {
- if (!$this->type_nodes) return array('rdf:Description', $ps);
- $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
- $types = $this->v($rdf . 'type', array(), $ps);
- if (!$types) return array('rdf:Description', $ps);
- $type = array_shift($types);
- $ps[$rdf . 'type'] = $types;
- if (!is_array($type)) $type = array('value' => $type);
- return array($this->getPName($type['value']), $ps);
- }
-
- /* */
-
- function getContainerTag($ps) {
- $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
- if (!isset($ps[$rdf . 'type'])) return '';
- $types = $ps[$rdf . 'type'];
- foreach ($types as $type) {
- if (!in_array($type['value'], array($rdf . 'Bag', $rdf . 'Seq', $rdf . 'Alt'))) return '';
- return str_replace($rdf, '', $type['value']);
+
+ public function getNodeTag($ps)
+ {
+ if (!$this->type_nodes) {
+ return ['rdf:Description', $ps];
+ }
+ $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+ $types = $this->v($rdf.'type', [], $ps);
+ if (!$types) {
+ return ['rdf:Description', $ps];
+ }
+ $type = array_shift($types);
+ $ps[$rdf.'type'] = $types;
+ if (!is_array($type)) {
+ $type = ['value' => $type];
+ }
+
+ return [$this->getPName($type['value']), $ps];
}
- }
-
- function splitContainerEntries($ps) {
- $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
- $items = array();
- $rest = array();
- foreach ($ps as $p => $os) {
- $p_short = str_replace($rdf, '', $p);
- if ($p_short === 'type') continue;
- if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
- $items = array_merge($items, $os);
- }
- else {
- $rest[$p] = $os;
- }
+
+ public function getContainerTag($ps)
+ {
+ $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+ if (!isset($ps[$rdf.'type'])) {
+ return '';
+ }
+ $types = $ps[$rdf.'type'];
+ foreach ($types as $type) {
+ if (!in_array($type['value'], [$rdf.'Bag', $rdf.'Seq', $rdf.'Alt'])) {
+ return '';
+ }
+
+ return str_replace($rdf, '', $type['value']);
+ }
}
- if ($items) return array(array($rdf . 'li' => $items), $rest);
- return array($rest, 0);
- }
- /* */
+ public function splitContainerEntries($ps)
+ {
+ $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+ $items = [];
+ $rest = [];
+ foreach ($ps as $p => $os) {
+ $p_short = str_replace($rdf, '', $p);
+ if ('type' === $p_short) {
+ continue;
+ }
+ if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
+ $items = array_merge($items, $os);
+ } else {
+ $rest[$p] = $os;
+ }
+ }
+ if ($items) {
+ return [[$rdf.'li' => $items], $rest];
+ }
+
+ return [$rest, 0];
+ }
}
diff --git a/serializers/ARC2_RSS10Serializer.php b/serializers/ARC2_RSS10Serializer.php
index 51a5cb03..7a4c61cf 100755
--- a/serializers/ARC2_RSS10Serializer.php
+++ b/serializers/ARC2_RSS10Serializer.php
@@ -1,30 +1,28 @@
- * @package ARC2
+ *
* @version 2010-11-16
-*/
-
+ */
ARC2::inc('RDFXMLSerializer');
-class ARC2_RSS10Serializer extends ARC2_RDFXMLSerializer {
-
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- $this->content_header = 'application/rss+xml';
- $this->default_ns = 'http://purl.org/rss/1.0/';
- $this->type_nodes = true;
- }
+class ARC2_RSS10Serializer extends ARC2_RDFXMLSerializer
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
+ }
- /* */
-
+ public function __init()
+ {
+ parent::__init();
+ $this->content_header = 'application/rss+xml';
+ $this->default_ns = 'http://purl.org/rss/1.0/';
+ $this->type_nodes = true;
+ }
}
diff --git a/serializers/ARC2_TurtleSerializer.php b/serializers/ARC2_TurtleSerializer.php
index c0d39908..84e42321 100644
--- a/serializers/ARC2_TurtleSerializer.php
+++ b/serializers/ARC2_TurtleSerializer.php
@@ -1,121 +1,128 @@
- * @package ARC2
+ *
* @version 2010-11-16
-*/
-
+ */
ARC2::inc('RDFSerializer');
-class ARC2_TurtleSerializer extends ARC2_RDFSerializer {
+class ARC2_TurtleSerializer extends ARC2_RDFSerializer
+{
+ public function __construct($a, &$caller)
+ {
+ parent::__construct($a, $caller);
+ }
- function __construct($a, &$caller) {
- parent::__construct($a, $caller);
- }
-
- function __init() {
- parent::__init();
- $this->content_header = 'application/x-turtle';
- }
+ public function __init()
+ {
+ parent::__init();
+ $this->content_header = 'application/x-turtle';
+ }
- /* */
-
- function getTerm($v, $term = '', $qualifier = '') {
- if (!is_array($v)) {
- if (preg_match('/^\_\:/', $v)) {
- return $v;
- }
- if (($term === 'p') && ($pn = $this->getPName($v))) {
- return $pn;
- }
- if (
- ($term === 'o') &&
- in_array($qualifier, array('rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf')) &&
+ public function getTerm($v, $term = '', $qualifier = '')
+ {
+ if (!is_array($v)) {
+ if (preg_match('/^\_\:/', $v)) {
+ return $v;
+ }
+ if (('p' === $term) && ($pn = $this->getPName($v))) {
+ return $pn;
+ }
+ if (
+ ('o' === $term) &&
+ in_array($qualifier, ['rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf']) &&
($pn = $this->getPName($v))
) {
- return $pn;
- }
- if (preg_match('/^[a-z0-9]+\:[^\s]*$/is' . ($this->has_pcre_unicode ? 'u' : ''), $v)) {
- return '<' .$v. '>';
- }
- return $this->getTerm(array('type' => 'literal', 'value' => $v), $term, $qualifier);
- }
- if (!isset($v['type']) || ($v['type'] != 'literal')) {
- return $this->getTerm($v['value'], $term, $qualifier);
- }
- /* literal */
- $quot = '"';
- if (preg_match('/\"/', $v['value'])) {
- $quot = "'";
- if (preg_match('/\'/', $v['value']) || preg_match('/[\x0d\x0a]/', $v['value'])) {
- $quot = '"""';
- if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
- $quot = "'''";
- $v['value'] = preg_replace("/'$/", "' ", $v['value']);
- $v['value'] = preg_replace("/^'/", " '", $v['value']);
- $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+ return $pn;
+ }
+ if (preg_match('/^[a-z0-9]+\:[^\s]*$/is'.($this->has_pcre_unicode ? 'u' : ''), $v)) {
+ return '<'.$v.'>';
+ }
+
+ return $this->getTerm(['type' => 'literal', 'value' => $v], $term, $qualifier);
}
- }
- }
- if ((strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
- $quot = $quot . $quot . $quot;
- }
- $suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
- $suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype'], 'dt') : $suffix;
- return $quot . $v['value'] . $quot . $suffix;
- }
-
- function getHead() {
- $r = '';
- $nl = "\n";
- foreach ($this->used_ns as $v) {
- $r .= $r ? $nl : '';
- foreach ($this->ns as $prefix => $ns) {
- if ($ns != $v) continue;
- $r .= '@prefix ' . $prefix . ': <' .$v. '> .';
- break;
- }
- }
- return $r;
- }
-
- function getSerializedIndex($index, $raw = 0) {
- $r = '';
- $nl = "\n";
- foreach ($index as $s => $ps) {
- $r .= $r ? ' .' . $nl . $nl : '';
- $s = $this->getTerm($s, 's');
- $r .= $s;
- $first_p = 1;
- foreach ($ps as $p => $os) {
- if (!$os) continue;
- $p = $this->getTerm($p, 'p');
- $r .= $first_p ? ' ' : ' ;' . $nl . str_pad('', strlen($s) + 1);
- $r .= $p;
- $first_o = 1;
- if (!is_array($os)) {/* single literal o */
- $os = array(array('value' => $os, 'type' => 'literal'));
+ if (!isset($v['type']) || ('literal' != $v['type'])) {
+ return $this->getTerm($v['value'], $term, $qualifier);
}
- foreach ($os as $o) {
- $r .= $first_o ? ' ' : ' ,' . $nl . str_pad('', strlen($s) + strlen($p) + 2);
- $o = $this->getTerm($o, 'o', $p);
- $r .= $o;
- $first_o = 0;
+ /* literal */
+ $quot = '"';
+ if (preg_match('/\"/', $v['value'])) {
+ $quot = "'";
+ if (preg_match('/\'/', $v['value']) || preg_match('/[\x0d\x0a]/', $v['value'])) {
+ $quot = '"""';
+ if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
+ $quot = "'''";
+ $v['value'] = preg_replace("/'$/", "' ", $v['value']);
+ $v['value'] = preg_replace("/^'/", " '", $v['value']);
+ $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+ }
+ }
}
- $first_p = 0;
- }
+ if ((1 == strlen($quot)) && preg_match('/[\x0d\x0a]/', $v['value'])) {
+ $quot = $quot.$quot.$quot;
+ }
+ $suffix = isset($v['lang']) && $v['lang'] ? '@'.$v['lang'] : '';
+ $suffix = isset($v['datatype']) && $v['datatype'] ? '^^'.$this->getTerm($v['datatype'], 'dt') : $suffix;
+
+ return $quot.$v['value'].$quot.$suffix;
}
- $r .= $r ? ' .' : '';
- if ($raw) {
- return $r;
+
+ public function getHead()
+ {
+ $r = '';
+ $nl = "\n";
+ foreach ($this->used_ns as $v) {
+ $r .= $r ? $nl : '';
+ foreach ($this->ns as $prefix => $ns) {
+ if ($ns != $v) {
+ continue;
+ }
+ $r .= '@prefix '.$prefix.': <'.$v.'> .';
+ break;
+ }
+ }
+
+ return $r;
}
- return $r ? $this->getHead() . $nl . $nl . $r : '';
- }
-
- /* */
+ public function getSerializedIndex($index, $raw = 0)
+ {
+ $r = '';
+ $nl = "\n";
+ foreach ($index as $s => $ps) {
+ $r .= $r ? ' .'.$nl.$nl : '';
+ $s = $this->getTerm($s, 's');
+ $r .= $s;
+ $first_p = 1;
+ foreach ($ps as $p => $os) {
+ if (!$os) {
+ continue;
+ }
+ $p = $this->getTerm($p, 'p');
+ $r .= $first_p ? ' ' : ' ;'.$nl.str_pad('', strlen($s) + 1);
+ $r .= $p;
+ $first_o = 1;
+ if (!is_array($os)) {/* single literal o */
+ $os = [['value' => $os, 'type' => 'literal']];
+ }
+ foreach ($os as $o) {
+ $r .= $first_o ? ' ' : ' ,'.$nl.str_pad('', strlen($s) + strlen($p) + 2);
+ $o = $this->getTerm($o, 'o', $p);
+ $r .= $o;
+ $first_o = 0;
+ }
+ $first_p = 0;
+ }
+ }
+ $r .= $r ? ' .' : '';
+ if ($raw) {
+ return $r;
+ }
+
+ return $r ? $this->getHead().$nl.$nl.$r : '';
+ }
}
diff --git a/src/ARC2/Store/Adapter/AbstractAdapter.php b/src/ARC2/Store/Adapter/AbstractAdapter.php
new file mode 100644
index 00000000..ea9afd55
--- /dev/null
+++ b/src/ARC2/Store/Adapter/AbstractAdapter.php
@@ -0,0 +1,74 @@
+
+ * @author Konrad Abicht
+ * @license W3C Software License and GPL
+ * @homepage
+ */
+
+namespace ARC2\Store\Adapter;
+
+abstract class AbstractAdapter
+{
+ protected $configuration;
+ protected $db;
+
+ /**
+ * Stores errors of failed queries.
+ *
+ * @var array
+ */
+ protected $errors = array();
+
+ /**
+ * Sent queries.
+ *
+ * @var array
+ */
+ protected $queries = array();
+
+ /**
+ * @param array $configuration Default is array(). Only use, if you have your own mysqli connection.
+ */
+ public function __construct(array $configuration = array())
+ {
+ $this->configuration = $configuration;
+
+ $this->checkRequirements();
+ }
+
+ abstract public function checkRequirements();
+
+ abstract public function connect($existingConnection = null);
+
+ abstract public function disconnect();
+
+ abstract public function escape($value);
+
+ abstract public function exec($sql);
+
+ abstract public function fetchList($sql);
+
+ abstract public function fetchRow($sql);
+
+ abstract public function getAdapterName();
+
+ abstract public function getCollation();
+
+ abstract public function getDBSName();
+
+ abstract public function getLastInsertId();
+
+ abstract public function getServerInfo();
+
+ abstract public function getErrorMessage();
+
+ abstract public function getNumberOfRows($sql);
+
+ abstract public function getStoreName();
+
+ abstract public function getTablePrefix();
+
+ abstract public function simpleQuery($sql);
+}
diff --git a/src/ARC2/Store/Adapter/AdapterFactory.php b/src/ARC2/Store/Adapter/AdapterFactory.php
new file mode 100644
index 00000000..9ace7c39
--- /dev/null
+++ b/src/ARC2/Store/Adapter/AdapterFactory.php
@@ -0,0 +1,65 @@
+
+ * @author Konrad Abicht
+ * @license W3C Software License and GPL
+ * @homepage
+ */
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * It provides an adapter instance for requested adapter name.
+ */
+class AdapterFactory
+{
+ /**
+ * @param string $adapterName
+ * @param array $configuration Default is array()
+ */
+ public function getInstanceFor($adapterName, $configuration = array())
+ {
+ if (in_array($adapterName, $this->getSupportedAdapters())) {
+ /*
+ * mysqli
+ */
+ if ('mysqli' == $adapterName) {
+ if (false == class_exists('\\ARC2\\Store\\Adapter\\mysqliAdapter')) {
+ require_once 'mysqliAdapter.php';
+ }
+ return new mysqliAdapter($configuration);
+ /*
+ * PDO
+ */
+ } elseif ('pdo' == $adapterName) {
+ // use cache?
+ if (isset($configuration['cache_enabled']) && true === $configuration['cache_enabled']) {
+ if (false == class_exists('\\ARC2\\Store\\Adapter\\CachedPDOAdapter')) {
+ require_once 'CachedPDOAdapter.php';
+ }
+ return new CachedPDOAdapter($configuration);
+ // no cache
+ } else {
+ if (false == class_exists('\\ARC2\\Store\\Adapter\\PDOAdapter')) {
+ require_once 'PDOAdapter.php';
+ }
+ return new PDOAdapter($configuration);
+ }
+ }
+ }
+
+ throw new \Exception(
+ 'Unknown adapter name given. Currently supported are: '
+ .implode(', ', $this->getSupportedAdapters())
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function getSupportedAdapters()
+ {
+ return array('mysqli', 'pdo');
+ }
+}
diff --git a/src/ARC2/Store/Adapter/CachedPDOAdapter.php b/src/ARC2/Store/Adapter/CachedPDOAdapter.php
new file mode 100644
index 00000000..f4c805e5
--- /dev/null
+++ b/src/ARC2/Store/Adapter/CachedPDOAdapter.php
@@ -0,0 +1,145 @@
+
+ * @author Konrad Abicht
+ * @license W3C Software License and GPL
+ * @homepage
+ */
+
+namespace ARC2\Store\Adapter;
+
+use Psr\SimpleCache\CacheInterface;
+use Symfony\Component\Cache\Simple\FilesystemCache;
+
+/**
+ * PDO Adapter - Handles database operations using PDO.
+ */
+class CachedPDOAdapter extends PDOAdapter
+{
+ protected $cacheEnabled;
+ protected $cache;
+
+ public function __construct(array $configuration = array())
+ {
+ parent::__construct($configuration);
+
+ $this->initCache($configuration);
+ }
+
+ protected function initCache(array $configuration)
+ {
+ $this->cacheEnabled = isset($configuration['cache_enabled'])
+ && true === $configuration['cache_enabled'];
+
+ if ($this->cacheEnabled) {
+ // reuse existing cache instance, if it implements Psr\SimpleCache\CacheInterface
+ if (isset($configuration['cache_instance'])
+ && $configuration['cache_instance'] instanceof CacheInterface) {
+ $this->cache = $configuration['cache_instance'];
+
+ // create new cache instance
+ } else {
+ // FYI: https://symfony.com/doc/current/components/cache/adapters/filesystem_adapter.html
+ $this->cache = new FilesystemCache('arc2', 0, null);
+ }
+ } else {
+ throw new \Exception('Cache not enabled, therefore CachedPDOAdapter can not be used.');
+ }
+ }
+
+ public function clearCache()
+ {
+ $this->cache->clear();
+ }
+
+ /**
+ * @param string $sql
+ *
+ * @return array
+ */
+ public function fetchList($sql)
+ {
+ $key = hash('sha1', $sql);
+
+ // sql query is known
+ if ($this->cache->has($key)) {
+ return $this->cache->get($key);
+
+ } else {
+ $result = parent::fetchList($sql);
+ $this->cache->set($key, $result);
+ return $result;
+ }
+ }
+
+ /**
+ * @param string $sql
+ *
+ * @return array
+ */
+ public function fetchRow($sql)
+ {
+ $key = hash('sha1', $sql);
+
+ // sql query is known
+ if ($this->cache->has($key)) {
+ return $this->cache->get($key);
+
+ } else {
+ $result = parent::fetchRow($sql);
+ $this->cache->set($key, $result);
+ return $result;
+ }
+ }
+
+ public function getCacheInstance()
+ {
+ return $this->cache;
+ }
+
+ public function getNumberOfRows($sql)
+ {
+ $key = hash('sha1', $sql);
+
+ // sql query is known
+ if ($this->cache->has($key)) {
+ return $this->cache->get($key);
+
+ } else {
+ $result = parent::getNumberOfRows($sql);
+ $this->cache->set($key, $result);
+ return $result;
+ }
+ }
+
+ /**
+ * catches the first part of the query
+ * we need that to determine if its an query which changes the DB in any way
+ */
+ protected function queryChangesDb($sql)
+ {
+ $sqlPart = substr(trim($sql), 0, 4);
+ return true === in_array($sqlPart, ['CREA', 'DROP', 'DELE', 'INSE', 'RENA', 'UPDA',]);
+ }
+
+ public function simpleQuery($sql)
+ {
+ if ($this->queryChangesDb($sql)) {
+ $this->cache->clear();
+ }
+
+ return parent::simpleQuery($sql);
+ }
+
+ public function exec($sql)
+ {
+ if ($this->queryChangesDb($sql)) {
+ $this->cache->clear();
+ }
+
+ return parent::exec($sql);
+ }
+}
diff --git a/src/ARC2/Store/Adapter/MysqliDbExtended.php b/src/ARC2/Store/Adapter/MysqliDbExtended.php
new file mode 100644
index 00000000..5a74cd51
--- /dev/null
+++ b/src/ARC2/Store/Adapter/MysqliDbExtended.php
@@ -0,0 +1,111 @@
+mysqli()->affected_rows;
+ }
+
+ /**
+ * If you ran a query using MysqliDbExtended::simpleQuery and an error occoured, you can
+ * get the error code with this function.
+ *
+ * @return int Error code, if available.
+ */
+ public function getErrorCode()
+ {
+ return $this->mysqli()->errno;
+ }
+
+ /**
+ * If you ran a query using MysqliDbExtended::simpleQuery and an error occoured, you can
+ * get the error message with this function.
+ *
+ * @return string Non-empty string, if an error occoured, empty string otherwise.
+ */
+ public function getErrorMessage()
+ {
+ return $this->mysqli()->error;
+ }
+
+ /**
+ * @return int
+ */
+ public function getLastInsertId()
+ {
+ if (is_object($this->last_result)) {
+ return $this->last_result->insert_id;
+ }
+
+ return null;
+ }
+
+ /**
+ * Executes a SQL statement and returns the number of rows. This function will return 0,
+ * regardless of errors in the query.
+ *
+ * @param string $sql Query to execute.
+ *
+ * @return int Number of rows, if available, 0 otherwise.
+ */
+ public function getNumberOfRows($sql = null)
+ {
+ if (null != $sql) {
+ $result = $this->mysqli()->query($sql);
+ return is_object($result) ? $result->num_rows : 0;
+
+ } elseif (is_object($this->last_result)) {
+ return $this->last_result->num_rows;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Returns the server version.
+ *
+ * @return string
+ */
+ public function getServerInfo()
+ {
+ return $this->mysqli()->server_info;
+ }
+
+ /**
+ * For compatibility reasons. Executes a query using mysqli and returns the result. Dont use
+ * this function directly. It is only used once to make sure, ARC2 keeps its backward compatibility
+ * while in the 2.x branch.
+ *
+ * @param string $sql Query to execute.
+ *
+ * @return mysqli result|false
+ */
+ public function mysqliQuery($sql)
+ {
+ return $this->mysqli()->query($sql);
+ }
+
+ /**
+ * @param string $sql Query to execute.
+ *
+ * @return bool True if query runs without problems, false otherwise.
+ */
+ public function simpleQuery($sql, $num_rows = null)
+ {
+ $this->last_result = $this->mysqli()->query($sql, $num_rows);
+ return $this->last_result ? true : false;
+ }
+}
diff --git a/src/ARC2/Store/Adapter/PDOAdapter.php b/src/ARC2/Store/Adapter/PDOAdapter.php
new file mode 100644
index 00000000..7b245e23
--- /dev/null
+++ b/src/ARC2/Store/Adapter/PDOAdapter.php
@@ -0,0 +1,320 @@
+
+ * @author Konrad Abicht
+ * @license W3C Software License and GPL
+ * @homepage
+ */
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * PDO Adapter - Handles database operations using PDO.
+ */
+class PDOAdapter extends AbstractAdapter
+{
+ public function checkRequirements()
+ {
+ if (false == \extension_loaded('pdo_mysql')) {
+ throw new \Exception('Extension pdo_mysql is not loaded.');
+ }
+ }
+
+ public function getAdapterName()
+ {
+ return 'pdo';
+ }
+
+ /**
+ * Connect to server or storing a given connection.
+ *
+ * @param EasyDB $existingConnection Default is null.
+ */
+ public function connect($existingConnection = null)
+ {
+ // reuse a given existing connection.
+ // it assumes that $existingConnection is a PDO connection object
+ if (null !== $existingConnection) {
+ $this->db = $existingConnection;
+
+ // create your own connection
+ } elseif (false === $this->db instanceof \PDO) {
+ /*
+ * build connection string
+ *
+ * - db_pdo_protocol: Protocol to determine server, e.g. mysql
+ */
+ if (false == isset($this->configuration['db_pdo_protocol'])) {
+ throw new \Exception(
+ 'When using PDO the protocol has to be given (e.g. mysql). Please set db_pdo_protocol in database configuration.'
+ );
+ }
+ $dsn = $this->configuration['db_pdo_protocol'].':host='. $this->configuration['db_host'];
+ if (isset($this->configuration['db_name'])) {
+ $dsn .= ';dbname='.$this->configuration['db_name'];
+ }
+
+ // set charset
+ $dsn .= ';charset=utf8mb4';
+
+ $this->db = new \PDO(
+ $dsn,
+ $this->configuration['db_user'],
+ $this->configuration['db_pwd']
+ );
+
+ $this->db->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
+
+ // errors DONT lead to exceptions
+ // set to false for compatibility reasons with mysqli. ARC2 using mysqli does not throw any
+ // exceptions, instead collects errors in a hidden array.
+ $this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+
+ // default fetch mode is associative
+ $this->db->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
+
+ // from source: http://php.net/manual/de/ref.pdo-mysql.php
+ // If this attribute is set to TRUE on a PDOStatement, the MySQL driver will use
+ // the buffered versions of the MySQL API. But we wont rely on that, setting it false.
+ $this->db->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+
+ // This is RDF, we may need many JOINs...
+ // TODO find an equivalent in other DBS
+ $stmt = $this->db->prepare('SET SESSION SQL_BIG_SELECTS=1');
+ $stmt->execute();
+ $stmt->closeCursor();
+
+ // with MySQL 5.6 we ran into exceptions like:
+ // PDOException: SQLSTATE[42000]: Syntax error or access violation:
+ // 1140 In aggregated query without GROUP BY, expression #1 of SELECT list contains
+ // nonaggregated column 'testdb.T_0_0_0.p'; this is incompatible with sql_mode=only_full_group_by
+ //
+ // the following query makes this right.
+ // FYI: https://stackoverflow.com/questions/23921117/disable-only-full-group-by
+ $stmt = $this->db->prepare("SET sql_mode = ''");
+ $stmt->execute();
+ $stmt->closeCursor();
+ }
+
+ return $this->db;
+ }
+
+ /**
+ * @return void
+ */
+ public function disconnect()
+ {
+ // FYI: https://stackoverflow.com/questions/18277233/pdo-closing-connection
+ $this->db = null;
+ }
+
+ public function escape($value)
+ {
+ // quote surronds the string with ', but using trim aligns the result
+ return \trim($this->db->quote($value), "'");
+ }
+
+ /**
+ * @param string $sql
+ *
+ * @return array
+ */
+ public function fetchList($sql)
+ {
+ // save query
+ $this->queries[] = [
+ 'query' => $sql,
+ 'by_function' => 'fetchList'
+ ];
+
+ if (null == $this->db) {
+ $this->connect();
+ }
+
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute();
+ $rows = $stmt->fetchAll();
+ $stmt->closeCursor();
+
+ return $rows;
+ }
+
+ public function fetchRow($sql)
+ {
+ // save query
+ $this->queries[] = [
+ 'query' => $sql,
+ 'by_function' => 'fetchRow'
+ ];
+
+ if (null == $this->db) {
+ $this->connect();
+ }
+
+ $row = false;
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute();
+ $rows = $stmt->fetchAll();
+ if (0 < \count($rows)) {
+ $row = \array_values($rows)[0];
+ }
+ $stmt->closeCursor();
+
+ return $row;
+ }
+
+ public function getCollation()
+ {
+ $row = $this->fetchRow('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"');
+
+ if (isset($row['Collation'])) {
+ return $row['Collation'];
+ } else {
+ return '';
+ }
+ }
+
+ public function getConnection()
+ {
+ return $this->db;
+ }
+
+ public function getConnectionId()
+ {
+ return $this->db->query('SELECT CONNECTION_ID()')->fetch(\PDO::FETCH_ASSOC);
+ }
+
+ public function getDBSName()
+ {
+ if (null == $this->db) {
+ return;
+ }
+
+ $clientVersion = \strtolower($this->db->getAttribute(\PDO::ATTR_CLIENT_VERSION));
+ $serverVersion = \strtolower($this->db->getAttribute(\PDO::ATTR_SERVER_VERSION));
+ if (false !== \strpos($clientVersion, 'mariadb') || false !== \strpos($serverVersion, 'mariadb')) {
+ $return = 'mariadb';
+ } elseif (false !== \strpos($clientVersion, 'mysql') || false !== \strpos($serverVersion, 'mysql')) {
+ $return = 'mysql';
+ } else {
+ $return = null;
+ }
+
+ return $return;
+ }
+
+ public function getServerInfo()
+ {
+ return $this->db->getAttribute(\constant('PDO::ATTR_CLIENT_VERSION'));
+ }
+
+ /**
+ * Returns the version of the database server like 05-00-12
+ */
+ public function getServerVersion()
+ {
+ $res = \preg_match(
+ "/([0-9]+)\.([0-9]+)\.([0-9]+)/",
+ $this->getServerInfo(),
+ $matches
+ );
+
+ return 1 == $res
+ ? \sprintf('%02d-%02d-%02d', $matches[1], $matches[2], $matches[3])
+ : '00-00-00';
+ }
+
+ public function getErrorCode()
+ {
+ return $this->db->errorCode();
+ }
+
+ public function getErrorMessage()
+ {
+ return $this->db->errorInfo()[2];
+ }
+
+ public function getLastInsertId()
+ {
+ return $this->db->lastInsertId();
+ }
+
+ public function getNumberOfRows($sql)
+ {
+ // save query
+ $this->queries[] = [
+ 'query' => $sql,
+ 'by_function' => 'getNumberOfRows'
+ ];
+
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute();
+ $rowCount = \count($stmt->fetchAll());
+ $stmt->closeCursor();
+ return $rowCount;
+ }
+
+ public function getStoreName()
+ {
+ if (isset($this->configuration['store_name'])) {
+ return $this->configuration['store_name'];
+ }
+
+ return 'arc';
+ }
+
+ public function getTablePrefix()
+ {
+ $prefix = '';
+ if (isset($this->configuration['db_table_prefix'])) {
+ $prefix = $this->configuration['db_table_prefix'].'_';
+ }
+
+ $prefix .= $this->getStoreName().'_';
+ return $prefix;
+ }
+
+ /**
+ * @param string $sql Query
+ *
+ * @return bool True if query ran fine, false otherwise.
+ */
+ public function simpleQuery($sql)
+ {
+ // save query
+ $this->queries[] = [
+ 'query' => $sql,
+ 'by_function' => 'simpleQuery'
+ ];
+
+ if (false === $this->db instanceof \PDO) {
+ $this->connect();
+ }
+
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute();
+ $stmt->closeCursor();
+ return true;
+ }
+
+ /**
+ * Encapsulates internal PDO::exec call. This allows us to extend it, e.g. with caching functionality.
+ *
+ * @param string $sql
+ *
+ * @return int Number of affected rows.
+ */
+ public function exec($sql)
+ {
+ // save query
+ $this->queries[] = [
+ 'query' => $sql,
+ 'by_function' => 'exec'
+ ];
+
+ return $this->db->exec($sql);
+ }
+}
diff --git a/src/ARC2/Store/Adapter/mysqliAdapter.php b/src/ARC2/Store/Adapter/mysqliAdapter.php
new file mode 100644
index 00000000..adaf0135
--- /dev/null
+++ b/src/ARC2/Store/Adapter/mysqliAdapter.php
@@ -0,0 +1,255 @@
+
+ * @author Konrad Abicht
+ * @license W3C Software License and GPL
+ * @homepage
+ */
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * mysqli Adapter - Handles database operations using mysqli.
+ */
+class mysqliAdapter extends AbstractAdapter
+{
+ protected $last_result;
+
+ public function checkRequirements()
+ {
+ if (false == \extension_loaded('mysqli') || false == \function_exists('mysqli_connect')) {
+ throw new \Exception('Extension mysqli is not loaded or function mysqli_connect is not available.');
+ }
+ }
+
+ public function getAdapterName()
+ {
+ return 'mysqli';
+ }
+
+ /**
+ * Connect to server or storing a given connection.
+ *
+ * @return string|MysqliDbExtended String if an error occoured, instance of MysqliDbExtended otherwise.
+ */
+ public function connect($existingConnection = null)
+ {
+ // reuse a given existing connection.
+ // it assumes that $existingConnection is a mysqli connection object
+ if (null !== $existingConnection) {
+ $this->db = new MysqliDbExtended($existingConnection);
+
+ // create your own connection
+ } elseif (null == $this->db) {
+ // connect
+ try {
+ $this->db = new MysqliDbExtended(
+ $this->configuration['db_host'],
+ $this->configuration['db_user'],
+ $this->configuration['db_pwd']
+ );
+ } catch (\Exception $e) {
+ return $e->getMessage();
+ }
+ }
+
+ if (isset($this->configuration['db_name'])
+ && true !== $this->db->simpleQuery('USE `'.$this->configuration['db_name'].'`')) {
+ $fixed = 0;
+ /* try to create it */
+ if ($this->configuration['db_name']) {
+ $this->db->simpleQuery('
+ CREATE DATABASE IF NOT EXISTS `'.$this->configuration['db_name'].'`
+ DEFAULT CHARACTER SET utf8
+ DEFAULT COLLATE utf8_general_ci
+ '
+ );
+ if ($this->db->simpleQuery('USE `'.$this->configuration['db_name'].'`')) {
+ $this->db->simpleQuery("SET NAMES 'utf8'");
+ $fixed = 1;
+ }
+ }
+ if (!$fixed) {
+ return $this->addError($this->db->getErrorMessage());
+ } else {
+ if (preg_match('/^utf8/', $this->getCollation())) {
+ $this->db->simpleQuery("SET NAMES 'utf8'");
+ }
+ // This is RDF, we may need many JOINs...
+ $this->db->simpleQuery('SET SESSION SQL_BIG_SELECTS=1');
+ }
+ }
+
+ return $this->db;
+ }
+
+ public function disconnect()
+ {
+ return $this->db->disconnect();
+ }
+
+ public function escape($value)
+ {
+ return $this->db->escape($value);
+ }
+
+ public function fetchList($sql)
+ {
+ return $this->db->rawQuery($sql);
+ }
+
+ public function fetchRow($sql)
+ {
+ $row = $this->db->rawQueryOne($sql);
+
+ return null != $row ? $row : false;
+ }
+
+ public function getCollation()
+ {
+ $row = $this->fetchRow('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"');
+
+ if (isset($row['Collation'])) {
+ return $row['Collation'];
+ } else {
+ return '';
+ }
+ }
+
+ public function getConnectionId()
+ {
+ if (null != $this->db) {
+ return $this->db->mysqli()->thread_id;
+ }
+ }
+
+ /**
+ * For backward compatibility reasons. Get mysqli connection object.
+ *
+ * @return mysqli
+ */
+ public function getConnection()
+ {
+ return $this->db->mysqli();
+ }
+
+ public function getDBSName()
+ {
+ if (null == $this->db) {
+ return null;
+ }
+
+ return false !== strpos($this->getServerInfo(), 'MariaDB')
+ ? 'mariadb'
+ : 'mysql';
+ }
+
+ public function getLastInsertId()
+ {
+ if (null != $this->db) {
+ return $this->db->getLastInsertId();
+ }
+
+ return 'No database connection (mysqliAdapter).';
+ }
+
+ public function getServerInfo()
+ {
+ $this->connect();
+
+ return $this->db->mysqli()->server_info;
+ }
+
+ /**
+ * Returns the version of the database server like 05-00-12
+ */
+ public function getServerVersion()
+ {
+ $res = preg_match(
+ "/([0-9]+)\.([0-9]+)\.([0-9]+)/",
+ $this->getServerInfo(),
+ $matches
+ );
+
+ return 1 == $res
+ ? sprintf('%02d-%02d-%02d', $matches[1], $matches[2], $matches[3])
+ : '00-00-00';
+ }
+
+ public function getErrorMessage()
+ {
+ return $this->db->getErrorMessage();
+ }
+
+ public function getErrorCode()
+ {
+ return $this->db->getErrorCode();
+ }
+
+ public function getNumberOfRows($sql)
+ {
+ return $this->db->getNumberOfRows($sql);
+ }
+
+ public function getStoreName()
+ {
+ if (isset($this->configuration['store_name'])) {
+ return $this->configuration['store_name'];
+ }
+
+ return 'arc';
+ }
+
+ public function getTablePrefix()
+ {
+ $prefix = '';
+ if (isset($this->configuration['db_table_prefix'])) {
+ $prefix = $this->configuration['db_table_prefix'].'_';
+ }
+
+ $prefix .= $this->getStoreName().'_';
+ return $prefix;
+ }
+
+ /**
+ * For compatibility reasons. Executes a query using mysqli and returns the result. Dont use
+ * this function directly. It is only used once to make sure, ARC2 keeps its backward compatibility
+ * while in the 2.x branch.
+ *
+ * @param string $sql Query to execute.
+ *
+ * @return mysqli result|false
+ */
+ public function mysqliQuery($sql)
+ {
+ return $this->db->mysqliQuery($sql);
+ }
+
+ /**
+ * @param string $sql Query
+ *
+ * @return bool True if query ran fine, false otherwise.
+ */
+ public function simpleQuery($sql)
+ {
+ if (null == $this->db) {
+ $this->connect();
+ }
+
+ return $this->db->simpleQuery($sql);
+ }
+
+ /**
+ * @param string $sql Query with return of affected rows
+ *
+ * @return bool True if query ran fine, false otherwise.
+ */
+ public function exec($sql)
+ {
+ $this->db->simpleQuery($sql);
+ return $this->db->getAffectedRows();
+ }
+}
diff --git a/store/ARC2_Store.php b/store/ARC2_Store.php
index 52aea8b2..3e40d5fd 100644
--- a/store/ARC2_Store.php
+++ b/store/ARC2_Store.php
@@ -10,13 +10,16 @@
class ARC2_Store extends ARC2_Class
{
+ protected $cache;
+ protected $db;
+
public function __construct($a, &$caller)
{
parent::__construct($a, $caller);
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->table_lock = 0;
$this->triggers = $this->v('store_triggers', [], $this->a);
@@ -24,6 +27,27 @@ public function __init()
$this->is_win = ('win' == strtolower(substr(PHP_OS, 0, 3))) ? true : false;
$this->max_split_tables = $this->v('store_max_split_tables', 10, $this->a);
$this->split_predicates = $this->v('store_split_predicates', [], $this->a);
+
+ /*
+ * setup cache instance, if required by the user.
+ */
+ if (isset($this->a['cache_enabled']) && true === $this->a['cache_enabled']) {
+ // reuse existing cache instance, if it implements Psr\SimpleCache\CacheInterface
+ if (isset($this->a['cache_instance'])
+ && $this->a['cache_instance'] instanceof \Psr\SimpleCache\CacheInterface) {
+ $this->cache = $this->a['cache_instance'];
+
+ // create new cache instance
+ } else {
+ // FYI: https://symfony.com/doc/current/components/cache/adapters/filesystem_adapter.html
+ $this->cache = new \Symfony\Component\Cache\Simple\FilesystemCache('arc2', 0, null);
+ }
+ }
+ }
+
+ public function cacheEnabled()
+ {
+ return isset($this->a['cache_enabled']) && true === $this->a['cache_enabled'];
}
public function getName()
@@ -45,53 +69,65 @@ public function getTablePrefix()
public function createDBCon()
{
+ // build connection credential array
foreach (['db_host' => 'localhost', 'db_user' => '', 'db_pwd' => '', 'db_name' => ''] as $k => $v) {
$this->a[$k] = $this->v($k, $v, $this->a);
}
- if (!$db_con = mysqli_connect($this->a['db_host'], $this->a['db_user'], $this->a['db_pwd'])) {
- return $this->addError(mysqli_error($db_con));
- }
- $this->a['db_con'] = $db_con;
- if (!mysqli_query($db_con, 'USE `'.$this->a['db_name'].'`')) {
- $fixed = 0;
- /* try to create it */
- if ($this->a['db_name']) {
- $this->queryDB('
- CREATE DATABASE IF NOT EXISTS `'.$this->a['db_name'].'`
- DEFAULT CHARACTER SET utf8
- DEFAULT COLLATE utf8_general_ci
- ', $db_con, 1
- );
- if (mysqli_query($db_con, 'USE `'.$this->a['db_name'].'`')) {
- $this->queryDB("SET NAMES 'utf8'", $db_con);
- $fixed = 1;
- }
+
+ // connect
+ try {
+ if (false === class_exists('\\ARC2\\Store\\Adapter\\AdapterFactory')) {
+ require __DIR__.'/../src/ARC2/Store/Adapter/AdapterFactory.php';
}
- if (!$fixed) {
- return $this->addError(mysqli_error($db_con));
+ if (false == isset($this->a['db_adapter'])) {
+ $this->a['db_adapter'] = 'mysqli';
}
+ $factory = new \ARC2\Store\Adapter\AdapterFactory();
+ $this->db = $factory->getInstanceFor($this->a['db_adapter'], $this->a);
+ $err = $this->db->connect();
+ // stop here, if an error occoured
+ if (is_string($err) && false !== empty($err)) {
+ throw new \Exception($err);
+ }
+ } catch (\Exception $e) {
+ return $this->addError($e->getMessage());
}
- if (preg_match('/^utf8/', $this->getCollation())) {
- $this->queryDB("SET NAMES 'utf8'", $db_con);
+
+ if ('mysqli' == $this->db->getAdapterName()) {
+ $this->a['db_con'] = $this->db->getConnection();
}
- // This is RDF, we may need many JOINs...
- $this->queryDB('SET SESSION SQL_BIG_SELECTS=1', $db_con);
+
+ $this->a['db_object'] = $this->db;
return true;
}
+ public function getDBObject()
+ {
+ return $this->db;
+ }
+
+ /**
+ * @param int $force 1 if you want to force a connection.
+ *
+ * @return mysqli mysqli-connection, only if mysqli adapter was selected. null otherwise,
+ * because direct access to DB connection is not recommended.
+ */
public function getDBCon($force = 0)
{
- if ($force || !isset($this->a['db_con'])) {
+ if ($force || !isset($this->a['db_object'])) {
if (!$this->createDBCon()) {
return false;
}
}
- if (!$force && !mysqli_thread_id($this->a['db_con'])) {
- return $this->getDBCon(1);
- }
- return $this->a['db_con'];
+ if ('mysqli' == $this->a['db_adapter']) {
+ // for backward compatibility reasons only.
+ // TODO remove that in 3.x
+ return $this->a['db_con'];
+ } else {
+ return true;
+ }
}
/**
@@ -99,34 +135,51 @@ public function getDBCon($force = 0)
*/
public function closeDBCon()
{
- if ($this->v('db_con', false, $this->a)) {
- mysqli_close($this->a['db_con']);
+ if (isset($this->a['db_object'])) {
+ $this->db->disconnect();
}
unset($this->a['db_con']);
+ unset($this->a['db_object']);
}
public function getDBVersion()
{
if (!$this->v('db_version')) {
- $this->db_version = preg_match("/^([0-9]+)\.([0-9]+)\.([0-9]+)/", mysqli_get_server_info($this->getDBCon()), $m) ? sprintf('%02d-%02d-%02d', $m[1], $m[2], $m[3]) : '00-00-00';
+ // connect, if no connection available
+ if (null == $this->db) {
+ $this->createDBCon();
+ }
+
+ $this->db_version = $this->db->getServerVersion();
}
return $this->db_version;
}
- public function getCollation()
+ /**
+ * @return string Returns DBS name. Possible values: mysql, mariadb
+ */
+ public function getDBSName()
{
- $rs = $this->queryDB('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"', $this->getDBCon());
+ return $this->db->getDBSName();
+ }
- return ($rs && ($row = mysqli_fetch_array($rs)) && isset($row['Collation'])) ? $row['Collation'] : '';
+ public function getCollation()
+ {
+ $row = $this->db->fetchRow('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"');
+ return isset($row['Collation']) ? $row['Collation'] : '';
}
public function getColumnType()
{
if (!$this->v('column_type')) {
$tbl = $this->getTablePrefix().'g2t';
- $rs = $this->queryDB('SHOW COLUMNS FROM '.$tbl.' LIKE "t"', $this->getDBCon());
- $row = $rs ? mysqli_fetch_array($rs) : ['Type' => 'mediumint'];
+
+ $row = $this->db->fetchRow('SHOW COLUMNS FROM '.$tbl.' LIKE "t"');
+ if (null == $row) {
+ $row = ['Type' => 'mediumint'];
+ }
+
$this->column_type = preg_match('/mediumint/', $row['Type']) ? 'mediumint' : 'int';
}
@@ -138,8 +191,9 @@ public function hasHashColumn($tbl)
$var_name = 'has_hash_column_'.$tbl;
if (!isset($this->$var_name)) {
$tbl = $this->getTablePrefix().$tbl;
- $rs = $this->queryDB('SHOW COLUMNS FROM '.$tbl.' LIKE "val_hash"', $this->getDBCon());
- $this->$var_name = ($rs && mysqli_fetch_array($rs));
+
+ $row = $this->db->fetchRow('SHOW COLUMNS FROM '.$tbl.' LIKE "val_hash"');
+ $this->$var_name = null !== $row;
}
return $this->$var_name;
@@ -150,8 +204,9 @@ public function hasFulltextIndex()
if (!isset($this->has_fulltext_index)) {
$this->has_fulltext_index = 0;
$tbl = $this->getTablePrefix().'o2val';
- $rs = $this->queryDB('SHOW INDEX FROM '.$tbl, $this->getDBCon());
- while ($row = mysqli_fetch_array($rs)) {
+
+ $rows = $this->db->fetchList('SHOW INDEX FROM '.$tbl);
+ foreach($rows as $row) {
if ('val' != $row['Column_name']) {
continue;
}
@@ -172,7 +227,7 @@ public function enableFulltextSearch()
return 1;
}
$tbl = $this->getTablePrefix().'o2val';
- $this->queryDB('CREATE FULLTEXT INDEX vft ON '.$tbl.'(val(128))', $this->getDBCon(), 1);
+ $this->db->simpleQuery('CREATE FULLTEXT INDEX vft ON '.$tbl.'(val(128))');
}
public function disableFulltextSearch()
@@ -181,24 +236,29 @@ public function disableFulltextSearch()
return 1;
}
$tbl = $this->getTablePrefix().'o2val';
- $this->queryDB('DROP INDEX vft ON '.$tbl, $this->getDBCon());
+ $this->db->simpleQuery('DROP INDEX vft ON '.$tbl);
}
public function countDBProcesses()
{
- return ($rs = $this->queryDB('SHOW PROCESSLIST', $this->getDBCon())) ? mysqli_num_rows($rs) : 0;
+ return $this->db->getNumberOfRows('SHOW PROCESSLIST');
}
+ /**
+ * Manipulating database processes using ARC2 is discouraged.
+ *
+ * @deprecated
+ */
public function killDBProcesses($needle = '', $runtime = 30)
{
- $dbcon = $this->getDBCon();
/* make sure needle is sql */
if (preg_match('/\?.+ WHERE/i', $needle, $m)) {
$needle = $this->query($needle, 'sql');
}
- $rs = $this->queryDB('SHOW FULL PROCESSLIST', $dbcon);
$ref_tbl = $this->getTablePrefix().'triple';
- while ($row = mysqli_fetch_array($rs)) {
+
+ $rows = $this->db->fetchList('SHOW FULL PROCESSLIST');
+ foreach ($rows as $row) {
if ($row['Time'] < $runtime) {
continue;
}
@@ -218,7 +278,7 @@ public function killDBProcesses($needle = '', $runtime = 30)
if (!$kill) {
continue;
}
- $this->queryDB('KILL '.$row['Id'], $dbcon);
+ $this->db->simpleQuery('KILL '.$row['Id']);
}
}
@@ -229,20 +289,25 @@ public function getTables()
public function isSetUp()
{
- if (($con = $this->getDBCon())) {
+ if (null !== $this->db) {
$tbl = $this->getTablePrefix().'setting';
- return $this->queryDB('SELECT 1 FROM '.$tbl.' LIMIT 0', $con) ? 1 : 0;
+ try {
+ // mysqli way
+ return $this->db->simpleQuery('SELECT 1 FROM '.$tbl.' LIMIT 0') ? 1 : 0;
+ } catch (\Exception $e) {
+ // when using PDO, an exception gets thrown if $tbl does not exist.
+ $this->errors[] = $e->getMessage();
+ return 0;
+ }
}
+
+ return 0;
}
public function setUp($force = 0)
{
- if (($force || !$this->isSetUp()) && ($con = $this->getDBCon())) {
- if ($this->getDBVersion() < '04-00-04') {
- /* UPDATE + JOINs */
- return $this->addError('MySQL version not supported. ARC requires version 4.0.4 or higher.');
- }
+ if (($force || !$this->isSetUp()) && false !== $this->getDBCon()) {
ARC2::inc('StoreTableManager');
$mgr = new ARC2_StoreTableManager($this->a, $this);
$mgr->createTables();
@@ -266,19 +331,26 @@ public function splitTables()
public function hasSetting($k)
{
+ if (null == $this->db) {
+ $this->createDBCon();
+ }
+
$tbl = $this->getTablePrefix().'setting';
- $sql = 'SELECT val FROM '.$tbl." WHERE k = '".md5($k)."'";
- $rs = $this->queryDB($sql, $this->getDBCon());
- return ($rs && ($row = mysqli_fetch_array($rs))) ? 1 : 0;
+ return $this->db->fetchRow('SELECT val FROM '.$tbl." WHERE k = '".md5($k)."'")
+ ? 1
+ : 0;
}
public function getSetting($k, $default = 0)
{
+ if (null == $this->db) {
+ $this->createDBCon();
+ }
+
$tbl = $this->getTablePrefix().'setting';
- $sql = 'SELECT val FROM '.$tbl." WHERE k = '".md5($k)."'";
- $rs = $this->queryDB($sql, $this->getDBCon());
- if ($rs && ($row = mysqli_fetch_array($rs))) {
+ $row = $this->db->fetchRow('SELECT val FROM '.$tbl." WHERE k = '".md5($k)."'");
+ if (isset($row['val'])) {
return unserialize($row['val']);
}
@@ -287,22 +359,21 @@ public function getSetting($k, $default = 0)
public function setSetting($k, $v)
{
- $con = $this->getDBCon();
$tbl = $this->getTablePrefix().'setting';
if ($this->hasSetting($k)) {
- $sql = 'UPDATE '.$tbl." SET val = '".mysqli_real_escape_string($con, serialize($v))."' WHERE k = '".md5($k)."'";
+ $sql = 'UPDATE '.$tbl." SET val = '".$this->db->escape(serialize($v))."' WHERE k = '".md5($k)."'";
} else {
- $sql = 'INSERT INTO '.$tbl." (k, val) VALUES ('".md5($k)."', '".mysqli_real_escape_string($con, serialize($v))."')";
+ $sql = 'INSERT INTO '.$tbl." (k, val) VALUES ('".md5($k)."', '".$this->db->escape(serialize($v))."')";
}
- return $this->queryDB($sql, $con);
+ return $this->db->simpleQuery($sql);
}
public function removeSetting($k)
{
$tbl = $this->getTablePrefix().'setting';
- return $this->queryDB('DELETE FROM '.$tbl." WHERE k = '".md5($k)."'", $this->getDBCon());
+ return $this->db->simpleQuery('DELETE FROM '.$tbl." WHERE k = '".md5($k)."'");
}
public function getQueueTicket()
@@ -311,14 +382,13 @@ public function getQueueTicket()
return 1;
}
$t = 'ticket_'.substr(md5(uniqid(rand())), 0, 10);
- $con = $this->getDBCon();
/* lock */
- $rs = $this->queryDB('LOCK TABLES '.$this->getTablePrefix().'setting WRITE', $con);
+ $this->db->simpleQuery('LOCK TABLES '.$this->getTablePrefix().'setting WRITE');
/* queue */
$queue = $this->getSetting('query_queue', []);
$queue[] = $t;
$this->setSetting('query_queue', $queue);
- $this->queryDB('UNLOCK TABLES', $con);
+ $this->db->simpleQuery('UNLOCK TABLES');
/* loop */
$lc = 0;
$queue = $this->getSetting('query_queue', []);
@@ -341,27 +411,25 @@ public function removeQueueTicket($t)
if (!$this->queue_queries) {
return 1;
}
- $con = $this->getDBCon();
/* lock */
- $this->queryDB('LOCK TABLES '.$this->getTablePrefix().'setting WRITE', $con);
+ $this->db->simpleQuery('LOCK TABLES '.$this->getTablePrefix().'setting WRITE');
/* queue */
$vals = $this->getSetting('query_queue', []);
$pos = array_search($t, $vals);
$queue = ($pos < (count($vals) - 1)) ? array_slice($vals, $pos + 1) : [];
$this->setSetting('query_queue', $queue);
- $this->queryDB('UNLOCK TABLES', $con);
+ $this->db->simpleQuery('UNLOCK TABLES');
}
public function reset($keep_settings = 0)
{
- $con = $this->getDBCon();
$tbls = $this->getTables();
$prefix = $this->getTablePrefix();
/* remove split tables */
$ps = $this->getSetting('split_predicates', []);
foreach ($ps as $p) {
$tbl = 'triple_'.abs(crc32($p));
- $this->queryDB('DROP TABLE '.$prefix.$tbl, $con);
+ $this->db->simpleQuery('DROP TABLE '.$prefix.$tbl);
}
$this->removeSetting('split_predicates');
/* truncate tables */
@@ -369,17 +437,20 @@ public function reset($keep_settings = 0)
if ($keep_settings && ('setting' == $tbl)) {
continue;
}
- $this->queryDB('TRUNCATE '.$prefix.$tbl, $con);
+ $this->db->simpleQuery('TRUNCATE '.$prefix.$tbl);
}
}
public function drop()
{
- $con = $this->getDBCon();
- $tbls = $this->getTables();
+ if (null == $this->db) {
+ $this->createDBCon();
+ }
+
$prefix = $this->getTablePrefix();
+ $tbls = $this->getTables();
foreach ($tbls as $tbl) {
- $this->queryDB('DROP TABLE '.$prefix.$tbl, $con);
+ $this->db->simpleQuery('DROP TABLE IF EXISTS '.$prefix.$tbl);
}
}
@@ -429,17 +500,15 @@ public function createBackup($path, $q = '')
public function renameTo($name)
{
- $con = $this->getDBCon();
$tbls = $this->getTables();
$old_prefix = $this->getTablePrefix();
$new_prefix = $this->v('db_table_prefix', '', $this->a);
$new_prefix .= $new_prefix ? '_' : '';
$new_prefix .= $name.'_';
foreach ($tbls as $tbl) {
- $rs = $this->queryDB('RENAME TABLE '.$old_prefix.$tbl.' TO '.$new_prefix.$tbl, $con);
- $err = mysqli_error($con);
- if (!empty($err)) {
- return $this->addError($err);
+ $this->db->simpleQuery('RENAME TABLE '.$old_prefix.$tbl.' TO '.$new_prefix.$tbl);
+ if (!empty($this->db->getErrorMessage())) {
+ return $this->addError($this->db->getErrorMessage());
}
}
$this->a['store_name'] = $name;
@@ -452,48 +521,89 @@ public function replicateTo($name)
$new_store = ARC2::getStore($conf);
$new_store->setUp();
$new_store->reset();
- $con = $this->getDBCon();
$tbls = $this->getTables();
$old_prefix = $this->getTablePrefix();
$new_prefix = $new_store->getTablePrefix();
foreach ($tbls as $tbl) {
- $rs = $this->queryDB('INSERT IGNORE INTO '.$new_prefix.$tbl.' SELECT * FROM '.$old_prefix.$tbl, $con);
- $err = mysqli_error($con);
- if (!empty($err)) {
- return $this->addError($err);
+ $this->db->simpleQuery('INSERT IGNORE INTO '.$new_prefix.$tbl.' SELECT * FROM '.$old_prefix.$tbl);
+ if (!empty($this->db->getErrorMessage())) {
+ return $this->addError($this->db->getErrorMessage());
}
}
return $new_store->query('SELECT COUNT(*) AS t_count WHERE { ?s ?p ?o}', 'row');
}
+ /**
+ * Executes a SPARQL query.
+ *
+ * @param string $q SPARQL query
+ * @param string $result_format Possible values: infos, raw, rows, row
+ * @param string $src
+ * @param int $keep_bnode_ids Keep blank node IDs? Default is 0
+ * @param int $log_query Log executed queries? Default is 0
+ *
+ * @return array|int Array if query returned a result, 0 otherwise.
+ */
public function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0)
{
if ($log_query) {
$this->logQuery($q);
}
- $con = $this->getDBCon();
if (preg_match('/^dump/i', $q)) {
$infos = ['query' => ['type' => 'dump']];
} else {
- ARC2::inc('SPARQLPlusParser');
- $p = new ARC2_SPARQLPlusParser($this->a, $this);
- $p->parse($q, $src);
- $infos = $p->getQueryInfos();
+ // check cache
+ $key = \hash('sha1', $q);
+ if ($this->cacheEnabled() && $this->cache->has($key.'_infos')) {
+ $infos = $this->cache->get($key.'_infos');
+ $errors = $this->cache->get($key.'_errors');
+ // no entry found
+ } else {
+ ARC2::inc('SPARQLPlusParser');
+ $p = new ARC2_SPARQLPlusParser($this->a, $this);
+ $p->parse($q, $src);
+ $infos = $p->getQueryInfos();
+ $errors = $p->getErrors();
+
+ // store result in cache
+ if ($this->cacheEnabled()) {
+ $this->cache->set($key.'_infos', $infos);
+ $this->cache->set($key.'_errors', $errors);
+ }
+ }
}
+
if ('infos' == $result_format) {
return $infos;
}
+
$infos['result_format'] = $result_format;
- if (!isset($p) || !$p->getErrors()) {
+
+ if (!isset($p) || 0 == count($errors)) {
$qt = $infos['query']['type'];
if (!in_array($qt, ['select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'])) {
return $this->addError('Unsupported query type "'.$qt.'"');
}
$t1 = ARC2::mtime();
- $r = ['query_type' => $qt, 'result' => $this->runQuery($infos, $qt, $keep_bnode_ids, $q)];
- $t2 = ARC2::mtime();
- $r['query_time'] = $t2 - $t1;
+
+ // if cache is enabled, get/store result
+ $key = \hash('sha1', $q);
+ if ($this->cacheEnabled() && $this->cache->has($key)) {
+ $result = $this->cache->get($key);
+
+ } else {
+ $result = $this->runQuery($infos, $qt, $keep_bnode_ids, $q);
+
+ // store in cache, if enabled
+ if ($this->cacheEnabled()) {
+ $this->cache->set($key, $result);
+ }
+ }
+
+ $r = ['query_type' => $qt, 'result' => $result];
+ $r['query_time'] = ARC2::mtime() - $t1;
+
/* query result */
if ('raw' == $result_format) {
return $r['result'];
@@ -511,8 +621,16 @@ public function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $
return 0;
}
+ /**
+ * Runs a SPARQL query. Dont use this function directly, use query instead.
+ */
public function runQuery($infos, $type, $keep_bnode_ids = 0, $q = '')
{
+ // invalidate cache, if enabled and a query is executed, which changes the store
+ if ($this->cacheEnabled() && in_array($type, ['load', 'insert', 'delete'])) {
+ $this->cache->clear();
+ }
+
ARC2::inc('Store'.ucfirst($type).'QueryHandler');
$cls = 'ARC2_Store'.ucfirst($type).'QueryHandler';
$h = new $cls($this->a, $this);
@@ -588,18 +706,15 @@ public function getTermID($val, $term = '')
if ((strlen($val) < 100) && isset($this->term_id_cache[$term][$val])) {
return $this->term_id_cache[$term][$val];
}
- $con = $this->getDBCon();
$r = 0;
/* via hash */
if (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
- $sql = 'SELECT id, val FROM '.$this->getTablePrefix().$tbl." WHERE val_hash = '".$this->getValueHash($val)."' ORDER BY id";
- $rs = $this->queryDB($sql, $con);
- if (!$rs || !mysqli_num_rows($rs)) {// try 32 bit version
- $sql = 'SELECT id, val FROM '.$this->getTablePrefix().$tbl." WHERE val_hash = '".$this->getValueHash($val, true)."' ORDER BY id";
- $rs = $this->queryDB($sql, $con);
- }
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs)) {
- while ($row = mysqli_fetch_array($rs)) {
+
+ $rows = $this->db->fetchList(
+ 'SELECT id, val FROM '.$this->getTablePrefix().$tbl." WHERE val_hash = '".$this->getValueHash($val)."' ORDER BY id"
+ );
+ if (is_array($rows) && 0 < count($rows)) {
+ foreach($rows as $row) {
if ($row['val'] == $val) {
$r = $row['id'];
break;
@@ -609,8 +724,10 @@ public function getTermID($val, $term = '')
}
/* exact match */
else {
- $sql = 'SELECT id FROM '.$this->getTablePrefix().$tbl." WHERE val = BINARY '".mysqli_real_escape_string($con, $val)."' LIMIT 1";
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs) && ($row = mysqli_fetch_array($rs))) {
+ $sql = 'SELECT id FROM '.$this->getTablePrefix().$tbl." WHERE val = BINARY '".$this->db->escape($val)."' LIMIT 1";
+ $row = $this->db->fetchRow($sql);
+
+ if (null !== $row && isset($row['id'])) {
$r = $row['id'];
}
}
@@ -624,9 +741,10 @@ public function getTermID($val, $term = '')
public function getIDValue($id, $term = '')
{
$tbl = preg_match('/^(s|o)$/', $term) ? $term.'2val' : 'id2val';
- $con = $this->getDBCon();
- $sql = 'SELECT val FROM '.$this->getTablePrefix().$tbl.' WHERE id = '.mysqli_real_escape_string($con, $id).' LIMIT 1';
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs) && ($row = mysqli_fetch_array($rs))) {
+ $row = $this->db->fetchRow(
+ 'SELECT val FROM '.$this->getTablePrefix().$tbl.' WHERE id = '.$this->db->escape($id).' LIMIT 1'
+ );
+ if (isset($row['val'])) {
return $row['val'];
}
@@ -638,11 +756,11 @@ public function getLock($t_out = 10, $t_out_init = '')
if (!$t_out_init) {
$t_out_init = $t_out;
}
- $con = $this->getDBCon();
+
$l_name = $this->a['db_name'].'.'.$this->getTablePrefix().'.write_lock';
- $rs = $this->queryDB('SELECT IS_FREE_LOCK("'.$l_name.'") AS success', $con);
- if ($rs) {
- $row = mysqli_fetch_array($rs);
+ $row = $this->db->fetchRow('SELECT IS_FREE_LOCK("'.$l_name.'") AS success');
+
+ if (is_array($row)) {
if (!$row['success']) {
if ($t_out) {
sleep(1);
@@ -650,10 +768,8 @@ public function getLock($t_out = 10, $t_out_init = '')
return $this->getLock($t_out - 1, $t_out_init);
}
} else {
- $rs = $this->queryDB('SELECT GET_LOCK("'.$l_name.'", '.$t_out_init.') AS success', $con);
- if ($rs) {
- $row = mysqli_fetch_array($rs);
-
+ $row = $this->db->fetchRow('SELECT GET_LOCK("'.$l_name.'", '.$t_out_init.') AS success');
+ if (isset($row['success'])) {
return $row['success'];
}
}
@@ -664,14 +780,17 @@ public function getLock($t_out = 10, $t_out_init = '')
public function releaseLock()
{
- $con = $this->getDBCon();
-
- return $this->queryDB('DO RELEASE_LOCK("'.$this->a['db_name'].'.'.$this->getTablePrefix().'.write_lock")', $con);
+ return $this->db->simpleQuery('DO RELEASE_LOCK("'.$this->a['db_name'].'.'.$this->getTablePrefix().'.write_lock")');
}
public function processTables($level = 2, $operation = 'optimize')
- {/* 1: triple + g2t, 2: triple + *2val, 3: all tables */
- $con = $this->getDBCon();
+ {
+ /*
+ * level:
+ * 1. triple + g2t
+ * 2. triple + *2val
+ * 3. all tables
+ */
$pre = $this->getTablePrefix();
$tbls = $this->getTables();
$sql = '';
@@ -685,10 +804,9 @@ public function processTables($level = 2, $operation = 'optimize')
$sql .= $sql ? ', ' : strtoupper($operation).' TABLE ';
$sql .= $pre.$tbl;
}
- $this->queryDB($sql, $con);
- $err = mysqli_error($con);
- if (!empty($err)) {
- $this->addError($err.' in '.$sql);
+ $this->db->simpleQuery($sql);
+ if (false == empty($this->db->getErrorMessage())) {
+ $this->addError($this->db->getErrorMessage().' in '.$sql);
}
}
@@ -719,39 +837,46 @@ public function changeNamespaceURI($old_uri, $new_uri)
return $c->changeNamespaceURI($old_uri, $new_uri);
}
+ /**
+ * @param string $res URI
+ * @param string $unnamed_label How to label a resource without a name?
+ *
+ * @return string
+ */
public function getResourceLabel($res, $unnamed_label = 'An unnamed resource')
{
+ // init local label cache, if not set
if (!isset($this->resource_labels)) {
$this->resource_labels = [];
}
+ // if we already know the label for the given resource
if (isset($this->resource_labels[$res])) {
return $this->resource_labels[$res];
}
+ // if no URI was given, assume its a literal and return it
if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) {
return $res;
- } /* literal */
+ }
+
$ps = $this->getLabelProps();
if ($this->getSetting('store_label_properties', '-') != md5(serialize($ps))) {
$this->inferLabelProps($ps);
}
- //$sub_q .= $sub_q ? ' || ' : '';
- //$sub_q .= 'REGEX(str(?p), "(last_name|name|fn|title|label)$", "i")';
- $q = 'SELECT ?label WHERE { <'.$res.'> ?p ?label . ?p a } LIMIT 3';
- $r = '';
- $rows = $this->query($q, 'rows');
- foreach ($rows as $row) {
- $r = strlen($row['label']) > strlen($r) ? $row['label'] : $r;
- }
- if (!$r && preg_match('/^\_\:/', $res)) {
- return $unnamed_label;
+
+ foreach ($ps as $labelProperty) {
+ // send a query for each label property
+ $result = $this->query('SELECT ?label WHERE { <'.$res.'> <'.$labelProperty.'> ?label }');
+ if (isset($result['result']['rows'][0])) {
+ $this->resource_labels[$res] = $result['result']['rows'][0]['label'];
+ return $result['result']['rows'][0]['label'];
+ }
}
- $r = $r ? $r : preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+
+ $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
$r = str_replace('_', ' ', $r);
$r = preg_replace_callback('/([a-z])([A-Z])/', function ($matches) {
return $matches[1].' '.strtolower($matches[2]);
}, $r);
- $this->resource_labels[$res] = $r;
-
return $r;
}
diff --git a/store/ARC2_StoreAskQueryHandler.php b/store/ARC2_StoreAskQueryHandler.php
index ff402570..9458c8d3 100755
--- a/store/ARC2_StoreAskQueryHandler.php
+++ b/store/ARC2_StoreAskQueryHandler.php
@@ -18,7 +18,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
}
@@ -39,10 +39,8 @@ public function buildResultVars()
public function getFinalQueryResult($q_sql, $tmp_tbl)
{
- $con = $this->store->getDBCon();
- $rs = mysqli_query($con, 'SELECT success FROM '.$tmp_tbl);
- $r = ($row = mysqli_fetch_array($rs)) ? $row['success'] : 0;
-
+ $row = $this->store->a['db_object']->fetchRow('SELECT success FROM '.$tmp_tbl);
+ $r = isset($row['success']) ? $row['success'] : 0;
return $r ? true : false;
}
}
diff --git a/store/ARC2_StoreConstructQueryHandler.php b/store/ARC2_StoreConstructQueryHandler.php
index 54c292d4..8c7ca92f 100755
--- a/store/ARC2_StoreConstructQueryHandler.php
+++ b/store/ARC2_StoreConstructQueryHandler.php
@@ -18,7 +18,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
}
diff --git a/store/ARC2_StoreDeleteQueryHandler.php b/store/ARC2_StoreDeleteQueryHandler.php
index d7bcb04c..b8889809 100644
--- a/store/ARC2_StoreDeleteQueryHandler.php
+++ b/store/ARC2_StoreDeleteQueryHandler.php
@@ -16,7 +16,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
$this->handler_type = 'delete';
@@ -25,7 +25,6 @@ public function __init()
public function runQuery($infos)
{
$this->infos = $infos;
- $con = $this->store->getDBCon();
$t1 = ARC2::mtime();
/* delete */
$this->refs_deleted = false;
@@ -46,9 +45,13 @@ public function runQuery($infos)
if ($tc && ($this->refs_deleted || (1 == rand(1, 100)))) {
$this->cleanTableReferences();
}
+ // TODO What does this rand() call here? remove it and think about a cleaner way
+ // when to trigger optimizeTables
if ($tc && (1 == rand(1, 100))) {
$this->store->optimizeTables();
}
+ // TODO What does this rand() call here? remove it and think about a cleaner way
+ // when to trigger cleanValueTables
if ($tc && (1 == rand(1, 500))) {
$this->cleanValueTables();
}
@@ -67,11 +70,9 @@ public function deleteTargetGraphs()
{
$tbl_prefix = $this->store->getTablePrefix();
$r = 0;
- $con = $this->store->getDBCon();
foreach ($this->infos['query']['target_graphs'] as $g) {
if ($g_id = $this->getTermID($g, 'g')) {
- $rs = mysqli_query($con, 'DELETE FROM '.$tbl_prefix.'g2t WHERE g = '.$g_id);
- $r += mysqli_affected_rows($con);
+ $r += $this->store->a['db_object']->exec('DELETE FROM '.$tbl_prefix.'g2t WHERE g = '.$g_id);
}
}
$this->refs_deleted = $r ? 1 : 0;
@@ -84,7 +85,6 @@ public function deleteTriples()
$r = 0;
$dbv = $this->store->getDBVersion();
$tbl_prefix = $this->store->getTablePrefix();
- $con = $this->store->getDBCon();
/* graph restriction */
$tgs = $this->infos['query']['target_graphs'];
$gq = '';
@@ -120,7 +120,7 @@ public function deleteTriples()
if ($gq) {
$sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'g2t' : 'DELETE G';
$sql .= '
- FROM '.$tbl_prefix.'g2t G
+ FROM '.$tbl_prefix.'g2t G
JOIN '.$this->getTripleTable().' T ON (T.t = G.t'.$gq.')
WHERE '.$q.'
';
@@ -129,13 +129,10 @@ public function deleteTriples()
$sql = ($dbv < '04-01') ? 'DELETE '.$this->getTripleTable() : 'DELETE T';
$sql .= ' FROM '.$this->getTripleTable().' T WHERE '.$q;
}
- //$rs = mysql_query($sql, $con);
- $rs = $this->queryDB($sql, $con);
- $er = mysqli_error($con);
- if (!empty($er)) {
- $this->addError($er.' in '.$sql);
+ $r += $this->store->a['db_object']->exec($sql);
+ if (!empty($this->store->a['db_object']->getErrorMessage())) {
+ $this->addError($this->store->a['db_object']->getErrorMessage().' in '.$sql);
}
- $r += mysqli_affected_rows($con);
}
return $r;
@@ -159,7 +156,6 @@ public function cleanTableReferences()
if (!$this->store->getLock()) {
return $this->addError('Could not get lock in "cleanTableReferences"');
}
- $con = $this->store->getDBCon();
$tbl_prefix = $this->store->getTablePrefix();
$dbv = $this->store->getDBVersion();
/* check for unconnected triples */
@@ -167,32 +163,33 @@ public function cleanTableReferences()
SELECT T.t FROM '.$tbl_prefix.'triple T LEFT JOIN '.$tbl_prefix.'g2t G ON ( G.t = T.t )
WHERE G.t IS NULL LIMIT 1
';
- if (($rs = mysqli_query($con, $sql)) && mysqli_num_rows($rs)) {
+ $numRows = $this->store->a['db_object']->getNumberOfRows($sql);
+ if (0 < $numRows) {
/* delete unconnected triples */
$sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'triple' : 'DELETE T';
$sql .= '
- FROM '.$tbl_prefix.'triple T
+ FROM '.$tbl_prefix.'triple T
LEFT JOIN '.$tbl_prefix.'g2t G ON (G.t = T.t)
WHERE G.t IS NULL
';
- mysqli_query($con, $sql);
+ $this->store->a['db_object']->simpleQuery($sql);
}
/* check for unconnected graph refs */
if ((1 == rand(1, 10))) {
$sql = '
- SELECT G.g FROM '.$tbl_prefix.'g2t G LEFT JOIN '.$tbl_prefix.'triple T ON ( T.t = G.t )
- WHERE T.t IS NULL LIMIT 1
- ';
- if (($rs = mysqli_query($con, $sql)) && mysqli_num_rows($rs)) {
+ SELECT G.g FROM '.$tbl_prefix.'g2t G LEFT JOIN '.$tbl_prefix.'triple T ON ( T.t = G.t )
+ WHERE T.t IS NULL LIMIT 1
+ ';
+ if (0 < $this->store->a['db_object']->getNumberOfRows($sql)) {
/* delete unconnected graph refs */
$sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'g2t' : 'DELETE G';
$sql .= '
- FROM '.$tbl_prefix.'g2t G
- LEFT JOIN '.$tbl_prefix.'triple T ON (T.t = G.t)
- WHERE T.t IS NULL
- ';
- mysqli_query($con, $sql);
- }
+ FROM '.$tbl_prefix.'g2t G
+ LEFT JOIN '.$tbl_prefix.'triple T ON (T.t = G.t)
+ WHERE T.t IS NULL
+ ';
+ $this->store->a['db_object']->simpleQuery($sql);
+ }
}
/* release lock */
$this->store->releaseLock();
@@ -204,35 +201,39 @@ public function cleanValueTables()
if (!$this->store->getLock()) {
return $this->addError('Could not get lock in "cleanValueTables"');
}
- $con = $this->store->getDBCon();
$tbl_prefix = $this->store->getTablePrefix();
$dbv = $this->store->getDBVersion();
+
/* o2val */
$sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'o2val' : 'DELETE V';
$sql .= '
- FROM '.$tbl_prefix.'o2val V
+ FROM '.$tbl_prefix.'o2val V
LEFT JOIN '.$tbl_prefix.'triple T ON (T.o = V.id)
WHERE T.t IS NULL
';
- mysqli_query($con, $sql);
+ $this->store->a['db_object']->simpleQuery($sql);
+
/* s2val */
$sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'s2val' : 'DELETE V';
$sql .= '
- FROM '.$tbl_prefix.'s2val V
+ FROM '.$tbl_prefix.'s2val V
LEFT JOIN '.$tbl_prefix.'triple T ON (T.s = V.id)
WHERE T.t IS NULL
';
- mysqli_query($con, $sql);
+ $this->store->a['db_object']->simpleQuery($sql);
+
/* id2val */
$sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'id2val' : 'DELETE V';
$sql .= '
- FROM '.$tbl_prefix.'id2val V
+ FROM '.$tbl_prefix.'id2val V
LEFT JOIN '.$tbl_prefix.'g2t G ON (G.g = V.id)
LEFT JOIN '.$tbl_prefix.'triple T1 ON (T1.p = V.id)
LEFT JOIN '.$tbl_prefix.'triple T2 ON (T2.o_lang_dt = V.id)
WHERE G.g IS NULL AND T1.t IS NULL AND T2.t IS NULL
';
- //mysql_query($sql, $con);
+ // TODO was commented out before. could this be a problem?
+ $this->store->a['db_object']->simpleQuery($sql);
+
/* release lock */
$this->store->releaseLock();
}
diff --git a/store/ARC2_StoreDescribeQueryHandler.php b/store/ARC2_StoreDescribeQueryHandler.php
index a23e72a9..00dcb5ce 100644
--- a/store/ARC2_StoreDescribeQueryHandler.php
+++ b/store/ARC2_StoreDescribeQueryHandler.php
@@ -18,7 +18,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
$this->detect_labels = $this->v('detect_describe_query_labels', 0, $this->a);
diff --git a/store/ARC2_StoreDumpQueryHandler.php b/store/ARC2_StoreDumpQueryHandler.php
index 1be2d409..f00025f0 100755
--- a/store/ARC2_StoreDumpQueryHandler.php
+++ b/store/ARC2_StoreDumpQueryHandler.php
@@ -18,7 +18,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
}
@@ -26,7 +26,6 @@ public function __init()
public function runQuery($infos, $keep_bnode_ids = 0)
{
$this->infos = $infos;
- $con = $this->store->getDBCon();
ARC2::inc('StoreDumper');
$d = new ARC2_StoreDumper($this->a, $this->store);
$d->dumpSPOG();
diff --git a/store/ARC2_StoreDumper.php b/store/ARC2_StoreDumper.php
index 26595a53..471e174d 100755
--- a/store/ARC2_StoreDumper.php
+++ b/store/ARC2_StoreDumper.php
@@ -43,11 +43,11 @@ public function dumpSPOG()
$offset = 0;
do {
$proceed = 0;
- $rs = $this->getRecordset($offset);
- if (!$rs) {
+ $rows = $this->getRecordset($offset);
+ if (false == is_array($rows)) {
break;
}
- while ($row = mysqli_fetch_array($rs)) {
+ foreach($rows as $row) {
echo $this->getEntry($row);
$proceed = 1;
}
@@ -68,11 +68,11 @@ public function saveSPOG($path, $q = '')
$offset = 0;
do {
$proceed = 0;
- $rs = $this->getRecordset($offset);
- if (!$rs) {
+ $rows = $this->getRecordset($offset);
+ if (false == is_array($rows)) {
break;
}
- while ($row = mysqli_fetch_array($rs)) {
+ foreach($rows as $row) {
fwrite($fp, $this->getEntry($row));
$proceed = 1;
}
@@ -101,7 +101,6 @@ public function saveCustomSPOG($path, $q)
public function getRecordset($offset)
{
$prefix = $this->store->getTablePrefix();
- $con = $this->store->getDBCon();
$sql = '
SELECT
VS.val AS s,
@@ -128,13 +127,13 @@ public function getRecordset($offset)
if ($offset) {
$sql .= ' OFFSET '.$offset;
}
- $rs = mysqli_query($con, $sql, MYSQLI_USE_RESULT);
- $err = mysqli_error($con);
- if (!empty($err)) {
- return $this->addError($err);
+
+ $rows = $this->store->a['db_object']->fetchList($sql);
+ if (false == empty($this->store->a['db_object']->getErrorMessage())) {
+ return $this->addError($this->store->a['db_object']->getErrorMessage());
}
- return $rs;
+ return $rows;
}
public function getHeader()
diff --git a/store/ARC2_StoreEndpoint.php b/store/ARC2_StoreEndpoint.php
index 584fc826..864f80af 100755
--- a/store/ARC2_StoreEndpoint.php
+++ b/store/ARC2_StoreEndpoint.php
@@ -397,7 +397,6 @@ public function getSPARQLXMLSelectResultDoc($r)
public function getSPARQLJSONSelectResultDoc($r)
{
- $con = $this->getDBCon();
$this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
$vars = $r['result']['variables'];
$rows = $r['result']['rows'];
@@ -430,13 +429,13 @@ public function getSPARQLJSONSelectResultDoc($r)
$r .= ' "'.$var.'": {';
if ('uri' == $row[$var.' type']) {
$r .= $nl.' "type": "uri",';
- $r .= $nl.' "value": "'.mysqli_real_escape_string($con, $row[$var]).'"';
+ $r .= $nl.' "value": "'.$this->store->a['db_object']->escape($row[$var]).'"';
} elseif ('bnode' == $row[$var.' type']) {
$r .= $nl.' "type": "bnode",';
$r .= $nl.' "value": "'.substr($row[$var], 2).'"';
} else {
- $dt = isset($row[$var.' datatype']) ? ','.$nl.' "datatype": "'.mysqli_real_escape_string($con, $row[$var.' datatype']).'"' : '';
- $lang = isset($row[$var.' lang']) ? ','.$nl.' "xml:lang": "'.mysqli_real_escape_string($con, $row[$var.' lang']).'"' : '';
+ $dt = isset($row[$var.' datatype']) ? ','.$nl.' "datatype": "'.$this->store->a['db_object']->escape($row[$var.' datatype']).'"' : '';
+ $lang = isset($row[$var.' lang']) ? ','.$nl.' "xml:lang": "'.$this->store->a['db_object']->escape($row[$var.' lang']).'"' : '';
$type = $dt ? 'typed-literal' : 'literal';
$r .= $nl.' "type": "'.$type.'",';
$r .= $nl.' "value": "'.$this->jsonEscape($row[$var]).'"';
diff --git a/store/ARC2_StoreHelper.php b/store/ARC2_StoreHelper.php
index ca2e3242..60b6de02 100755
--- a/store/ARC2_StoreHelper.php
+++ b/store/ARC2_StoreHelper.php
@@ -18,7 +18,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
}
@@ -29,20 +29,20 @@ public function changeNamespaceURI($old_uri, $new_uri)
$t_changes = 0;
/* table lock */
if ($this->store->getLock()) {
- $con = $this->store->getDBCon();
foreach (['id', 's', 'o'] as $id_col) {
$tbl = $this->store->getTablePrefix().$id_col.'2val';
- $sql = 'SELECT id, val FROM '.$tbl.' WHERE val LIKE "'.mysqli_real_escape_string($con, $old_uri).'%"';
- $rs = mysqli_query($con, $sql);
- if (!$rs) {
+ $sql = 'SELECT id, val FROM '.$tbl.' WHERE val LIKE "'.$this->store->a['db_object']->escape($old_uri).'%"';
+ $rows = $this->store->a['db_object']->fetchList($sql);
+
+ if (false == is_array($rows)) {
continue;
}
- while ($row = mysqli_fetch_array($rs)) {
+ foreach($rows as $row) {
$new_val = str_replace($old_uri, $new_uri, $row['val']);
$new_id = $this->store->getTermID($new_val, $id_col);
if (!$new_id) {/* unknown ns uri, overwrite current id value */
- $sub_sql = 'UPDATE '.$tbl." SET val = '".mysqli_real_escape_string($con, $new_val)."' WHERE id = ".$row['id'];
- $sub_r = mysqli_query($con, $sub_sql);
+ $sub_sql = 'UPDATE '.$tbl." SET val = '".$this->store->a['db_object']->escape($new_val)."' WHERE id = ".$row['id'];
+ $sub_r = $this->store->a['db_object']->simpleQuery($sub_sql);
++$id_changes;
} else {/* replace ids */
$t_tbls = $this->store->getTables();
@@ -50,8 +50,8 @@ public function changeNamespaceURI($old_uri, $new_uri)
if (preg_match('/^triple/', $t_tbl)) {
foreach (['s', 'p', 'o', 'o_lang_dt'] as $t_col) {
$sub_sql = 'UPDATE '.$this->store->getTablePrefix().$t_tbl.' SET '.$t_col.' = '.$new_id.' WHERE '.$t_col.' = '.$row['id'];
- $sub_r = mysqli_query($con, $sub_sql);
- $t_changes += mysqli_affected_rows($con);
+ $sub_r = $this->store->a['db_object']->simpleQuery($sub_sql);
+ $t_changes += $this->store->a['db_object']->getAffectedRows();
}
}
}
diff --git a/store/ARC2_StoreInsertQueryHandler.php b/store/ARC2_StoreInsertQueryHandler.php
index dbfbe115..8f0bd729 100644
--- a/store/ARC2_StoreInsertQueryHandler.php
+++ b/store/ARC2_StoreInsertQueryHandler.php
@@ -16,7 +16,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
}
@@ -24,7 +24,6 @@ public function __init()
public function runQuery($infos, $keep_bnode_ids = 0)
{
$this->infos = $infos;
- $con = $this->store->getDBCon();
/* insert */
if (!$this->v('pattern', [], $this->infos['query'])) {
$triples = $this->infos['query']['construct_triples'];
diff --git a/store/ARC2_StoreLoadQueryHandler.php b/store/ARC2_StoreLoadQueryHandler.php
index c69a7d30..54e2d550 100644
--- a/store/ARC2_StoreLoadQueryHandler.php
+++ b/store/ARC2_StoreLoadQueryHandler.php
@@ -155,15 +155,17 @@ public function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '')
public function getMaxTermID()
{
- $con = $this->store->getDBCon();
$sql = '';
foreach (['id2val', 's2val', 'o2val'] as $tbl) {
$sql .= $sql ? ' UNION ' : '';
$sql .= '(SELECT MAX(id) as `id` FROM '.$this->store->getTablePrefix().$tbl.')';
}
$r = 0;
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs)) {
- while ($row = mysqli_fetch_array($rs)) {
+
+ $rows = $this->store->a['db_object']->fetchList($sql);
+
+ if (is_array($rows)) {
+ foreach($rows as $row) {
$r = ($r < $row['id']) ? $row['id'] : $r;
}
}
@@ -171,12 +173,18 @@ public function getMaxTermID()
return $r + 1;
}
+ /**
+ * @todo change DB schema and avoid using this function because it does not protect against race conditions
+ *
+ * @return int
+ */
public function getMaxTripleID()
{
- $con = $this->store->getDBCon();
$sql = 'SELECT MAX(t) AS `id` FROM '.$this->store->getTablePrefix().'triple';
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs) && ($row = mysqli_fetch_array($rs))) {
- return $row['id'] + 1;
+
+ $row = $this->store->a['db_object']->fetchRow($sql);
+ if (isset($row['id'])) {
+ return $row['id']+1;
}
return 1;
@@ -184,7 +192,6 @@ public function getMaxTripleID()
public function getStoredTermID($val, $type_id, $tbl)
{
- $con = $this->store->getDBCon();
/* buffered */
if (isset($this->term_ids[$val])) {
if (!isset($this->term_ids[$val][$tbl])) {
@@ -204,12 +211,12 @@ public function getStoredTermID($val, $type_id, $tbl)
$sub_tbls = ('id' == $tbl) ? ['id2val', 's2val', 'o2val'] : ('s' == $tbl ? ['s2val', 'id2val', 'o2val'] : ['o2val', 'id2val', 's2val']);
foreach ($sub_tbls as $sub_tbl) {
$id = 0;
- //$sql = "SELECT id AS `id`, '" . $sub_tbl . "' AS `tbl` FROM " . $tbl_prefix . $sub_tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "'";
/* via hash */
if (preg_match('/^(s2val|o2val)$/', $sub_tbl) && $this->hasHashColumn($sub_tbl)) {
$sql = 'SELECT id AS `id`, val AS `val` FROM '.$tbl_prefix.$sub_tbl." WHERE val_hash = BINARY '".$this->getValueHash($val)."'";
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs)) {
- while ($row = mysqli_fetch_array($rs)) {
+ $rows = $this->store->a['db_object']->fetchList($sql);
+ if (is_array($rows)) {
+ foreach($rows as $row) {
if ($row['val'] == $val) {
$id = $row['id'];
break;
@@ -217,10 +224,13 @@ public function getStoredTermID($val, $type_id, $tbl)
}
}
} else {
- $sql = 'SELECT id AS `id` FROM '.$tbl_prefix.$sub_tbl." WHERE val = BINARY '".mysqli_real_escape_string($con, $val)."'";
- if (($rs = $this->queryDB($sql.' LIMIT 1', $con)) && mysqli_num_rows($rs)) {
- $row = mysqli_fetch_array($rs);
- $id = $row['id'];
+ $binaryValue = $this->store->a['db_object']->escape($val);
+ if (false !== empty($binaryValue)) {
+ $sql = 'SELECT id AS `id` FROM '.$tbl_prefix.$sub_tbl." WHERE val = BINARY '".$binaryValue."'";
+ $row = $this->store->a['db_object']->fetchRow($sql);
+ if (is_array($row) && isset($row['id'])) {
+ $id = $row['id'];
+ }
}
}
if ($id) {
@@ -248,23 +258,25 @@ public function getStoredTermID($val, $type_id, $tbl)
public function getTripleID($t)
{
- $con = $this->store->getDBCon();
$val = serialize($t);
/* buffered */
if (isset($this->triple_ids[$val])) {
return [$this->triple_ids[$val]]; /* hack for "don't insert this triple" */
}
/* db */
- $sql = 'SELECT t FROM '.$this->store->getTablePrefix().'triple WHERE
- s = '.$t['s'].' AND p = '.$t['p'].' AND o = '.$t['o'].' AND o_lang_dt = '.$t['o_lang_dt'].' AND s_type = '.$t['s_type'].' AND o_type = '.$t['o_type'].'
- LIMIT 1
- ';
- if (($rs = $this->queryDB($sql, $con)) && mysqli_num_rows($rs) && ($row = mysqli_fetch_array($rs))) {
+ $sql = 'SELECT t
+ FROM '.$this->store->getTablePrefix().'triple
+ WHERE s = '.$t['s'].' AND p = '.$t['p'].' AND o = '.$t['o'].'
+ AND o_lang_dt = '.$t['o_lang_dt'].' AND s_type = '.$t['s_type'].'
+ AND o_type = '.$t['o_type'].'
+ LIMIT 1';
+ $row = $this->store->a['db_object']->fetchRow($sql);
+ if (isset($row['t'])) {
$this->triple_ids[$val] = $row['t']; /* hack for "don't insert this triple" */
return [$row['t']]; /* hack for "don't insert this triple" */
- }
+
/* new */
- else {
+ } else {
$this->triple_ids[$val] = $this->max_triple_id;
++$this->max_triple_id;
/* split tables ? */
@@ -300,7 +312,9 @@ public function getOComp($val)
if (isset($m[3]) && ('Z' != $m[3])) {
$uts = strtotime(str_replace('T', ' ', $val));
if (preg_match('/([\+\-])([0-9]{2})\:?([0-9]{2})$/', $m[3], $sub_m)) {
- $diff_mins = (3600 * ltrim($sub_m[2], '0')) + ltrim($sub_m[3], '0');
+ // without the explicit (int) casting, you will get the following error with PHP 7.1+
+ // A non-numeric value encountered
+ $diff_mins = (3600 * (int)ltrim($sub_m[2], '0')) + (int)ltrim($sub_m[3], '0');
$uts = ('-' == $sub_m[1]) ? $uts + $diff_mins : $uts - $diff_mins;
$val = date('Y-m-d\TH:i:s\Z', $uts);
}
@@ -345,14 +359,13 @@ public function getOComp($val)
public function bufferTripleSQL($t)
{
- $con = $this->store->getDBCon();
$tbl = 'triple';
$sql = ', ';
if (!isset($this->sql_buffers[$tbl])) {
$this->sql_buffers[$tbl] = 'INSERT IGNORE INTO '.$this->store->getTablePrefix().$tbl.' (t, s, p, o, o_lang_dt, o_comp, s_type, o_type) VALUES';
$sql = ' ';
}
- $this->sql_buffers[$tbl] .= $sql.'('.$t['t'].', '.$t['s'].', '.$t['p'].', '.$t['o'].', '.$t['o_lang_dt'].", '".mysqli_real_escape_string($con, $t['o_comp'])."', ".$t['s_type'].', '.$t['o_type'].')';
+ $this->sql_buffers[$tbl] .= $sql.'('.$t['t'].', '.$t['s'].', '.$t['p'].', '.$t['o'].', '.$t['o_lang_dt'].", '".$this->store->a['db_object']->escape($t['o_comp'])."', ".$t['s_type'].', '.$t['o_type'].')';
}
public function bufferGraphSQL($g2t)
@@ -368,17 +381,16 @@ public function bufferGraphSQL($g2t)
public function bufferIDSQL($tbl, $id, $val, $val_type)
{
- $con = $this->store->getDBCon();
$tbl = $tbl.'2val';
if ('id2val' == $tbl) {
$cols = 'id, val, val_type';
- $vals = '('.$id.", '".mysqli_real_escape_string($con, $val)."', ".$val_type.')';
+ $vals = '('.$id.", '".$this->store->a['db_object']->escape($val)."', ".$val_type.')';
} elseif (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
$cols = 'id, val_hash, val';
- $vals = '('.$id.", '".$this->getValueHash($val)."', '".mysqli_real_escape_string($con, $val)."')";
+ $vals = '('.$id.", '".$this->getValueHash($val)."', '".$this->store->a['db_object']->escape($val)."')";
} else {
$cols = 'id, val';
- $vals = '('.$id.", '".mysqli_real_escape_string($con, $val)."')";
+ $vals = '('.$id.", '".$this->store->a['db_object']->escape($val)."')";
}
if (!isset($this->sql_buffers[$tbl])) {
$this->sql_buffers[$tbl] = '';
@@ -392,7 +404,6 @@ public function bufferIDSQL($tbl, $id, $val, $val_type)
public function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refresh_lock = 0, $split_tables = 0)
{
- $con = $this->store->getDBCon();
if (!$this->keep_time_limit) {
set_time_limit($this->v('time_limit', 60, $this->a));
}
@@ -400,19 +411,30 @@ public function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refres
$buffer_size = isset($this->sql_buffers[$tbl]) ? 1 : 0;
if ($buffer_size && $force_write) {
$t1 = ARC2::mtime();
- $this->queryDB($this->sql_buffers[$tbl], $con);
+ $this->store->a['db_object']->simpleQuery($this->sql_buffers[$tbl]);
/* table error */
- $er = mysqli_error($con);
- if (!empty($er)) {
- $this->autoRepairTable($er, $con, $this->sql_buffers[$tbl]);
+ $error = $this->store->a['db_object']->getErrorMessage();
+ if (!empty($error)) {
+ $this->autoRepairTable($error, $this->sql_buffers[$tbl]);
}
unset($this->sql_buffers[$tbl]);
if ($this->log_inserts) {
$t2 = ARC2::mtime();
- $this->inserts[$tbl] = $this->v($tbl, 0, $this->inserts) + max(0, mysqli_affected_rows($con));
+ $this->inserts[$tbl] = $this->v(
+ $tbl,
+ 0,
+ $this->inserts
+ ) + max(0, $this->store->a['db_object']->getAffectedRows());
+
$dur = round($t2 - $t1, 4);
- $this->insert_times[$tbl] = isset($this->insert_times[$tbl]) ? $this->insert_times[$tbl] : ['min' => $dur, 'max' => $dur, 'sum' => $dur];
- $this->insert_times[$tbl] = ['min' => min($dur, $this->insert_times[$tbl]['min']), 'max' => max($dur, $this->insert_times[$tbl]['max']), 'sum' => $dur + $this->insert_times[$tbl]['sum']];
+ $this->insert_times[$tbl] = isset($this->insert_times[$tbl])
+ ? $this->insert_times[$tbl]
+ : ['min' => $dur, 'max' => $dur, 'sum' => $dur];
+ $this->insert_times[$tbl] = [
+ 'min' => min($dur, $this->insert_times[$tbl]['min']),
+ 'max' => max($dur, $this->insert_times[$tbl]['max']),
+ 'sum' => $dur + $this->insert_times[$tbl]['sum']
+ ];
}
/* reset term id buffers */
if ($reset_id_buffers) {
@@ -435,12 +457,13 @@ public function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refres
return 1;
}
- public function autoRepairTable($er, $con, $sql = '')
+ public function autoRepairTable($er, $sql = '')
{
$this->addError('MySQL error: '.$er.' ('.$sql.')');
if (preg_match('/Table \'[^\']+\/([a-z0-9\_\-]+)\' .*(crashed|repair)/i', $er, $m)) {
- $rs = $this->queryDB('REPAIR TABLE '.rawurlencode($m[1]), $con);
- $msg = $rs ? mysqli_fetch_array($rs) : [];
+ $row = $this->store->a['db_object']->fetchRow('REPAIR TABLE '.rawurlencode($m[1]));
+ $msg = is_array($row) ? $row : [];
+
if ('error' == $this->v('Msg_type', 'error', $msg)) {
/* auto-reset */
if ($this->v('store_reset_on_table_crash', 0, $this->a)) {
@@ -450,7 +473,6 @@ public function autoRepairTable($er, $con, $sql = '')
$er = $this->v('Msg_text', 'unknown error', $msg);
$this->addError('Auto-repair failed on '.rawurlencode($m[1]).': '.$er);
}
- //die("Fatal errors: \n" . print_r($this->getErrors(), 1));
}
}
}
diff --git a/store/ARC2_StoreQueryHandler.php b/store/ARC2_StoreQueryHandler.php
index 59c516e1..98f93d32 100755
--- a/store/ARC2_StoreQueryHandler.php
+++ b/store/ARC2_StoreQueryHandler.php
@@ -18,7 +18,7 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->xsd = 'http://www.w3.org/2001/XMLSchema#';
$this->allow_extension_functions = $this->v('store_allow_extension_functions', 1, $this->a);
@@ -55,8 +55,7 @@ public function createMergeTable()
return 1;
}
$this->mrg_table_id = 'MRG_'.$this->store->getTablePrefix().crc32(uniqid(rand()));
- $con = $this->store->getDBCon();
- $this->queryDB('FLUSH TABLES', $con);
+ $this->getDBObject()->query('FLUSH TABLES');
$indexes = $this->v('store_indexes', ['sp (s,p)', 'os (o,s)', 'po (p,o)'], $this->a);
$index_code = $indexes ? 'KEY '.implode(', KEY ', $indexes).', ' : '';
$prefix = $this->store->getTablePrefix();
@@ -72,7 +71,7 @@ public function createMergeTable()
o_type tinyint(1) NOT NULL default 0, /* uri/bnode/literal => 0/1/2 */
misc tinyint(1) NOT NULL default 0, /* temporary flags */
UNIQUE KEY (t), '.$index_code.' KEY (misc)
- )
+ )
';
$v = $this->store->getDBVersion();
$sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
@@ -81,17 +80,19 @@ public function createMergeTable()
$sql .= ','.$prefix.'triple_'.abs(crc32($p));
}
$sql .= ')';
+ // TODO whats about that?
//$sql .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
//$sql .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
//echo $sql;
- return $this->queryDB($sql, $con);
+ return $this->getDBObject()->query($sql);
}
public function dropMergeTable()
{
return 1;
+ // TODO triple_all table seems not used anymore, therefore this function can be removed?
$sql = 'DROP TABLE IF EXISTS '.$this->store->getTablePrefix().'triple_all';
//echo $sql;
- return $this->queryDB($sql, $this->store->getDBCon());
+ //return $this->queryDB($sql, $this->store->getDBCon());
}
}
diff --git a/store/ARC2_StoreSelectQueryHandler.php b/store/ARC2_StoreSelectQueryHandler.php
index f820050e..88388c7f 100644
--- a/store/ARC2_StoreSelectQueryHandler.php
+++ b/store/ARC2_StoreSelectQueryHandler.php
@@ -18,10 +18,9 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->store = $this->caller;
- $con = $this->store->getDBCon();
$this->handler_type = 'select';
$this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
$this->cache_results = $this->v('store_cache_results', 0, $this->a);
@@ -29,7 +28,6 @@ public function __init()
public function runQuery($infos)
{
- $con = $this->store->getDBCon();
$rf = $this->v('result_format', '', $infos);
$this->infos = $infos;
$this->infos['null_vars'] = [];
@@ -53,7 +51,7 @@ public function runQuery($infos)
$r = $this->getFinalQueryResult($q_sql, $tmp_tbl);
/* remove intermediate results */
if (!$this->cache_results) {
- $this->queryDB('DROP TABLE IF EXISTS '.$tmp_tbl, $con);
+ $this->getDBObjectFromARC2Class()->simpleQuery('DROP TABLE IF EXISTS '.$tmp_tbl);
}
return $r;
@@ -108,6 +106,8 @@ public function buildInitialIndexes()
{
$this->dependency_log = [];
$this->index = $this->getEmptyIndex();
+ // if no pattern is in the query, the index "pattern" is undefined, which leads to an error.
+ // TODO throw an exception/raise an error and avoid "Undefined index: pattern" notification
$this->buildIndex($this->infos['query']['pattern'], 0);
$tmp = $this->index;
$this->analyzeIndex($this->getPattern('0'));
@@ -119,7 +119,6 @@ public function buildInitialIndexes()
public function createTempTable($q_sql)
{
- $con = $this->store->getDBCon();
$v = $this->store->getDBVersion();
if ($this->cache_results) {
$tbl = $this->store->getTablePrefix().'Q'.md5($q_sql);
@@ -132,13 +131,12 @@ public function createTempTable($q_sql)
$tmp_sql = 'CREATE TEMPORARY TABLE '.$tbl.' ( '.$this->getTempTableDef($tbl, $q_sql).') ';
$tmp_sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
$tmp_sql .= '='.$this->engine_type; /* HEAP doesn't support AUTO_INCREMENT, and MySQL breaks on MEMORY sometimes */
- if (!$this->queryDB($tmp_sql, $con) && !$this->queryDB(str_replace('CREATE TEMPORARY', 'CREATE', $tmp_sql), $con)) {
- return $this->addError(mysqli_error($con));
+ if (!$this->store->a['db_object']->simpleQuery($tmp_sql)
+ && !$this->store->a['db_object']->simpleQuery(str_replace('CREATE TEMPORARY', 'CREATE', $tmp_sql))) {
+ return $this->addError($this->store->a['db_object']->getErrorMessage());
}
- mysqli_query($con, 'INSERT INTO '.$tbl.' '."\n".$q_sql, MYSQLI_USE_RESULT);
- $er = mysqli_error($con);
- if (!empty($er)) {
- $this->addError($er);
+ if (false == $this->store->a['db_object']->simpleQuery('INSERT INTO '.$tbl.' '."\n".$q_sql)) {
+ $this->addError($this->store->a['db_object']->getErrorMessage());
}
return $tbl;
@@ -203,24 +201,33 @@ public function getFinalQueryResult($q_sql, $tmp_tbl)
/* result */
$r = ['variables' => $vars];
$v_sql = $this->getValueSQL($tmp_tbl, $q_sql);
- //echo "\n\n" . $v_sql;
+
$t1 = ARC2::mtime();
- $con = $this->store->getDBCon();
- $rs = mysqli_query($con, $v_sql, MYSQLI_USE_RESULT);
- $er = mysqli_error($con);
- if (!empty($er)) {
- $this->addError($er);
+
+ try {
+ $entries = []; // in case an exception gets thrown
+
+ $entries = $this->store->a['db_object']->fetchList($v_sql);
+ } catch (\Exception $e) {
+ $this->addError($e->getMessage());
}
+
$t2 = ARC2::mtime();
$rows = [];
$types = [0 => 'uri', 1 => 'bnode', 2 => 'literal'];
- if ($rs) {
- while ($pre_row = mysqli_fetch_array($rs)) {
+ if (0 < count($entries)) {
+ foreach($entries as $pre_row) {
$row = [];
foreach ($vars as $var) {
if (isset($pre_row[$var])) {
$row[$var] = $pre_row[$var];
- $row[$var.' type'] = isset($pre_row[$var.' type']) ? $types[$pre_row[$var.' type']] : (in_array($var, $aggregate_vars) ? 'literal' : 'uri');
+ $row[$var.' type'] = isset($pre_row[$var.' type'])
+ ? $types[$pre_row[$var.' type']]
+ : (
+ in_array($var, $aggregate_vars)
+ ? 'literal'
+ : 'uri'
+ );
if (isset($pre_row[$var.' lang_dt']) && ($lang_dt = $pre_row[$var.' lang_dt'])) {
if (preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt)) {
$row[$var.' lang'] = $lang_dt;
@@ -467,17 +474,19 @@ public function getQuerySQL()
$nl = "\n";
$where_sql = $this->getWHERESQL(); /* pre-fills $index['sub_joins'] $index['constraints'] */
$order_sql = $this->getORDERSQL(); /* pre-fills $index['sub_joins'] $index['constraints'] */
- return ''.
- ($this->is_union_query ? 'SELECT' : 'SELECT'.$this->getDistinctSQL()).$nl.
- $this->getResultVarsSQL().$nl. /* fills $index['sub_joins'] */
- $this->getFROMSQL().
- $this->getAllJoinsSQL().
- $this->getWHERESQL().
- $this->getGROUPSQL().
- $this->getORDERSQL().
- ($this->is_union_query ? '' : $this->getLIMITSQL()).
- $nl.
- '';
+ return ''. (
+ $this->is_union_query
+ ? 'SELECT'
+ : 'SELECT'.$this->getDistinctSQL()).$nl.
+ $this->getResultVarsSQL().$nl. /* fills $index['sub_joins'] */
+ $this->getFROMSQL().
+ $this->getAllJoinsSQL().
+ $this->getWHERESQL().
+ $this->getGROUPSQL().
+ $this->getORDERSQL().
+ ($this->is_union_query
+ ? ''
+ : $this->getLIMITSQL()).$nl.'';
}
public function getDistinctSQL()
@@ -841,7 +850,8 @@ public function getDependentJoins($id)
}
public function getRequiredSubJoinSQL($id, $prefix = '')
- {/* id is a triple pattern id. Optional FILTERS and GRAPHs are getting added to the join directly */
+ {
+ /* id is a triple pattern id. Optional FILTERS and GRAPHs are getting added to the join directly */
$nl = "\n";
$r = '';
foreach ($this->index['sub_joins'] as $alias) {
@@ -861,7 +871,6 @@ public function getRequiredSubJoinSQL($id, $prefix = '')
$sub_sub_r = 'T_'.$id.'.o_type = 2';
$sub_r .= $nl.' AND ('.$sub_sub_r.')';
}
- //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
$cur_prefix = $prefix ? $prefix.' ' : '';
if ('g' == $col) {
$r .= trim($cur_prefix.'JOIN '.$this->getValueTable($col).' V_'.$id.'_'.$col.' ON ('.$nl.' (G_'.$id.'.'.$col.' = V_'.$id.'_'.$col.'.id) '.$sub_r.$nl.')');
@@ -883,7 +892,7 @@ public function getRequiredSubJoinSQL($id, $prefix = '')
$added_gts[] = $set['graph'];
}
}
- $sub_r .= ('' !== $sub_sub_r) ? $nl.' AND (G_'.$id.'.g IN ('.$sub_sub_r.'))' : ''; // /* ' . str_replace('#' , '::', $set['graph']) . ' */';
+ $sub_r .= ('' !== $sub_sub_r) ? $nl.' AND (G_'.$id.'.g IN ('.$sub_sub_r.'))' : '';
/* other graph join conditions */
foreach ($this->index['graph_vars'] as $var => $occurs) {
$occur_tbls = [];
@@ -899,7 +908,6 @@ public function getRequiredSubJoinSQL($id, $prefix = '')
}
}
}
- //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
$cur_prefix = $prefix ? $prefix.' ' : '';
$r .= trim($cur_prefix.'JOIN '.$this->getGraphTable().' G_'.$id.' ON ('.$nl.' (T_'.$id.'.t = G_'.$id.'.t)'.$sub_r.$nl.')');
}
@@ -926,14 +934,14 @@ public function getWHERESQL()
$d_joins = $this->getDependentJoins($id);
$added = [];
$d_aliases = [];
- //echo $id . ' =>' . print_r($d_joins, 1);
$id_alias = 'T_'.$id.'.s';
foreach ($d_joins as $alias) {
if (preg_match('/^(T|V|G)_([0-9\_]+)(_[spo])?\.([a-z\_]+)/', $alias, $m)) {
$tbl_type = $m[1];
$tbl_pattern_id = $m[2];
$suffix = $m[3];
- if (($tbl_pattern_id >= $id) && $this->sameOptional($tbl_pattern_id, $id)) {/* get rid of dependency permutations and nested optionals */
+ /* get rid of dependency permutations and nested optionals */
+ if (($tbl_pattern_id >= $id) && $this->sameOptional($tbl_pattern_id, $id)) {
if (!in_array($tbl_type.'_'.$tbl_pattern_id.$suffix, $added)) {
$sub_r .= $sub_r ? ' AND ' : '';
$sub_r .= $alias.' IS NULL';
@@ -944,7 +952,8 @@ public function getWHERESQL()
}
}
}
- if (count($d_aliases) > 2) {/* @@todo fix this! */
+ /* TODO fix this! */
+ if (count($d_aliases) > 2) {
$sub_r1 = ' /* '.$id_alias.' dependencies */';
$sub_r2 = '(('.$id_alias.' IS NULL) OR (CONCAT('.implode(', ', $d_aliases).') IS NOT NULL))';
$r .= $r ? $nl.$sub_r1.$nl.' AND '.$sub_r2 : $sub_r1.$nl.$sub_r2;
@@ -1316,6 +1325,9 @@ public function detectExpressionValueType($pattern_ids)
return '';
}
+ /**
+ * @todo not in use, so remove?
+ */
public function getRelationalExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
{
$r = '';
@@ -1334,6 +1346,9 @@ public function getRelationalExpressionSQL($pattern, $context, $val_type = '', $
return $r ? '('.$r.')' : $r;
}
+ /**
+ * @todo not in use, so remove?
+ */
public function getAdditiveExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
{
$r = '';
@@ -1350,6 +1365,9 @@ public function getAdditiveExpressionSQL($pattern, $context, $val_type = '', $pa
return $r;
}
+ /**
+ * @todo not in use, so remove?
+ */
public function getMultiplicativeExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
{
$r = '';
@@ -1430,7 +1448,7 @@ public function getUriExpressionSQL($pattern, $context, $val_type = '')
{
$val = $pattern['uri'];
$r = $pattern['operator'];
- $r .= is_numeric($val) ? ' '.$val : ' "'.mysqli_real_escape_string($this->store->getDBCon(), $val).'"';
+ $r .= is_numeric($val) ? ' '.$val : ' "'.$this->store->a['db_object']->escape($val).'"';
return $r;
}
@@ -1444,10 +1462,10 @@ public function getLiteralExpressionSQL($pattern, $context, $val_type = '', $par
} elseif (preg_match('/^(true|false)$/i', $val) && ('http://www.w3.org/2001/XMLSchema#boolean' == $this->v1('datatype', '', $pattern))) {
$r .= ' '.strtoupper($val);
} elseif ('regex' == $parent_type) {
- $sub_r = mysqli_real_escape_string($this->store->getDBCon(), $val);
+ $sub_r = $this->store->a['db_object']->escape($val);
$r .= ' "'.preg_replace('/\x5c\x5c/', '\\', $sub_r).'"';
} else {
- $r .= ' "'.mysqli_real_escape_string($this->store->getDBCon(), $val).'"';
+ $r .= ' "'.$this->store->a['db_object']->escape($val).'"';
}
if (($lang_dt = $this->v1('lang', '', $pattern)) || ($lang_dt = $this->v1('datatype', '', $pattern))) {
/* try table/alias via var in siblings */
@@ -1467,8 +1485,10 @@ public function getLiteralExpressionSQL($pattern, $context, $val_type = '', $par
} else {
$context_pattern_id = $pattern['id'];
}
- if ($tbl == $context_pattern_id) {/* @todo better dependency check */
- if ($term_id || ('http://www.w3.org/2001/XMLSchema#integer' != $lang_dt)) {/* skip if simple int, but no id */
+ // TODO better dependency check
+ if ($tbl == $context_pattern_id) {
+ if ($term_id || ('http://www.w3.org/2001/XMLSchema#integer' != $lang_dt)) {
+ /* skip, if simple int, but no id */
$this->addConstraintSQLEntry($context_pattern_id, 'T_'.$tbl.'.o_lang_dt = '.$term_id.' /* '.preg_replace('/[\#\*\>]/', '::', $lang_dt).' */');
}
}
@@ -1681,6 +1701,9 @@ public function getLangmatchesCallSQL($pattern, $context)
return '';
}
+ /**
+ * @todo not in use, so remove?
+ */
public function getSametermCallSQL($pattern, $context)
{
if (2 == count($pattern['args'])) {
@@ -1790,10 +1813,11 @@ public function getLIMITSQL()
$limit = $this->v('limit', -1, $this->infos['query']);
$offset = $this->v('offset', -1, $this->infos['query']);
if ($limit != -1) {
- $offset = ($offset == -1) ? 0 : mysqli_real_escape_string($this->store->getDBCon(), $offset);
+ $offset = ($offset == -1) ? 0 : $this->store->a['db_object']->escape($offset);
$r = 'LIMIT '.$offset.','.$limit;
} elseif ($offset != -1) {
- $r = 'LIMIT '.mysqli_real_escape_string($this->store->getDBCon(), $offset).',999999999999'; /* mysql doesn't support stand-alone offsets .. */
+ // mysql doesn't support stand-alone offsets
+ $r = 'LIMIT '.$this->store->a['db_object']->escape($offset).',999999999999';
}
return $r ? $nl.$r : '';
diff --git a/store/ARC2_StoreTableManager.php b/store/ARC2_StoreTableManager.php
index 58f402d6..38d9830e 100755
--- a/store/ARC2_StoreTableManager.php
+++ b/store/ARC2_StoreTableManager.php
@@ -17,19 +17,16 @@ public function __construct($a, &$caller)
}
public function __init()
- {/* db_con */
+ {
parent::__init();
$this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
}
public function getTableOptionsCode()
{
- $v = $this->getDBVersion();
- $r = '';
- $r .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
- $r .= '='.$this->engine_type;
- $r .= ($v >= '04-00-00') ? ' CHARACTER SET utf8' : '';
- $r .= ($v >= '04-01-00') ? ' COLLATE utf8_unicode_ci' : '';
+ $r = 'ENGINE='.$this->engine_type;
+ $r .= ' CHARACTER SET utf8';
+ $r .= ' COLLATE utf8_unicode_ci';
$r .= ' DELAY_KEY_WRITE = 1';
return $r;
@@ -37,24 +34,23 @@ public function getTableOptionsCode()
public function createTables()
{
- $con = $this->getDBCon();
if (!$this->createTripleTable()) {
- return $this->addError('Could not create "triple" table ('.mysqli_error($con).').');
+ return $this->addError('Could not create "triple" table ('.$this->a['db_object']->getErrorMessage().').');
}
if (!$this->createG2TTable()) {
- return $this->addError('Could not create "g2t" table ('.mysqli_error($con).').');
+ return $this->addError('Could not create "g2t" table ('.$this->a['db_object']->getErrorMessage().').');
}
if (!$this->createID2ValTable()) {
- return $this->addError('Could not create "id2val" table ('.mysqli_error($con).').');
+ return $this->addError('Could not create "id2val" table ('.$this->a['db_object']->getErrorMessage().').');
}
if (!$this->createS2ValTable()) {
- return $this->addError('Could not create "s2val" table ('.mysqli_error($con).').');
+ return $this->addError('Could not create "s2val" table ('.$this->a['db_object']->getErrorMessage().').');
}
if (!$this->createO2ValTable()) {
- return $this->addError('Could not create "o2val" table ('.mysqli_error($con).').');
+ return $this->addError('Could not create "o2val" table ('.$this->a['db_object']->getErrorMessage().').');
}
if (!$this->createSettingTable()) {
- return $this->addError('Could not create "setting" table ('.mysqli_error($con).').');
+ return $this->addError('Could not create "setting" table ('.$this->a['db_object']->getErrorMessage().').');
}
return 1;
@@ -79,8 +75,7 @@ public function createTripleTable($suffix = 'triple')
UNIQUE KEY (t), '.$index_code.' KEY (misc)
) '.$this->getTableOptionsCode().'
';
-
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function extendTripleTableColumns($suffix = 'triple')
@@ -94,7 +89,7 @@ public function extendTripleTableColumns($suffix = 'triple')
MODIFY o_lang_dt int(10) UNSIGNED NOT NULL
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function createG2TTable()
@@ -107,7 +102,7 @@ public function createG2TTable()
) '.$this->getTableOptionsCode().'
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function extendG2tTableColumns($suffix = 'g2t')
@@ -118,7 +113,7 @@ public function extendG2tTableColumns($suffix = 'g2t')
MODIFY t int(10) UNSIGNED NOT NULL
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function createID2ValTable()
@@ -129,13 +124,13 @@ public function createID2ValTable()
misc tinyint(1) NOT NULL default 0,
val text NOT NULL,
val_type tinyint(1) NOT NULL default 0, /* uri/bnode/literal => 0/1/2 */
- PRIMARY KEY (`id`),
- UNIQUE KEY (id,val_type),
+ PRIMARY KEY (`id`),
+ UNIQUE KEY (id,val_type),
KEY v (val(64))
) '.$this->getTableOptionsCode().'
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function extendId2valTableColumns($suffix = 'id2val')
@@ -145,7 +140,7 @@ public function extendId2valTableColumns($suffix = 'id2val')
MODIFY id int(10) UNSIGNED NOT NULL
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function createS2ValTable()
@@ -162,7 +157,7 @@ public function createS2ValTable()
) '.$this->getTableOptionsCode().'
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function extendS2valTableColumns($suffix = 's2val')
@@ -172,7 +167,7 @@ public function extendS2valTableColumns($suffix = 's2val')
MODIFY id int(10) UNSIGNED NOT NULL
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function createO2ValTable()
@@ -192,7 +187,7 @@ public function createO2ValTable()
) '.$this->getTableOptionsCode().'
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function extendO2valTableColumns($suffix = 'o2val')
@@ -202,7 +197,7 @@ public function extendO2valTableColumns($suffix = 'o2val')
MODIFY id int(10) UNSIGNED NOT NULL
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function createSettingTable()
@@ -215,12 +210,11 @@ public function createSettingTable()
) '.$this->getTableOptionsCode().'
';
- return mysqli_query($this->getDBCon(), $sql);
+ return $this->a['db_object']->simpleQuery($sql);
}
public function extendColumns()
{
- $con = $this->getDBCon();
$tbl_prefix = $this->getTablePrefix();
$tbls = $this->getTables();
foreach ($tbls as $suffix) {
@@ -257,13 +251,12 @@ public function unsplitPredicate($p)
$old_tbl = $this->getTablePrefix().$suffix;
$new_tbl = $this->getTablePrefix().'triple';
$p_id = $this->getTermID($p, 'p');
- $con = $this->getDBCon();
$sql = '
INSERT IGNORE INTO '.$new_tbl.'
SELECT * FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id.'
';
- if ($rs = mysqli_query($con, $sql)) {
- mysqli_query($con, 'DROP TABLE '.$old_tbl);
+ if ($this->a['db_object']->simpleQuery($sql)) {
+ $this->a['db_object']->simpleQuery('DROP TABLE '.$old_tbl);
return 1;
} else {
@@ -278,17 +271,16 @@ public function splitPredicate($p)
$old_tbl = $this->getTablePrefix().'triple';
$new_tbl = $this->getTablePrefix().$suffix;
$p_id = $this->getTermID($p, 'p');
- $con = $this->getDBCon();
$sql = '
INSERT IGNORE INTO '.$new_tbl.'
SELECT * FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id.'
';
- if ($rs = mysqli_query($con, $sql)) {
- mysqli_query($con, 'DELETE FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id);
+ if ($this->a['db_object']->simpleQuery($sql)) {
+ $this->a['db_object']->simpleQuery('DELETE FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id);
return 1;
} else {
- mysqli_query($con, 'DROP TABLE '.$new_tbl);
+ $this->a['db_object']->simpleQuery('DROP TABLE '.$new_tbl);
return 0;
}
diff --git a/tests/ARC2_TestCase.php b/tests/ARC2_TestCase.php
index 613a2aa8..6336fc86 100644
--- a/tests/ARC2_TestCase.php
+++ b/tests/ARC2_TestCase.php
@@ -2,6 +2,8 @@
namespace Tests;
+use Psr\SimpleCache\CacheInterface;
+
class ARC2_TestCase extends \PHPUnit\Framework\TestCase
{
/**
@@ -23,5 +25,20 @@ public function setUp()
global $dbConfig;
$this->dbConfig = $dbConfig;
+
+ // in case we run with a cache, clear it
+ if (isset($this->dbConfig['cache_instance']) && $this->dbConfig['cache_instance'] instanceof CacheInterface) {
+ $this->dbConfig['cache_instance']->clear();
+ }
+ }
+
+ public function tearDown()
+ {
+ // in case we run with a cache, clear it
+ if (isset($this->dbConfig['cache_instance']) && $this->dbConfig['cache_instance'] instanceof CacheInterface) {
+ $this->dbConfig['cache_instance']->clear();
+ }
+
+ parent::tearDown();
}
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index e78011ca..ea2e476e 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -18,6 +18,37 @@
'db_name' => 'testdb',
'db_user' => 'root',
'db_pwd' => '',
- 'db_host' => 'localhost',
+ 'db_host' => '127.0.0.1',
);
}
+
+// set defaults for dbConfig entries
+if (false == isset($dbConfig['store_name'])) {
+ $dbConfig['store_name'] = 'arc';
+}
+
+if (false == isset($dbConfig['db_table_prefix'])) {
+ $dbConfig['db_table_prefix'] = null;
+}
+
+// set DB adapter (see related phpunit-xx.xml file), possible values: mysqli, pdo
+if ('pdo' == getenv('DB_ADAPTER')) {
+ if (!empty(getenv('DB_PDO_PROTOCOL'))) {
+ $dbConfig['db_adapter'] = 'pdo';
+ $dbConfig['db_pdo_protocol'] = getenv('DB_PDO_PROTOCOL');
+ } else {
+ throw new \Exception('Environment variable DB_PDO_PROTOCOL not set. Possible values are: mysql');
+ }
+} else {
+ $dbConfig['db_adapter'] = 'mysqli';
+}
+
+/*
+ * set cache enable
+ *
+ * if enabled, we use an instance of ArrayCache which is very fast
+ */
+if (true ===\getenv('CACHE_ENABLED') || 'true' == \getenv('CACHE_ENABLED')) {
+ $dbConfig['cache_enabled'] = true;
+ $dbConfig['cache_instance'] = new Symfony\Component\Cache\Simple\ArrayCache();
+}
diff --git a/tests/data/nt/saft-arc2-addition-regression1.nt b/tests/data/nt/saft-arc2-addition-regression1.nt
new file mode 100644
index 00000000..3d6ca2e5
--- /dev/null
+++ b/tests/data/nt/saft-arc2-addition-regression1.nt
@@ -0,0 +1,442 @@
+ "Cumberland"@en .
+ "Sydney"@en .
+ "151.2111111111111"^^ .
+ "4399722"^^ .
+ "33.859972222222225 151.2111111111111"@en .
+ "33.859972222222225"^^ .
+ .
+ "1911"^^ .
+ "0.4"^^ .
+ "1.0"^^ .
+ "3.53533377060864E9"^^ .
+ "3.534E9"^^ .
+ "1.4E7"^^ .
+ .
+ "Adams County"@en .
+ .
+ "0.9652553963561148"^^ .
+ "2000"^^ .
+ .
+ "1.294994055168E7"^^ .
+ .
+ "3476"^^ .
+ "3.548E9"^^ .
+ "3.54828371116032E9"^^ .
+ .
+ "Charles Douglas Cecil"@en .
+ "26"^^ .
+ .
+ .
+ "Chuck Cecil"@en .
+ "Free safety"@en .
+ "1.8288"^^ .
+ .
+ "1964-11-08"^^ .
+ "83462.4"^^ .
+ "Active (coach)"@en .
+ .
+ .
+ .
+ "0.0"^^ .
+ "221.0"^^ .
+ .
+ .
+ .
+ .
+ "Daugava"@en .
+ "1020000.0"^^ .
+ "8.79E10"^^ .
+ .
+ .
+ "678.0"^^ .
+ .
+ .
+ "-82.4"^^ .
+ .
+ .
+ .
+ "244620.288"^^ .
+ "331524.864"^^ .
+ .
+ .
+ "44.8"^^ .
+ "Lake Huron"@en .
+ "228.6"^^ .
+ "1.934721118420992E11"^^ .
+ .
+ "175.8696"^^ .
+ .
+ .
+ .
+ .
+ "59.436"^^ .
+ .
+ "6155740.8"^^ .
+ "44.8 -82.4"@en .
+ .
+