diff --git a/src/includes/api/TasksController.php b/src/includes/api/TasksController.php index 431f240..d7f038d 100644 --- a/src/includes/api/TasksController.php +++ b/src/includes/api/TasksController.php @@ -350,7 +350,7 @@ class TasksController extends ApiController { if (!$r || $listId == $r['list_id']) return false; // Check target list exists - if (!$db->sq("SELECT COUNT(*) FROM {$db->prefix}lists WHERE id=?", $listId)) + if (!$db->sq("SELECT COUNT(*) FROM {$db->prefix}lists WHERE id=?", [$listId])) return false; $ow = 1 + (int)$db->sq("SELECT MAX(ow) FROM {$db->prefix}todolist WHERE list_id=? AND compl=?", array($listId, $r['compl']?1:0)); diff --git a/src/includes/class.db.mysql.php b/src/includes/class.db.mysql.php index d706784..30dcb37 100644 --- a/src/includes/class.db.mysql.php +++ b/src/includes/class.db.mysql.php @@ -1,4 +1,4 @@ -affected = $dbh->exec($query); //throws PDOException + $this->affected = (int) $dbh->exec($query); //throws PDOException } // SELECT else @@ -28,17 +30,25 @@ class DatabaseResult_Mysql extends DatabaseResult_Abstract } } - function fetchRow() + function fetchRow(): ?array { - return $this->q->fetch(PDO::FETCH_NUM); + $res = $this->q->fetch(PDO::FETCH_NUM); + if ($res === false || !is_array($res)) { + return null; + } + return $res; } - function fetchAssoc() + function fetchAssoc(): ?array { - return $this->q->fetch(PDO::FETCH_ASSOC); + $res = $this->q->fetch(PDO::FETCH_ASSOC); + if ($res === false || !is_array($res)) { + return null; + } + return $res; } - function rowsAffected() + function rowsAffected(): int { return $this->affected; } @@ -49,14 +59,17 @@ class Database_Mysql extends Database_Abstract { /** @var PDO */ protected $dbh; - protected $affected = null; + + /** @var int */ + protected $affected = 0; + protected $dbname; function __construct() { } - function connect($params) + function connect(array $params): void { $host = $params['host']; $user = $params['user']; @@ -67,9 +80,7 @@ class Database_Mysql extends Database_Abstract PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ); $this->dbname = $db; - $this->dbh = new PDO("mysql:host=$host;dbname=$db", $user, $pass, $options); - return true; } @@ -78,12 +89,14 @@ class Database_Mysql extends Database_Abstract Returns single row of SELECT query as indexed array (FETCH_NUM). Returns single field value if resulting array has only one field. */ - function sq($query, $p = NULL) + function sq(string $query, ?array $values = null) { - $q = $this->_dq($query, $p); + $q = $this->_dq($query, $values); $res = $q->fetchRow(); - if ($res === false) return NULL; + if ($res === false || !is_array($res)) { + return null; + } if (sizeof($res) > 1) return $res; else return $res[0]; @@ -91,51 +104,44 @@ class Database_Mysql extends Database_Abstract /* Returns single row of SELECT query as dictionary array (FETCH_ASSOC). - Returns single field value if resulting array has only one field. */ - function sqa($query, $p = NULL) + function sqa(string $query, ?array $values = null): ?array { - $q = $this->_dq($query, $p); - + $q = $this->_dq($query, $values); $res = $q->fetchAssoc(); - if ($res === false) return NULL; - - if (sizeof($res) > 1) return $res; - else return $res[0]; + if ($res === false || !is_array($res)){ + return null; + } + return $res; } - function dq($query, $p = NULL) : DatabaseResult_Abstract + function dq(string $query, ?array $values = null) : DatabaseResult_Abstract { - return $this->_dq($query, $p); + return $this->_dq($query, $values); } /* for resultless queries like INSERT,UPDATE,DELETE */ - function ex($query, $p = NULL) + function ex(string $query, ?array $values = null): void { - $dbr = $this->_dq($query, $p, true); - return $this->affected(); + $this->_dq($query, $values, true); } - private function _dq($query, $p = NULL, $resultless = 0) : DatabaseResult_Abstract + private function _dq(string $query, ?array $values = null, bool $resultless = false) : DatabaseResult_Abstract { - if (!isset($p)) $p = array(); - elseif (!is_array($p)) $p = array($p); - - $m = explode('?', $query); - - if (sizeof($p) > 0) + if (null !== $values && sizeof($values) > 0) { - if (sizeof($m) < sizeof($p)+1) { + $m = explode('?', $query); + if (sizeof($m) < sizeof($values)+1) { throw new Exception("params to set MORE than query params"); } - if (sizeof($m) > sizeof($p)+1) { + if (sizeof($m) > sizeof($values)+1) { throw new Exception("params to set LESS than query params"); } $query = ""; for ($i=0; $iquote($p[$i])); + $query .= $m[$i]. $this->quote($values[$i]); } $query .= $m[$i]; } @@ -145,28 +151,35 @@ class Database_Mysql extends Database_Abstract return $dbr; } - function affected() + function affected(): int { return $this->affected; } - function quote($s) + function quote($value): string { - return '\''. addslashes($s). '\''; + if (null === $value) { + return 'null'; + } + return '\''. addslashes( (string) $value). '\''; } - function quoteForLike($format, $s) + function quoteForLike(string $format, string $string): string { - $s = str_replace(array('%','_'), array('\%','\_'), addslashes($s)); - return '\''. sprintf($format, $s). '\''; + $string = str_replace(array('%','_'), array('\%','\_'), addslashes($string)); + return '\''. sprintf($format, $string). '\''; } - function lastInsertId($name = null) + function lastInsertId(?string $name = null): ?string { - return $this->dbh->lastInsertId(); + $ret = $this->dbh->lastInsertId(); + if (false === $ret) { + return null; + } + return (string) $ret; } - function tableExists($table) + function tableExists(string $table): bool { $r = $this->sq("SELECT 1 FROM information_schema.tables WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?", array($this->dbname, $table) ); @@ -174,7 +187,7 @@ class Database_Mysql extends Database_Abstract return true; } - function tableFieldExists($table, $field): bool + function tableFieldExists(string $table, string $field): bool { $table = str_replace('`', '\\`', addslashes($table)); $q = $this->dq("DESCRIBE `$table`"); diff --git a/src/includes/class.db.mysqli.php b/src/includes/class.db.mysqli.php index 77b60da..a289468 100644 --- a/src/includes/class.db.mysqli.php +++ b/src/includes/class.db.mysqli.php @@ -1,4 +1,4 @@ -q = $dbh->query($query); //throws mysqli_sql_exception } - function fetchRow() + function fetchRow(): ?array { - return $this->q->fetch_row(); + $res = $this->q->fetch_row(); + if ($res === null || $res === false || !is_array($res)) { + return null; + } + return $res; } - function fetchAssoc() + function fetchAssoc(): ?array { - return $this->q->fetch_assoc(); + $res = $this->q->fetch_assoc(); + if ($res === null || $res === false || !is_array($res)) { + return null; + } + return $res; } } @@ -41,7 +49,7 @@ class Database_Mysqli extends Database_Abstract mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); } - function connect($params) + function connect(array $params): void { $host = $params['host']; $user = $params['user']; @@ -49,67 +57,66 @@ class Database_Mysqli extends Database_Abstract $db = $params['db']; $this->dbname = $db; $this->dbh = new mysqli($host, $user, $pass, $db); //throws mysqli_sql_exception - return true; } - function lastInsertId($name = null) + function lastInsertId(?string $name = null): ?string { - return $this->dbh->insert_id; + return (string) $this->dbh->insert_id; } - function sq($query, $p = NULL) + function sq(string $query, ?array $values = null) { - $q = $this->_dq($query, $p); + $q = $this->_dq($query, $values); $res = $q->fetchRow(); - if ($res === false || $res === null) return NULL; + if ($res === false || !is_array($res)) { + return null; + } if (sizeof($res) > 1) return $res; else return $res[0]; } - function sqa($query, $p = NULL) + /* + Returns single row of SELECT query as dictionary array (fetch_assoc()). + */ + function sqa(string $query, ?array $values = null): ?array { - $q = $this->_dq($query, $p); - + $q = $this->_dq($query, $values); $res = $q->fetchAssoc(); - if ($res === false || $res === null) return NULL; - + if ($res === false || !is_array($res)){ + return null; + } return $res; } - function dq($query, $p = NULL) : DatabaseResult_Abstract + function dq(string $query, ?array $values = null) : DatabaseResult_Abstract { - return $this->_dq($query, $p); + return $this->_dq($query, $values); } /* for resultless queries like INSERT,UPDATE,DELETE */ - function ex($query, $p = NULL) + function ex(string $query, ?array $values = null): void { - $dbr = $this->_dq($query, $p, 1); - return $this->affected(); + $this->_dq($query, $values, true); } - private function _dq($query, $p = NULL, $resultless = 0) : DatabaseResult_Abstract + private function _dq(string $query, ?array $values = null, bool $resultless = false) : DatabaseResult_Abstract { - if (!isset($p)) $p = array(); - elseif (!is_array($p)) $p = array($p); - - $m = explode('?', $query); - - if (sizeof($p) > 0) + if (null !== $values && sizeof($values) > 0) { - if (sizeof($m) < sizeof($p)+1) { + $m = explode('?', $query); + if (sizeof($m) < sizeof($values)+1) { throw new Exception("params to set MORE than query params"); } - if (sizeof($m) > sizeof($p)+1) { + if (sizeof($m) > sizeof($values)+1) { throw new Exception("params to set LESS than query params"); } $query = ""; for ($i=0; $i < sizeof($m)-1; $i++) { - $query .= $m[$i]. (is_null($p[$i]) ? 'NULL' : $this->quote($p[$i])); + $query .= $m[$i]. $this->quote($values[$i]); } $query .= $m[$i]; } @@ -117,23 +124,26 @@ class Database_Mysqli extends Database_Abstract return new DatabaseResult_Mysqli($this->dbh, $query, $resultless); } - function affected() + function affected(): int { - return $this->dbh->affected_rows; + return max( (int)$this->dbh->affected_rows, 0 ); } - function quote($s) + function quote($value): string { - return '\''. addslashes($s). '\''; + if (null === $value) { + return 'null'; + } + return '\''. addslashes( (string) $value). '\''; } - function quoteForLike($format, $s) + function quoteForLike(string $format, string $string): string { - $s = str_replace(array('%','_'), array('\%','\_'), addslashes($s)); - return '\''. sprintf($format, $s). '\''; + $string = str_replace(array('%','_'), array('\%','\_'), addslashes($string)); + return '\''. sprintf($format, $string). '\''; } - function tableExists($table) + function tableExists(string $table): bool { $r = $this->sq("SELECT 1 FROM information_schema.tables WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?", array($this->dbname, $table) ); @@ -141,7 +151,7 @@ class Database_Mysqli extends Database_Abstract return true; } - function tableFieldExists($table, $field): bool + function tableFieldExists(string $table, string $field): bool { $table = str_replace('`', '\\`', addslashes($table)); $q = $this->dq("DESCRIBE `$table`"); diff --git a/src/includes/class.db.sqlite3.php b/src/includes/class.db.sqlite3.php index a7cce4e..c3560d1 100644 --- a/src/includes/class.db.sqlite3.php +++ b/src/includes/class.db.sqlite3.php @@ -1,4 +1,4 @@ -affected = $dbh->exec($query); //throws PDOException + $this->affected = (int) $dbh->exec($query); //throws PDOException } // SELECT else @@ -27,17 +29,25 @@ class DatabaseResult_Sqlite3 extends DatabaseResult_Abstract } } - function fetchRow() + function fetchRow(): ?array { - return $this->q->fetch(PDO::FETCH_NUM); + $res = $this->q->fetch(PDO::FETCH_NUM); + if ($res === false || !is_array($res)) { + return null; + } + return $res; } - function fetchAssoc() + function fetchAssoc(): ?array { - return $this->q->fetch(PDO::FETCH_ASSOC); + $res = $this->q->fetch(PDO::FETCH_ASSOC); + if ($res === false || !is_array($res)) { + return null; + } + return $res; } - function rowsAffected() + function rowsAffected(): int { return $this->affected; } @@ -48,83 +58,82 @@ class Database_Sqlite3 extends Database_Abstract { /** @var PDO */ protected $dbh; - protected $affected = null; + + /** @var int */ + protected $affected = 0; function __construct() { } - function connect($params) + function connect(array $params): void { $filename = $params['filename']; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ); $this->dbh = new PDO("sqlite:$filename", null, null, $options); //throws PDOException - return true; } /* SELECT queries for single row */ - function sq($query, $p = NULL) + function sq(string $query, ?array $values = null) { - $q = $this->_dq($query, $p); + $q = $this->_dq($query, $values); $res = $q->fetchRow(); - if ($res === false) return NULL; + if ($res === false || !is_array($res)) { + return null; + } if (sizeof($res) > 1) return $res; else return $res[0]; } /* - SELECT queries for single row + Returns single row of SELECT query as dictionary array (FETCH_ASSOC). */ - function sqa($query, $p = NULL) + function sqa(string $query, ?array $values = null): ?array { - $q = $this->_dq($query, $p); - + $q = $this->_dq($query, $values); $res = $q->fetchAssoc(); - if ($res === false) return NULL; + if ($res === false || !is_array($res)) { + return null; + } return $res; } /* SELECT queries for multiple rows */ - function dq($query, $p = NULL) : DatabaseResult_Abstract + function dq(string $query, ?array $values = null) : DatabaseResult_Abstract { - return $this->_dq($query, $p); + return $this->_dq($query, $values); } /* for resultless queries like INSERT,UPDATE,DELETE */ - function ex($query, $p = NULL) + function ex(string $query, ?array $values = null): void { - $dbr = $this->_dq($query, $p, 1); - return $this->affected(); + $this->_dq($query, $values, true); } - private function _dq($query, $p = NULL, $resultless = 0) : DatabaseResult_Abstract + private function _dq(string $query, ?array $values = null, bool $resultless = false) : DatabaseResult_Abstract { - if (!isset($p)) $p = array(); - elseif (!is_array($p)) $p = array($p); - - $m = explode('?', $query); - - if (sizeof($p) > 0) + if (null !== $values && sizeof($values) > 0) { - if (sizeof($m) < sizeof($p)+1) { + $m = explode('?', $query); + if (sizeof($m) < sizeof($values)+1) { throw new Exception("params to set MORE than query params"); } - if (sizeof($m) > sizeof($p)+1) { + if (sizeof($m) > sizeof($values)+1) { throw new Exception("params to set LESS than query params"); } $query = ""; for ($i=0; $iquote($p[$i])); + $query .= $m[$i]. $this->quote($values[$i]); } $query .= $m[$i]; } @@ -134,41 +143,48 @@ class Database_Sqlite3 extends Database_Abstract return $dbr; } - function affected() + function affected(): int { return $this->affected; } - function quote($s) + function quote($value): string { - return $this->dbh->quote($s); + if (null === $value) { + return 'null'; + } + return $this->dbh->quote( (string) $value); } - function quoteForLike($format, $s) + function quoteForLike(string $format, string $string): string { - $s = str_replace(array('\\','%','_'), array('\\\\','\%','\_'), $s); - return $this->dbh->quote(sprintf($format, $s)). " ESCAPE '\'"; + $string = str_replace(array('\\','%','_'), array('\\\\','\%','\_'), $string); + return $this->dbh->quote(sprintf($format, $string)). " ESCAPE '\'"; } - function lastInsertId($name = null) + function lastInsertId(?string $name = null): ?string { - return $this->dbh->lastInsertId(); + $ret = $this->dbh->lastInsertId(); + if (false === $ret) { + return null; + } + return (string) $ret; } - function tableExists($table) + function tableExists(string $table): bool { - $exists = $this->sq("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", $table); + $exists = $this->sq("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", [$table]); if ($exists == "1") { return true; } - $exists = $this->sq("SELECT 1 FROM sqlite_temp_master WHERE type='table' AND name=?", $table); + $exists = $this->sq("SELECT 1 FROM sqlite_temp_master WHERE type='table' AND name=?", [$table]); if ($exists == "1") { return true; } return false; } - function tableFieldExists($table, $field): bool + function tableFieldExists(string $table, string $field): bool { $q = $this->dq("PRAGMA table_info(". $this->quote($table). ")"); while ($r = $q->fetchRow()) { diff --git a/src/includes/class.dbconnection.php b/src/includes/class.dbconnection.php index c7abf8e..1a16460 100644 --- a/src/includes/class.dbconnection.php +++ b/src/includes/class.dbconnection.php @@ -1,4 +1,4 @@ -db->sq("SELECT data,last_access FROM {$this->db->prefix}sessions WHERE id = ? AND expires >= $expire", $id); + $r = $this->db->sq("SELECT data,last_access FROM {$this->db->prefix}sessions WHERE id = ? AND expires >= $expire", [$id]); if ( is_null($r) ) return ''; // update last access time and set expires in 14 days @@ -63,7 +63,7 @@ class MTTSessionHandler implements SessionHandlerInterface */ public function write($id, $data): bool { - $exists = $this->db->sq("SELECT COUNT(*) FROM {$this->db->prefix}sessions WHERE id = ?", $id); + $exists = $this->db->sq("SELECT COUNT(*) FROM {$this->db->prefix}sessions WHERE id = ?", [$id]); if (!$exists) { // Create new session with 14 days lifetime $expire = time() + 14 * 86400; @@ -85,7 +85,7 @@ class MTTSessionHandler implements SessionHandlerInterface */ public function destroy($id): bool { - $this->db->ex("DELETE FROM {$this->db->prefix}sessions WHERE id = ?", $id); + $this->db->ex("DELETE FROM {$this->db->prefix}sessions WHERE id = ?", [$id]); return true; } @@ -98,8 +98,8 @@ class MTTSessionHandler implements SessionHandlerInterface { // We ignore php runtime 'session.gc_maxlifetime' $expire = time(); - $affected = $this->db->ex("DELETE FROM {$this->db->prefix}sessions WHERE expires < $expire"); - return $affected; + $this->db->ex("DELETE FROM {$this->db->prefix}sessions WHERE expires < $expire"); + return $this->db->affected(); } }