From 63b0b0544557563dfb1ac7d4626bacdc33c7bc97 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 23 Apr 2017 23:15:38 +0000 Subject: [PATCH 01/17] We now can work with prepared statements --- include/dba.php | 242 ++++++++++++++++++++++++++++++++++++++++++++---- include/dbm.php | 5 + 2 files changed, 229 insertions(+), 18 deletions(-) diff --git a/include/dba.php b/include/dba.php index 5066dcd56..0d983be32 100644 --- a/include/dba.php +++ b/include/dba.php @@ -15,12 +15,15 @@ require_once('include/datetime.php'); class dba { private $debug = 0; - private $db; + //private $db; + public $db; private $result; - private $driver; + //private $driver; + public $driver; public $connected = false; public $error = false; private $_server_info = ''; + private static $dbo; function __construct($server, $user, $pass, $db, $install = false) { $a = get_app(); @@ -93,6 +96,8 @@ class dba { } } $a->save_timestamp($stamp1, "network"); + + self::$dbo = $this; } /** @@ -462,22 +467,6 @@ class dba { return $id; } - function __destruct() { - if ($this->db) { - switch ($this->driver) { - case 'pdo': - $this->db = null; - break; - case 'mysqli': - $this->db->close(); - break; - case 'mysql': - mysql_close($this->db); - break; - } - } - } - /** * @brief Replaces ANY_VALUE() function by MIN() function, * if the database server does not support ANY_VALUE(). @@ -497,6 +486,223 @@ class dba { } return $sql; } + + function __destruct() { + if ($this->db) { + switch ($this->driver) { + case 'pdo': + $this->db = null; + break; + case 'mysqli': + $this->db->close(); + break; + case 'mysql': + mysql_close($this->db); + break; + } + } + } + + /** + * @brief Executes a prepared statement + * + * @param string $sql SQL statement + * @return object statement object + */ + static public function p($sql) { + $a = get_app(); + + $stamp1 = microtime(true); + + $args = func_get_args(); + unset($args[0]); + + if (!self::$dbo OR !self::$dbo->connected) { + return false; + } + + $sql = self::$dbo->any_value_fallback($sql); + + $orig_sql = $sql; + + if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) { + $sql = "/*".$a->callstack()." */ ".$sql; + } + + switch (self::$dbo->driver) { + case 'pdo': + $stmt = self::$dbo->db->prepare($sql); + + foreach ($args AS $param => $value) { + $stmt->bindParam($param, $args[$param]); + } + + $success = $stmt->execute(); + + if ($success) { + $retval = $stmt; + } else { + $retval = false; + } + + $errorInfo = self::$dbo->db->errorInfo(); + + if ($errorInfo) { + self::$dbo->error = $errorInfo[2]; + self::$dbo->errorno = $errorInfo[1]; + } + + break; + case 'mysqli': + $stmt = self::$dbo->db->stmt_init(); + + if (!$stmt->prepare($sql)) { + self::$dbo->error = self::$dbo->db->error; + self::$dbo->errorno = self::$dbo->db->errno; + $retval = false; + break; + } + + $params = ''; + $values = array(); + foreach ($args AS $param => $value) { + if (is_int($args[$param])) { + $params .= 'i'; + } elseif (is_float($args[$param])) { + $params .= 'd'; + } elseif (is_string($args[$param])) { + $params .= 's'; + } else { + $params .= 'b'; + } + $values[] = &$args[$param]; + } + + array_unshift($values, $params); + + call_user_func_array(array($stmt, 'bind_param'), $values); + + if (!$stmt->execute()) { + self::$dbo->error = self::$dbo->db->error; + self::$dbo->errorno = self::$dbo->db->errno; + $retval = false; + } elseif (method_exists($stmt, 'get_result')) { + // Is mysqlnd installed? + $retval = $stmt->get_result(); + } else { + $retval = $stmt; + } + break; + case 'mysql': + // For the old "mysql" functions we cannot use prepared statements + foreach ($args AS $param => $value) { + if (is_int($args[$param]) OR is_float($args[$param])) { + $replace = intval($args[$param]); + } else { + $replace = "'".dbesc($args[$param])."'"; + } + + $pos = strpos($sql, '?'); + if ($pos !== false) { + $sql = substr_replace($sql, $replace, $pos, 1); + } + } + + $retval = mysql_query($sql, self::$dbo->db); + if (mysql_errno(self::$dbo->db)) { + self::$dbo->error = mysql_error(self::$dbo->db); + self::$dbo->errorno = mysql_errno(self::$dbo->db); + } + break; + } + + $stamp2 = microtime(true); + $duration = (float)($stamp2 - $stamp1); + + $a->save_timestamp($stamp1, 'database'); + + if (strtolower(substr($orig_sql, 0, 6)) != "select") { + $a->save_timestamp($stamp1, "database_write"); + } + + return $retval; + } + + /** + * @brief Executes a prepared statement + * + * @param string $sql SQL statement + * @return boolean Was the query successfull? + */ + static public function e($sql) { + } + + /** + * @brief Fetch a single row + * + * @param object $stmt statement object + * @return array current row + */ + static public function fetch($stmt) { + switch (self::$dbo->driver) { + case 'pdo': + return $stmt->fetch(PDO::FETCH_ASSOC); + case 'mysqli': + // When mysqlnd is installed, we can use a shortcut + if (method_exists($stmt, 'fetch_array')) { + return $stmt->fetch_array(MYSQLI_ASSOC); + } + + // This code works, but is slow + + // Bind the result to a result array + $cols = array(); + + $cols_num = array(); + for ($x = 0; $x < $stmt->field_count; $x++) { + $cols[] = &$cols_num[$x]; + } + + call_user_func_array(array($stmt, 'bind_result'), $cols); + + $success = $stmt->fetch(); + + if (!$success) { + return false; + } + + // The slow part: + // We need to get the field names for the array keys + // It seems that there is no better way to do this. + $result = $stmt->result_metadata(); + + $columns = array(); + foreach ($cols_num AS $col) { + $field = $result->fetch_field(); + $columns[$field->name] = $col; + } + return $columns; + case 'mysql': + return mysql_fetch_array(self::$dbo->result, MYSQL_ASSOC); + } + } + + /** + * @brief Closes the current statement + * + * @param object $stmt statement object + * @return boolean was the close successfull? + */ + static public function close($stmt) { + switch (self::$dbo->driver) { + case 'pdo': + return $stmt->closeCursor(); + case 'mysqli': + return $stmt->close(); + case 'mysql': + return mysql_free_result($stmt); + } + } } function printable($s) { diff --git a/include/dbm.php b/include/dbm.php index d28d49d63..34cbcad3a 100644 --- a/include/dbm.php +++ b/include/dbm.php @@ -47,6 +47,11 @@ class dbm { if (is_bool($array)) { return $array; } + + if (is_object($array)) { + return true; + } + return (is_array($array) && count($array) > 0); } From 28a28f00a46c53f8b6b77ddd6a8c44a1f90662b8 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 06:13:42 +0000 Subject: [PATCH 02/17] New function skeleton for execution of queries --- include/auth_ejabberd.php | 2 ++ include/dba.php | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/auth_ejabberd.php b/include/auth_ejabberd.php index 8ee3af8e2..3ac72d916 100755 --- a/include/auth_ejabberd.php +++ b/include/auth_ejabberd.php @@ -32,6 +32,8 @@ * */ +die(); + if (sizeof($_SERVER["argv"]) == 0) die(); diff --git a/include/dba.php b/include/dba.php index 0d983be32..26da115b5 100644 --- a/include/dba.php +++ b/include/dba.php @@ -635,6 +635,10 @@ class dba { * @return boolean Was the query successfull? */ static public function e($sql) { + $args = func_get_args(); + + $stmt = self::p(); + self::close($stmt); } /** @@ -739,8 +743,6 @@ function dbesc($str) { // 'user', 1); function q($sql) { global $db; - $args = func_get_args(); - unset($args[0]); if ($db && $db->connected) { $sql = $db->any_value_fallback($sql); From 34bb34b9a421223985a3d626c772b2f205d96ec4 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 06:24:03 +0000 Subject: [PATCH 03/17] Lost lines are back --- include/dba.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dba.php b/include/dba.php index 26da115b5..ee62d309c 100644 --- a/include/dba.php +++ b/include/dba.php @@ -743,6 +743,8 @@ function dbesc($str) { // 'user', 1); function q($sql) { global $db; + $args = func_get_args(); + unset($args[0]); if ($db && $db->connected) { $sql = $db->any_value_fallback($sql); From 311c029bcf0efe6abd2881e5e8bf0a5b533491b0 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 06:26:49 +0000 Subject: [PATCH 04/17] Rearranged lines --- include/dba.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/dba.php b/include/dba.php index ee62d309c..d9ab38f42 100644 --- a/include/dba.php +++ b/include/dba.php @@ -467,6 +467,22 @@ class dba { return $id; } + function __destruct() { + if ($this->db) { + switch ($this->driver) { + case 'pdo': + $this->db = null; + break; + case 'mysqli': + $this->db->close(); + break; + case 'mysql': + mysql_close($this->db); + break; + } + } + } + /** * @brief Replaces ANY_VALUE() function by MIN() function, * if the database server does not support ANY_VALUE(). @@ -487,22 +503,6 @@ class dba { return $sql; } - function __destruct() { - if ($this->db) { - switch ($this->driver) { - case 'pdo': - $this->db = null; - break; - case 'mysqli': - $this->db->close(); - break; - case 'mysql': - mysql_close($this->db); - break; - } - } - } - /** * @brief Executes a prepared statement * From d636bcb9d3750f15c95cf7bfd8b9ba4bb27a0fc3 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 06:27:59 +0000 Subject: [PATCH 05/17] Restored privates variables --- include/dba.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/dba.php b/include/dba.php index d9ab38f42..b4a2d6782 100644 --- a/include/dba.php +++ b/include/dba.php @@ -15,11 +15,9 @@ require_once('include/datetime.php'); class dba { private $debug = 0; - //private $db; - public $db; + private $db; private $result; - //private $driver; - public $driver; + private $driver; public $connected = false; public $error = false; private $_server_info = ''; From 0c8a2fd34529ab6545148e875a337e7e25e21028 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 06:28:57 +0000 Subject: [PATCH 06/17] =?UTF-8?q?=C3=96rgs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/auth_ejabberd.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/auth_ejabberd.php b/include/auth_ejabberd.php index 3ac72d916..8ee3af8e2 100755 --- a/include/auth_ejabberd.php +++ b/include/auth_ejabberd.php @@ -32,8 +32,6 @@ * */ -die(); - if (sizeof($_SERVER["argv"]) == 0) die(); From d67338a89576737880c36e4b831b56d851304c5b Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 19:23:49 +0000 Subject: [PATCH 07/17] New function to check for the existance of data --- include/dba.php | 95 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/include/dba.php b/include/dba.php index b4a2d6782..4f931e020 100644 --- a/include/dba.php +++ b/include/dba.php @@ -252,7 +252,7 @@ class dba { break; } $stamp2 = microtime(true); - $duration = (float)($stamp2-$stamp1); + $duration = (float)($stamp2 - $stamp1); $a->save_timestamp($stamp1, "database"); @@ -529,27 +529,26 @@ class dba { switch (self::$dbo->driver) { case 'pdo': - $stmt = self::$dbo->db->prepare($sql); + if (!$stmt = self::$dbo->db->prepare($sql)) { + $errorInfo = self::$dbo->db->errorInfo(); + self::$dbo->error = $errorInfo[2]; + self::$dbo->errorno = $errorInfo[1]; + $retval = false; + break; + } foreach ($args AS $param => $value) { $stmt->bindParam($param, $args[$param]); } - $success = $stmt->execute(); - - if ($success) { - $retval = $stmt; - } else { - $retval = false; - } - - $errorInfo = self::$dbo->db->errorInfo(); - - if ($errorInfo) { + if (!$stmt->execute()) { + $errorInfo = self::$dbo->db->errorInfo(); self::$dbo->error = $errorInfo[2]; self::$dbo->errorno = $errorInfo[1]; + $retval = false; + } else { + $retval = $stmt; } - break; case 'mysqli': $stmt = self::$dbo->db->stmt_init(); @@ -614,15 +613,22 @@ class dba { break; } - $stamp2 = microtime(true); - $duration = (float)($stamp2 - $stamp1); - $a->save_timestamp($stamp1, 'database'); - if (strtolower(substr($orig_sql, 0, 6)) != "select") { - $a->save_timestamp($stamp1, "database_write"); - } + if (x($a->config,'system') && x($a->config['system'], 'db_log')) { + $stamp2 = microtime(true); + $duration = (float)($stamp2 - $stamp1); + + if (($duration > $a->config["system"]["db_loglimit"])) { + $duration = round($duration, 3); + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + @file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t". + basename($backtrace[1]["file"])."\t". + $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t". + substr($sql, 0, 2000)."\n", FILE_APPEND); + } + } return $retval; } @@ -633,10 +639,49 @@ class dba { * @return boolean Was the query successfull? */ static public function e($sql) { + $a = get_app(); + + $stamp = microtime(true); + $args = func_get_args(); - $stmt = self::p(); + $stmt = call_user_func_array('self::p', $args); + + if (is_bool($stmt)) { + $retval = $stmt; + } elseif (is_object($stmt)) { + $retval = true; + } else { + $retval = false; + } + self::close($stmt); + + $a->save_timestamp($stamp, "database_write"); + + return $retval; + } + + /** + * @brief Check if data exists + * + * @param string $sql SQL statement + * @return boolean Are there rows for that query? + */ + static public function exists($sql) { + $args = func_get_args(); + + $stmt = call_user_func_array('self::p', $args); + + if (is_bool($stmt)) { + $retval = $stmt; + } else { + $retval = is_array(self::fetch($stmt)); + } + + self::close($stmt); + + return $retval; } /** @@ -646,6 +691,10 @@ class dba { * @return array current row */ static public function fetch($stmt) { + if (!is_object($stmt)) { + return false; + } + switch (self::$dbo->driver) { case 'pdo': return $stmt->fetch(PDO::FETCH_ASSOC); @@ -696,6 +745,10 @@ class dba { * @return boolean was the close successfull? */ static public function close($stmt) { + if (!is_object($stmt)) { + return false; + } + switch (self::$dbo->driver) { case 'pdo': return $stmt->closeCursor(); From 9959da5a1ca3c74628ddc0ed2a38b7d339521fb6 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 20:32:35 +0000 Subject: [PATCH 08/17] New function to calculate rows --- include/dba.php | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/include/dba.php b/include/dba.php index 4f931e020..c8c9ecc60 100644 --- a/include/dba.php +++ b/include/dba.php @@ -587,6 +587,7 @@ class dba { // Is mysqlnd installed? $retval = $stmt->get_result(); } else { + $stmt->store_result(); $retval = $stmt; } break; @@ -676,7 +677,7 @@ class dba { if (is_bool($stmt)) { $retval = $stmt; } else { - $retval = is_array(self::fetch($stmt)); + $retval = (self::rows($stmt) > 0); } self::close($stmt); @@ -684,6 +685,24 @@ class dba { return $retval; } + /** + * @brief Returnr the number of rows of a statement + * + * @param object Statement object + * @return int Number of rows + */ + static public function rows($stmt) { + switch (self::$dbo->driver) { + case 'pdo': + return $stmt->rowCount(); + case 'mysqli': + return $stmt->num_rows; + case 'mysql': + return mysql_num_rows($stmt); + } + return 0; + } + /** * @brief Fetch a single row * @@ -726,11 +745,11 @@ class dba { // We need to get the field names for the array keys // It seems that there is no better way to do this. $result = $stmt->result_metadata(); + $fields = $result->fetch_fields(); $columns = array(); - foreach ($cols_num AS $col) { - $field = $result->fetch_field(); - $columns[$field->name] = $col; + foreach ($cols_num AS $param => $col) { + $columns[$fields[$param]->name] = $col; } return $columns; case 'mysql': From 82f13441bc5aa0e74fcbef6fcda704c0464a5287 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 21:02:51 +0000 Subject: [PATCH 09/17] Removed old functions --- include/dba.php | 61 +----------------------------------------- include/dbclean.php | 65 +++++++++++++++++++++++++-------------------- include/tags.php | 17 ++++++------ include/threads.php | 24 +++++++---------- 4 files changed, 55 insertions(+), 112 deletions(-) diff --git a/include/dba.php b/include/dba.php index c8c9ecc60..cf1c962b1 100644 --- a/include/dba.php +++ b/include/dba.php @@ -134,30 +134,6 @@ class dba { return $r[0]['db']; } - /** - * @brief Returns the number of rows - * - * @return integer - */ - public function num_rows() { - if (!$this->result) { - return 0; - } - - switch ($this->driver) { - case 'pdo': - $rows = $this->result->rowCount(); - break; - case 'mysqli': - $rows = $this->result->num_rows; - break; - case 'mysql': - $rows = mysql_num_rows($this->result); - break; - } - return $rows; - } - /** * @brief Analyze a database query and log this if some conditions are met. * @@ -382,41 +358,6 @@ class dba { return($r); } - public function qfetch() { - $x = false; - - if ($this->result) { - switch ($this->driver) { - case 'pdo': - $x = $this->result->fetch(PDO::FETCH_ASSOC); - break; - case 'mysqli': - $x = $this->result->fetch_array(MYSQLI_ASSOC); - break; - case 'mysql': - $x = mysql_fetch_array($this->result, MYSQL_ASSOC); - break; - } - } - return($x); - } - - public function qclose() { - if ($this->result) { - switch ($this->driver) { - case 'pdo': - $this->result->closeCursor(); - break; - case 'mysqli': - $this->result->free_result(); - break; - case 'mysql': - mysql_free_result($this->result); - break; - } - } - } - public function dbg($dbg) { $this->debug = $dbg; } @@ -691,7 +632,7 @@ class dba { * @param object Statement object * @return int Number of rows */ - static public function rows($stmt) { + static public function num_rows($stmt) { switch (self::$dbo->driver) { case 'pdo': return $stmt->rowCount(); diff --git a/include/dbclean.php b/include/dbclean.php index bff4ff2a2..64ceb51d3 100644 --- a/include/dbclean.php +++ b/include/dbclean.php @@ -43,96 +43,103 @@ function remove_orphans($stage = 0) { if (($stage == 1) OR ($stage == 0)) { logger("Deleting old global item entries from item table without user copy"); - if ($db->q("SELECT `id` FROM `item` WHERE `uid` = 0 + $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) - AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found global item orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting old global item entries from item table without user copy"); } if (($stage == 2) OR ($stage == 0)) { logger("Deleting items without parents"); - if ($db->q("SELECT `id` FROM `item` WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `id` FROM `item` WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found item orphans without parents: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting items without parents"); } if (($stage == 3) OR ($stage == 0)) { logger("Deleting orphaned data from thread table"); - if ($db->q("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found thread orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `thread` WHERE `iid` = %d", intval($orphan["iid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from thread table"); } if (($stage == 4) OR ($stage == 0)) { logger("Deleting orphaned data from notify table"); - if ($db->q("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found notify orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `notify` WHERE `iid` = %d", intval($orphan["iid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from notify table"); } if (($stage == 5) OR ($stage == 0)) { logger("Deleting orphaned data from notify-threads table"); - if ($db->q("SELECT `id` FROM `notify-threads` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `id` FROM `notify-threads` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found notify-threads orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `notify-threads` WHERE `id` = %d", intval($orphan["id"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from notify-threads table"); } if (($stage == 6) OR ($stage == 0)) { logger("Deleting orphaned data from sign table"); - if ($db->q("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found sign orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `sign` WHERE `iid` = %d", intval($orphan["iid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from sign table"); } if (($stage == 7) OR ($stage == 0)) { logger("Deleting orphaned data from term table"); - if ($db->q("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found term orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `term` WHERE `oid` = %d", intval($orphan["oid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from term table"); } diff --git a/include/tags.php b/include/tags.php index 0a0943847..d809da2bf 100644 --- a/include/tags.php +++ b/include/tags.php @@ -111,12 +111,11 @@ function create_tags_from_itemuri($itemuri, $uid) { } function update_items() { - global $db; - $messages = $db->q("SELECT `oid`,`item`.`guid`, `item`.`created`, `item`.`received` FROM `term` INNER JOIN `item` ON `item`.`id`=`term`.`oid` WHERE `term`.`otype` = 1 AND `term`.`guid` = ''", true); + $messages = dba::p("SELECT `oid`,`item`.`guid`, `item`.`created`, `item`.`received` FROM `term` INNER JOIN `item` ON `item`.`id`=`term`.`oid` WHERE `term`.`otype` = 1 AND `term`.`guid` = ''"); - logger("fetched messages: ".count($messages)); - while ($message = $db->qfetch()) { + logger("fetched messages: ".dba::num_rows($messages)); + while ($message = dba::fetch($messages)) { if ($message["uid"] == 0) { $global = true; @@ -135,15 +134,15 @@ function update_items() { intval($global), intval(TERM_OBJ_POST), intval($message["oid"])); } - $db->qclose(); + dba::close($messages); - $messages = $db->q("SELECT `guid` FROM `item` WHERE `uid` = 0", true); + $messages = dba::p("SELECT `guid` FROM `item` WHERE `uid` = 0"); - logger("fetched messages: ".count($messages)); - while ($message = $db->qfetch()) { + logger("fetched messages: ".dba::num_rows($messages)); + while ($message = dba::fetch(messages)) { q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($message["guid"])); } - $db->qclose(); + dba::close($messages); } ?> diff --git a/include/threads.php b/include/threads.php index c214cf264..3d0aa05c3 100644 --- a/include/threads.php +++ b/include/threads.php @@ -251,19 +251,17 @@ function delete_thread($itemid, $itemuri = "") { } function update_threads() { - global $db; - logger("update_threads: start"); - $messages = $db->q("SELECT `id` FROM `item` WHERE `id` = `parent`", true); + $messages = dba::p("SELECT `id` FROM `item` WHERE `id` = `parent`"); - logger("update_threads: fetched messages: ".count($messages)); + logger("update_threads: fetched messages: ".dba::num_rows($messages)); - while ($message = $db->qfetch()) { + while ($message = dba::fetch($messages)) { add_thread($message["id"]); add_shadow_thread($message["id"]); } - $db->qclose(); + dba::close($messages); } function update_threads_mention() { @@ -283,18 +281,16 @@ function update_threads_mention() { function update_shadow_copy() { - global $db; - logger("start"); - $messages = $db->q(sprintf("SELECT `iid` FROM `thread` WHERE `uid` != 0 AND `network` IN ('', '%s', '%s', '%s') - AND `visible` AND NOT `deleted` AND NOT `moderated` AND NOT `private` ORDER BY `created`", - NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS), true); + $messages = dba::p("SELECT `iid` FROM `thread` WHERE `uid` != 0 AND `network` IN ('', ?, ?, ?) + AND `visible` AND NOT `deleted` AND NOT `moderated` AND NOT `private` ORDER BY `created`", + NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS); - logger("fetched messages: ".count($messages)); - while ($message = $db->qfetch()) + logger("fetched messages: ".dba::num_rows($messages)); + while ($message = dba::fetch($messages)) add_shadow_thread($message["iid"]); - $db->qclose(); + dba::close($messages); } ?> From ed437e978a17174dc01c5d3da75a09a659748eb6 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 21:18:30 +0000 Subject: [PATCH 10/17] Code cleanup --- include/dba.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/dba.php b/include/dba.php index cf1c962b1..5760d782c 100644 --- a/include/dba.php +++ b/include/dba.php @@ -462,8 +462,6 @@ class dba { $sql = self::$dbo->any_value_fallback($sql); - $orig_sql = $sql; - if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) { $sql = "/*".$a->callstack()." */ ".$sql; } @@ -676,9 +674,7 @@ class dba { call_user_func_array(array($stmt, 'bind_result'), $cols); - $success = $stmt->fetch(); - - if (!$success) { + if (!$stmt->fetch()) { return false; } From b5f10e5ddb14ef079ece22db963cc9617d8ea4ec Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 21:20:24 +0000 Subject: [PATCH 11/17] Replace spaces by tabs --- include/dba.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/dba.php b/include/dba.php index 5760d782c..607936df8 100644 --- a/include/dba.php +++ b/include/dba.php @@ -555,20 +555,20 @@ class dba { $a->save_timestamp($stamp1, 'database'); - if (x($a->config,'system') && x($a->config['system'], 'db_log')) { + if (x($a->config,'system') && x($a->config['system'], 'db_log')) { $stamp2 = microtime(true); $duration = (float)($stamp2 - $stamp1); - if (($duration > $a->config["system"]["db_loglimit"])) { - $duration = round($duration, 3); - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - @file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t". - basename($backtrace[1]["file"])."\t". - $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t". - substr($sql, 0, 2000)."\n", FILE_APPEND); - } - } + if (($duration > $a->config["system"]["db_loglimit"])) { + $duration = round($duration, 3); + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + @file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t". + basename($backtrace[1]["file"])."\t". + $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t". + substr($sql, 0, 2000)."\n", FILE_APPEND); + } + } return $retval; } From ec0d2a1a038617c99ae57ee2329bbcbe0b2cb1e6 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 21:23:00 +0000 Subject: [PATCH 12/17] Little spelling problem --- include/dba.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dba.php b/include/dba.php index 607936df8..beb72bbc2 100644 --- a/include/dba.php +++ b/include/dba.php @@ -625,7 +625,7 @@ class dba { } /** - * @brief Returnr the number of rows of a statement + * @brief Returns the number of rows of a statement * * @param object Statement object * @return int Number of rows From eb63ce5df5ceb8415c0345f4604eccaf09972fc5 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 21:36:04 +0000 Subject: [PATCH 13/17] Free results --- include/dba.php | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dba.php b/include/dba.php index beb72bbc2..4eaa1e314 100644 --- a/include/dba.php +++ b/include/dba.php @@ -709,6 +709,7 @@ class dba { case 'pdo': return $stmt->closeCursor(); case 'mysqli': + return $stmt->free_result(); return $stmt->close(); case 'mysql': return mysql_free_result($stmt); From 8de510e635022c3d551a1eb11c78f6677cc41a02 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 24 Apr 2017 21:51:47 +0000 Subject: [PATCH 14/17] We weren't able to test mysqlnd, so better remove the code --- include/dba.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/dba.php b/include/dba.php index 4eaa1e314..d4a05ff94 100644 --- a/include/dba.php +++ b/include/dba.php @@ -522,9 +522,6 @@ class dba { self::$dbo->error = self::$dbo->db->error; self::$dbo->errorno = self::$dbo->db->errno; $retval = false; - } elseif (method_exists($stmt, 'get_result')) { - // Is mysqlnd installed? - $retval = $stmt->get_result(); } else { $stmt->store_result(); $retval = $stmt; @@ -657,11 +654,6 @@ class dba { case 'pdo': return $stmt->fetch(PDO::FETCH_ASSOC); case 'mysqli': - // When mysqlnd is installed, we can use a shortcut - if (method_exists($stmt, 'fetch_array')) { - return $stmt->fetch_array(MYSQLI_ASSOC); - } - // This code works, but is slow // Bind the result to a result array From 67bae59c666a308e62b0d5c8cad28d5ec52b5cf1 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 25 Apr 2017 05:11:04 +0000 Subject: [PATCH 15/17] Small corrections --- include/dba.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/dba.php b/include/dba.php index d4a05ff94..3383da86b 100644 --- a/include/dba.php +++ b/include/dba.php @@ -443,8 +443,8 @@ class dba { } /** - * @brief Executes a prepared statement - * + * @brief Executes a prepared statement that returns data + * @usage Example: $r = p("SELECT * FROM `item` WHERE `guid` = ?", $guid); * @param string $sql SQL statement * @return object statement object */ @@ -529,6 +529,7 @@ class dba { break; case 'mysql': // For the old "mysql" functions we cannot use prepared statements + $offset = 0; foreach ($args AS $param => $value) { if (is_int($args[$param]) OR is_float($args[$param])) { $replace = intval($args[$param]); @@ -536,10 +537,11 @@ class dba { $replace = "'".dbesc($args[$param])."'"; } - $pos = strpos($sql, '?'); + $pos = strpos($sql, '?', $offset); if ($pos !== false) { $sql = substr_replace($sql, $replace, $pos, 1); } + $offset = $pos + strlen($replace); } $retval = mysql_query($sql, self::$dbo->db); @@ -570,10 +572,10 @@ class dba { } /** - * @brief Executes a prepared statement + * @brief Executes a prepared statement like UPDATE or INSERT that doesn't return data * * @param string $sql SQL statement - * @return boolean Was the query successfull? + * @return boolean Was the query successfull? False is returned only if an error occurred */ static public function e($sql) { $a = get_app(); From 4c131362b3adcd14664da1f4e3a449fbb8b1b0ea Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 25 Apr 2017 05:20:34 +0000 Subject: [PATCH 16/17] Better debugging --- include/dba.php | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/include/dba.php b/include/dba.php index 3383da86b..f3af9e7c3 100644 --- a/include/dba.php +++ b/include/dba.php @@ -442,6 +442,31 @@ class dba { return $sql; } + /** + * @brief Replaces the ? placeholders with the parameters in the $args array + * + * @param string $sql SQL query + * @param array $args The parameters that are to replace the ? placeholders + * @return string The replaced SQL query + */ + static private function replace_parameters($sql, $args) { + $offset = 0; + foreach ($args AS $param => $value) { + if (is_int($args[$param]) OR is_float($args[$param])) { + $replace = intval($args[$param]); + } else { + $replace = "'".dbesc($args[$param])."'"; + } + + $pos = strpos($sql, '?', $offset); + if ($pos !== false) { + $sql = substr_replace($sql, $replace, $pos, 1); + } + $offset = $pos + strlen($replace); + } + return $sql; + } + /** * @brief Executes a prepared statement that returns data * @usage Example: $r = p("SELECT * FROM `item` WHERE `guid` = ?", $guid); @@ -529,22 +554,7 @@ class dba { break; case 'mysql': // For the old "mysql" functions we cannot use prepared statements - $offset = 0; - foreach ($args AS $param => $value) { - if (is_int($args[$param]) OR is_float($args[$param])) { - $replace = intval($args[$param]); - } else { - $replace = "'".dbesc($args[$param])."'"; - } - - $pos = strpos($sql, '?', $offset); - if ($pos !== false) { - $sql = substr_replace($sql, $replace, $pos, 1); - } - $offset = $pos + strlen($replace); - } - - $retval = mysql_query($sql, self::$dbo->db); + $retval = mysql_query(self::replace_parameters($sql, $args), self::$dbo->db); if (mysql_errno(self::$dbo->db)) { self::$dbo->error = mysql_error(self::$dbo->db); self::$dbo->errorno = mysql_errno(self::$dbo->db); @@ -562,10 +572,11 @@ class dba { if (($duration > $a->config["system"]["db_loglimit"])) { $duration = round($duration, 3); $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + @file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t". basename($backtrace[1]["file"])."\t". $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t". - substr($sql, 0, 2000)."\n", FILE_APPEND); + substr(self::replace_parameters($sql, $args), 0, 2000)."\n", FILE_APPEND); } } return $retval; From d11e3afc6c5ec1bfd6ddca11175514fe88b39672 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 25 Apr 2017 16:05:26 +0000 Subject: [PATCH 17/17] Added class description --- include/dba.php | 1 + include/dbm.php | 1 + 2 files changed, 2 insertions(+) diff --git a/include/dba.php b/include/dba.php index f3af9e7c3..76791911a 100644 --- a/include/dba.php +++ b/include/dba.php @@ -10,6 +10,7 @@ require_once('include/datetime.php'); * When logging, all binary info is converted to text and html entities are escaped so that * the debugging stream is safe to view within both terminals and web pages. * + * This class is for the low level database stuff that does driver specific things. */ class dba { diff --git a/include/dbm.php b/include/dbm.php index 34cbcad3a..3430577da 100644 --- a/include/dbm.php +++ b/include/dbm.php @@ -2,6 +2,7 @@ /** * @brief This class contain functions for the database management * + * This class contains functions that doesn't need to know if pdo, mysqli or whatever is used. */ class dbm { /**