diff --git a/functions.inc.php b/functions.inc.php index 67814919..96e5051a 100644 --- a/functions.inc.php +++ b/functions.inc.php @@ -270,11 +270,11 @@ function get_password_expiration_value($domain) { $table_domain = table_by_key('domain'); $query = "SELECT password_expiry FROM $table_domain WHERE domain= :domain"; - $result = db_prepared_fetch_one($query, array('domain' => $domain)); + $result = db_query_one($query, array('domain' => $domain)); if (is_array($result) && isset($result['password_expiry'])) { return $result['password_expiry']; } - return null; + return 0; } /** @@ -507,7 +507,7 @@ function create_page_browser($idxfield, $querypart) { # get number of rows $query = "SELECT count(*) as counter FROM (SELECT $idxfield $querypart) AS tmp"; - $result = db_prepared_fetch_one($query); + $result = db_query_one($query); if ($result && isset($result['counter'])) { $count_results = $result['counter'] -1; # we start counting at 0, not 1 } @@ -522,7 +522,7 @@ function create_page_browser($idxfield, $querypart) { $initcount = "CREATE TEMPORARY SEQUENCE rowcount MINVALUE 0"; } if (!db_sqlite()) { - db_query($initcount); + db_execute($initcount); } # get labels for relevant rows (first and last of each page) @@ -556,8 +556,7 @@ function create_page_browser($idxfield, $querypart) { # CREATE TEMPORARY SEQUENCE foo MINVALUE 0 MAXVALUE $page_size_zerobase CYCLE # afterwards: DROP SEQUENCE foo - $result = db_query($query); - $result = db_prepared_fetch_all($query); + $result = db_query_all($query); foreach ($result as $k => $row) { if (isset($result[$k + 1])) { $row2 = $result[$k + 1]; @@ -569,7 +568,7 @@ function create_page_browser($idxfield, $querypart) { } if (db_pgsql()) { - db_query("DROP SEQUENCE rowcount"); + db_execute("DROP SEQUENCE rowcount"); } return $pagebrowser; @@ -599,7 +598,7 @@ function divide_quota($quota) { function check_owner($username, $domain) { $table_domain_admins = table_by_key('domain_admins'); - $result = db_prepared_fetch_all( + $result = db_query_all( "SELECT 1 FROM $table_domain_admins WHERE username= ? AND (domain = ? OR domain = 'ALL') AND active = ?" , array($username, $domain, db_get_boolean(true)) ); @@ -636,7 +635,7 @@ function list_domains_for_admin($username) { $pvalues = array(); - $result = db_prepared_fetch_one("SELECT username FROM $table_domain_admins WHERE username= :username AND domain='ALL'", array('username' => $username)); + $result = db_query_one("SELECT username FROM $table_domain_admins WHERE username= :username AND domain='ALL'", array('username' => $username)); if (empty($result)) { # not a superadmin $pvalues['username'] = $username; $pvalues['active'] = db_get_boolean(true); @@ -651,20 +650,14 @@ function list_domains_for_admin($username) { $query .= " WHERE " . join(' AND ', $condition); $query .= " ORDER BY $table_domain.domain"; - $result = db_prepared_fetch_all($query, $pvalues); + $result = db_query_all($query, $pvalues); return array_column($result, 'domain'); } if (!function_exists('array_column')) { - function array_column(array $array, $column) { - $retval = array(); - foreach ($array as $row) { - $retval[] = $row[$column]; - } - return $retval; - } + require_once(dirname(__FILE__) . '/lib/array_column.php'); } /** @@ -676,7 +669,7 @@ function list_domains() { $list = array(); $table_domain = table_by_key('domain'); - $result = db_prepared_fetch_all("SELECT domain FROM $table_domain WHERE domain!='ALL' ORDER BY domain"); + $result = db_query_all("SELECT domain FROM $table_domain WHERE domain!='ALL' ORDER BY domain"); $i = 0; foreach ($result as $row) { $list[$i] = $row['domain']; @@ -911,9 +904,9 @@ function _pacrypt_mysql_encrypt($pw, $pw_db) { $pw = escape_string($pw); if ($pw_db!="") { $values = array('pw' => $pw_db, 'salt' => substr($pw_db, 0, 2)); - $res = db_prepared_fetch_one("SELECT ENCRYPT(:pw,:salt) as result", $values); + $res = db_query_one("SELECT ENCRYPT(:pw,:salt) as result", $values); } else { - $res= db_prepared_fetch_one("SELECT ENCRYPT(:pw) as result", array('pw' => $pw)); + $res= db_query_one("SELECT ENCRYPT(:pw) as result", array('pw' => $pw)); } return $res['result']; @@ -1456,7 +1449,6 @@ function db_connect_with_errors() { global $CONF; global $DEBUG_TEXT; - $DEBUG_TEXT = ''; $error_text = ''; static $link; @@ -1465,11 +1457,15 @@ function db_connect_with_errors() { } $link = 0; - $options = [ + $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - ]; + ); $username_password = true; + $queries = array(); + + $dsn = null; + if (db_mysql()) { $dsn = "mysql:host={$CONF['database_host']};dbname={$CONF['database_name']};charset=UTF8"; if (Config::bool('database_use_ssl')) { @@ -1489,7 +1485,7 @@ function db_connect_with_errors() { } $dsn = "pgsql:host={$CONF['database_host']};port={$CONF['database_port']};dbname={$CONF['database_name']};charset=UTF8"; } else { - $error_text = "

DEBUG INFORMATION:
Invalid \$CONF['database_type']! Please fix your config.inc.php! $DEBUG_TEXT"; + die("

FATAL Error:
Invalid \$CONF['database_type']! Please fix your config.inc.php!

"); } if ($username_password) { @@ -1498,6 +1494,12 @@ function db_connect_with_errors() { $link = new PDO($dsn, null, null, $options); } + if (!empty($queries)) { + foreach ($queries as $q) { + $link->exec($q); + } + } + return array($link, $error_text); } @@ -1604,8 +1606,8 @@ function db_sqlite() { * @param array $values * @return array */ -function db_prepared_fetch_all($sql, array $values = array()) { - $r = db_prepared_query($sql, $values); +function db_query_all($sql, array $values = array()) { + $r = db_query($sql, $values); return $r['result']->fetchAll(PDO::FETCH_ASSOC); } @@ -1614,15 +1616,14 @@ function db_prepared_fetch_all($sql, array $values = array()) { * @param array $values * @return array */ -function db_prepared_fetch_one($sql, array $values = array()) { - $r = db_prepared_query($sql, $values); +function db_query_one($sql, array $values = array()) { + $r = db_query($sql, $values); return $r['result']->fetch(PDO::FETCH_ASSOC); } -function db_prepared_insert($sql, array $values = array()) { +function db_execute($sql, array $values = array(), $throw_errors = false) { $link = db_connect(); - $error_text = ''; try { $stmt = $link->prepare($sql); @@ -1630,6 +1631,9 @@ function db_prepared_insert($sql, array $values = array()) { } catch (PDOException $e) { $error_text = "Invalid query: " . $e->getMessage() . " caused by " . $sql ; error_log($error_text); + if ($throw_errors) { + throw $e; + } } return $stmt->rowCount(); } @@ -1640,7 +1644,7 @@ function db_prepared_insert($sql, array $values = array()) { * @param bool $ignore_errors - set to true to ignore errors. * @return array e.g. ['result' => PDOStatement, 'error' => string ] */ -function db_prepared_query($sql, array $values = array(), $ignore_errors = false) { +function db_query($sql, array $values = array(), $ignore_errors = false) { $link = db_connect(); $error_text = ''; @@ -1655,21 +1659,13 @@ function db_prepared_query($sql, array $values = array(), $ignore_errors = false } } - return array( "result" => $stmt, "error" => $error_text, ); } -/** - * @param string $query SQL to execute - * @param int $ignore_errors (default 0 aka do not ignore errors) - * @return array ['result' => resource, 'rows' => int ,'error' => string] - */ -function db_query($query, $ignore_errors = 0) { - return db_prepared_query($query, array(), $ignore_errors == 0); -} + @@ -1689,7 +1685,7 @@ function db_delete($table, $where, $delete, $additionalwhere='') { $query = "DELETE FROM $table WHERE $where = ? $additionalwhere"; - return db_prepared_insert($query, [$delete]); + return db_execute($query, array($delete)); } @@ -1749,7 +1745,7 @@ function db_insert($table, array $values, $timestamp = array('created', 'modifie } - return db_prepared_insert( + return db_execute( "INSERT INTO $table (" . implode(",", array_keys($values)) .") VALUES ($value_string)", $prepared_statment_values); } @@ -1772,6 +1768,8 @@ function db_update($table, $where_col, $where_value, $values, $timestamp = array $sql = "UPDATE $table_key SET "; + $pvalues = array(); + $set = array(); foreach ($values as $key => $value) { if (in_array($key, $timestamp)) { @@ -1803,7 +1801,7 @@ function db_update($table, $where_col, $where_value, $values, $timestamp = array $sql="UPDATE $table_key SET " . implode(",", $set) . " WHERE $where_col = :where"; - return db_prepared_insert($sql, $pvalues); + return db_execute($sql, $pvalues); } @@ -1974,12 +1972,12 @@ function check_db_version($error_out = true) { $table = table_by_key('config'); $sql = "SELECT value FROM $table WHERE name = 'version'"; - $row = db_prepared_fetch_one($sql); - + $row = db_query_one($sql); if (isset($row['value'])) { $dbversion = (int) $row['value']; } else { - db_query("INSERT INTO $table (name, value) VALUES ('version', '0')", 0); + db_execute("INSERT INTO $table (name, value) VALUES ('version', '0')"); + $dbversion = 0; } if (($dbversion < $min_db_version) && $error_out == true) { @@ -2006,7 +2004,7 @@ function gen_show_status($show_alias) { $stat_string = ""; $stat_goto = ""; - $stat_result = db_prepared_fetch_one("SELECT goto FROM $table_alias WHERE address=?", array($show_alias)); + $stat_result = db_query_one("SELECT goto FROM $table_alias WHERE address=?", array($show_alias)); if ($stat_result) { $stat_goto = $stat_result['goto']; @@ -2050,7 +2048,7 @@ function gen_show_status($show_alias) { $sql .= " OR address = ? "; } - $stat_result = db_prepared_fetch_one($sql, $v); + $stat_result = db_query_one($sql, $v); if (empty($stat_result)) { $stat_ok = 0; @@ -2071,7 +2069,7 @@ function gen_show_status($show_alias) { // Vacation CHECK if ( $CONF['show_vacation'] == 'YES' ) { - $stat_result = db_prepared_fetch_one("SELECT * FROM ". $CONF['database_tables']['vacation'] ." WHERE email = ? AND active = ? ", array($show_alias, db_get_boolean(true) )) ; + $stat_result = db_query_one("SELECT * FROM ". $CONF['database_tables']['vacation'] ." WHERE email = ? AND active = ? ", array($show_alias, db_get_boolean(true) )) ; if (!empty($stat_result)) { $stat_string .= "" . $CONF['show_status_text'] . " "; } else { @@ -2081,7 +2079,7 @@ function gen_show_status($show_alias) { // Disabled CHECK if ( $CONF['show_disabled'] == 'YES' ) { - $stat_result = db_prepared_fetch_one( + $stat_result = db_query_one( "SELECT * FROM ". $CONF['database_tables']['mailbox'] ." WHERE username = ? AND active = ?", array($show_alias, db_get_boolean(false)) ); @@ -2099,7 +2097,7 @@ function gen_show_status($show_alias) { $now = "datetime('now')"; } - $stat_result = db_prepared_fetch_one("SELECT * FROM ". $CONF['database_tables']['mailbox'] ." WHERE username = ? AND password_expiry <= ? AND active = ?", array( $show_alias , $now , db_get_boolean(true) )); + $stat_result = db_query_one("SELECT * FROM ". $CONF['database_tables']['mailbox'] ." WHERE username = ? AND password_expiry <= ? AND active = ?", array( $show_alias , $now , db_get_boolean(true) )); if (!empty($stat_result)) { $stat_string .= "" . $CONF['show_status_text'] . " "; diff --git a/model/AdminHandler.php b/model/AdminHandler.php index 318157a2..418627eb 100644 --- a/model/AdminHandler.php +++ b/model/AdminHandler.php @@ -154,8 +154,8 @@ class AdminHandler extends PFAHandler { 'domain' => 'ALL', ); $where = db_where_clause(array('username' => $this->id, 'domain' => 'ALL'), $this->struct); - $result = db_prepared_fetch_one("SELECT username from " . table_by_key('domain_admins') . " " . $where); - if(empty($result)) { + $result = db_query_one("SELECT username from " . table_by_key('domain_admins') . " " . $where); + if (empty($result)) { db_insert('domain_admins', $values, array('created')); # TODO: check for errors } diff --git a/model/CliDelete.php b/model/CliDelete.php index 5e532bef..c3391d93 100644 --- a/model/CliDelete.php +++ b/model/CliDelete.php @@ -5,7 +5,6 @@ */ class CliDelete extends Shell { - protected $handler_to_use = ''; /** * Execution method always used for tasks diff --git a/model/MailboxHandler.php b/model/MailboxHandler.php index 024e9d6e..2cf25937 100644 --- a/model/MailboxHandler.php +++ b/model/MailboxHandler.php @@ -481,7 +481,7 @@ class MailboxHandler extends PFAHandler { $table_mailbox = table_by_key('mailbox'); $query = "SELECT SUM(quota) as sum FROM $table_mailbox WHERE domain = ? AND username != ?"; - $rows = db_prepared_fetch_all($query, array($domain, $this->id)); + $rows = db_query_all($query, array($domain, $this->id)); $cur_quota_total = divide_quota($rows[0]['sum']); # convert to MB if (($quota + $cur_quota_total) > $limit['quota']) { diff --git a/model/PFAHandler.php b/model/PFAHandler.php index 59189d7e..3dff1473 100644 --- a/model/PFAHandler.php +++ b/model/PFAHandler.php @@ -728,7 +728,7 @@ abstract class PFAHandler { $db_result = array(); - $result = db_prepared_fetch_all($query); + $result = db_query_all($query); foreach ($result as $row) { $db_result[$row[$this->id_field]] = $row; @@ -822,7 +822,7 @@ abstract class PFAHandler { $values = array('username' => $username, 'active' => $active); - $result = db_prepared_fetch_all($query,$values); + $result = db_query_all($query,$values); if (sizeof($result) == 1) { $row = $result[0]; @@ -868,7 +868,7 @@ abstract class PFAHandler { $query = "SELECT token FROM $table WHERE {$this->id_field} = :username AND token <> '' AND active = :active AND NOW() < token_validity"; $values = array('username' => $username, 'active' => $active); - $result = db_prepared_fetch_all($query, $values); + $result = db_query_all($query, $values); if (sizeof($result) == 1) { $row = $result[0]; diff --git a/model/VacationHandler.php b/model/VacationHandler.php index 896ced59..fcdc900d 100644 --- a/model/VacationHandler.php +++ b/model/VacationHandler.php @@ -189,7 +189,7 @@ class VacationHandler extends PFAHandler { $table_vacation = table_by_key('vacation'); $sql = "SELECT * FROM $table_vacation WHERE email = :username"; - $result = db_prepared_fetch_all($sql, array('username' => $this->username)); + $result = db_query_all($sql, array('username' => $this->username)); if (sizeof($result) != 1) { return false; } @@ -243,8 +243,8 @@ class VacationHandler extends PFAHandler { // is there an entry in the vacaton table for the user, or do we need to insert? $table_vacation = table_by_key('vacation'); - $result = db_prepared_fetch_one("SELECT * FROM $table_vacation WHERE email = ?", array($this->username)); - if(!empty($result)) { + $result = db_query_one("SELECT * FROM $table_vacation WHERE email = ?", array($this->username)); + if (!empty($result)) { $result = db_update('vacation', 'email', $this->username, $vacation_data); } else { $result = db_insert('vacation', $vacation_data); diff --git a/psalm.xml b/psalm.xml index 5bba1f03..c974a905 100644 --- a/psalm.xml +++ b/psalm.xml @@ -17,6 +17,13 @@ + + + + + + + diff --git a/public/backup.php b/public/backup.php index 1744367a..900fd091 100644 --- a/public/backup.php +++ b/public/backup.php @@ -97,7 +97,7 @@ if ($_SERVER['REQUEST_METHOD'] == "GET") { ); for ($i = 0 ; $i < sizeof($tables) ; ++$i) { - $result = db_prepared_fetch_all("SHOW CREATE TABLE " . table_by_key($tables[$i])); + $result = db_query_all("SHOW CREATE TABLE " . table_by_key($tables[$i])); foreach ($result as $row) { fwrite($fh, array_pop($row)); } diff --git a/public/broadcast-message.php b/public/broadcast-message.php index 66aed0be..b2fe38f0 100644 --- a/public/broadcast-message.php +++ b/public/broadcast-message.php @@ -63,7 +63,7 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { if (intval(safepost('mailboxes_only')) == 0) { $q .= " UNION SELECT goto FROM $table_alias WHERE active='" . db_get_boolean(true) . "' AND ".db_in_clause("domain", $wanted_domains)."AND goto NOT IN ($q)"; } - $result = db_prepared_fetch_all($q); + $result = db_query_all($q); $recipients = array_column($result, 'username'); $recipients = array_unique($recipients); diff --git a/public/list-virtual.php b/public/list-virtual.php index 099dddf8..45770f0a 100644 --- a/public/list-virtual.php +++ b/public/list-virtual.php @@ -220,7 +220,7 @@ if (Config::bool('used_quotas') && (! Config::bool('new_quota_table'))) { $mailbox_pagebrowser_query = "$sql_from\n$sql_join\n$sql_where\n$sql_order" ; $query = "$sql_select\n$mailbox_pagebrowser_query\n$sql_limit"; -$result = db_prepared_fetch_all($query); +$result = db_query_all($query); $tMailbox = array(); diff --git a/public/setup.php b/public/setup.php index ba98098c..f9a5c186 100644 --- a/public/setup.php +++ b/public/setup.php @@ -303,7 +303,7 @@ if ($error != 0) { if ($error == 0 && $pw_check_result == 'pass_OK') { // XXX need to ensure domains table includes an 'ALL' entry. $table_domain = table_by_key('domain'); - $rows = db_prepared_fetch_all("SELECT * FROM $table_domain WHERE domain = 'ALL'"); + $rows = db_query_all("SELECT * FROM $table_domain WHERE domain = 'ALL'"); if (empty($rows)) { db_insert('domain', array('domain' => 'ALL', 'description' => '', 'transport' => '')); // all other fields should default through the schema. } diff --git a/public/upgrade.php b/public/upgrade.php index 568ee5b0..e708318c 100644 --- a/public/upgrade.php +++ b/public/upgrade.php @@ -20,7 +20,7 @@ if (!isset($CONF) || !is_array($CONF)) { */ function _pgsql_object_exists($name) { $sql = "select relname from pg_class where relname = '$name'"; - $r = db_prepared_fetch_one($sql); + $r = db_query_one($sql); return !empty($r); } @@ -48,7 +48,7 @@ function _pgsql_field_exists($table, $field) { AND pg_catalog.pg_table_is_visible(c.oid) ) AND a.attname = '$field' "; - $r = db_prepared_fetch_all($sql); + $r = db_query_all($sql); return !empty($r); } @@ -56,14 +56,14 @@ function _pgsql_field_exists($table, $field) { function _mysql_field_exists($table, $field) { # $table = table_by_key($table); # _mysql_field_exists is always called with the expanded table name - don't expand it twice $sql = "SHOW COLUMNS FROM $table LIKE ?"; - $r = db_prepared_fetch_all($sql, array( $field)); + $r = db_query_all($sql, array( $field)); return !empty($r); } function _sqlite_field_exists($table, $field) { $sql = "PRAGMA table_info($table)"; - $r = db_prepared_fetch_all($sql); + $r = db_query_all($sql); foreach ($r as $row) { if ($row[1] == $field) { @@ -225,8 +225,8 @@ function _do_upgrade($current_version) { } // Update config table so we don't run the same query twice in the future. $table = table_by_key('config'); - $sql = "UPDATE $table SET value = $i WHERE name = 'version'"; - db_query($sql); + $sql = "UPDATE $table SET value = :value WHERE name = 'version'"; + db_execute($sql, array('value' => $i)); }; } @@ -322,9 +322,13 @@ function db_query_parsed($sql, $ignore_errors = 0, $attach_mysql = "") { if ($debug) { printdebug($query); } - $result = db_query($query, $ignore_errors); - if ($debug) { - echo_out("
" . $result['error'] . "
"); + + try { + $result = db_execute($query, array(), true); + } catch (PDOException $e) { + if ($debug) { + echo_out("
" . $e->getMessage() . "
"); + } } } @@ -1410,7 +1414,7 @@ function upgrade_1284_mysql_pgsql() { # migrate the ALL domain to the superadmin column # Note: The ALL domain is not (yet) deleted to stay backwards-compatible for now (will be done in a later upgrade function) - $result = db_prepared_fetch_all("SELECT username FROM " . table_by_key('domain_admins') . " where domain='ALL'"); + $result = db_query_all("SELECT username FROM " . table_by_key('domain_admins') . " where domain='ALL'"); foreach ($result as $row) { printdebug("Setting superadmin flag for " . $row['username']); diff --git a/public/users/password-recover.php b/public/users/password-recover.php index 9013a5ca..32d55e55 100644 --- a/public/users/password-recover.php +++ b/public/users/password-recover.php @@ -70,7 +70,7 @@ if ($_SERVER['REQUEST_METHOD'] === "POST") { $token = $handler->getPasswordRecoveryCode($tUsername); if ($token !== false) { $table = table_by_key($context === 'users' ? 'mailbox' : 'admin'); - $row = db_prepared_fetch_one("SELECT * FROM $table WHERE username= :username", array('username' => $username)); + $row = db_query_one("SELECT * FROM $table WHERE username= :username", array('username' => $username)); // $row must exist unless there's a race condition? diff --git a/public/viewlog.php b/public/viewlog.php index 7918ecec..2c985146 100644 --- a/public/viewlog.php +++ b/public/viewlog.php @@ -66,7 +66,7 @@ if ($error != 1) { if (db_pgsql()) { $query = "SELECT extract(epoch from timestamp) as timestamp,username,domain,action,data FROM $table_log WHERE domain= :domain ORDER BY timestamp DESC LIMIT $page_size"; } - $result = db_prepared_fetch_all($query, array('domain' => $fDomain)); + $result = db_query_all($query, array('domain' => $fDomain)); foreach ($result as $row) { if (is_array($row) && db_pgsql()) { $row['timestamp'] = gmstrftime('%c %Z', $row['timestamp']); diff --git a/tests/DbBasicTest.php b/tests/DbBasicTest.php index 52fdc082..75292760 100644 --- a/tests/DbBasicTest.php +++ b/tests/DbBasicTest.php @@ -42,7 +42,7 @@ class DbBasicTest extends \PHPUnit\Framework\TestCase { ) ); - $ret = db_prepared_fetch_one("SELECT * FROM mailbox WHERE username = :username", array('username' => $username)); + $ret = db_query_one("SELECT * FROM mailbox WHERE username = :username", array('username' => $username)); $this->assertTrue(!empty($ret));