. * */ namespace Vvveb\System\Db; use Vvveb\System\Event; class Sqlite extends DBDriver { private static $link = null; //public $error; private $stmt; public $affected_rows = 0; public $num_rows = 0; public $insert_id = null; public $prefix = ''; //'vv_'; public $quote = '`'; public static function version() { if (self :: $link) { return mysqli_get_server_version(self :: $link); } } public static function info() { if (self :: $link) { return self :: $link->version(); } } public function error() { if (self :: $link) { return self :: $link->lastErrorMsg() ?? ''; } } public function errorCode() { if (self :: $link) { return self :: $link->lastErrorCode() ?? 0; } } public function get_result($stmt) { return $stmt; $result = new \SQLite3Stmt($stmt); return $result; } public function __construct($filename = DB_HOST, $dbname = DB_NAME, $user = DB_USER, $pass = DB_PASS, $port = null, $prefix = DB_PREFIX) { //return $this->connect($host, $dbname, $user, $pass, $port, $prefix); } public function connect($filename = DB_HOST, $dbname = DB_NAME, $user = DB_USER, $pass = DB_PASS, $port = null, $prefix = DB_PREFIX) { if (self :: $link) { return self :: $link; } try { self :: $link = new \SQLite3($filename); //, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); } catch (\Exception $e) { $errorMessage = str_replace($pass,'*****', $e->getMessage()); throw new \Exception($errorMessage, $e->getCode()); } self :: $link->enableExceptions(true); return self :: $link; } /* * Get all columns for a table used for sanitizing input */ function getColumnsMeta($tableName, $comment = false) { $sql = "SELECT type as t, name, dflt_value as d, `notnull` as n FROM pragma_table_info('$tableName');"; if ($result = $this->query($sql)) { //$columns = $result->fetch_all(MYSQLI_ASSOC); $columns = []; while ($row = $result->fetchArray(SQLITE3_ASSOC)) { $columns[$row['name']] = $row; } /* free result set */ $result->finalize(); return $columns; } else { } return false; } function getTableNames($db = DB_NAME) { $sql = "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_search%' ORDER BY name"; if ($result = $this->query($sql)) { //$columns = $result->fetch_all(MYSQLI_ASSOC); $names = []; while ($row = $result->fetchArray(SQLITE3_ASSOC)) { //$names[] = $row; $names[] = $row['name']; } /* free result set */ $result->finalize(); return $names; } else { } return false; } public function escape($string) { if (is_string($string)) { return self :: $link->escapeString($string); } if (is_null($string)) { return 'null'; } return $string; } public function escapeLiteral($string) { return $this->escape($string); } public function sqlLimit($start, $limit) { return "LIMIT $start, $limit"; } public function fetchOne($result) { $return = false; if ($result) { $return = $result->fetchArray(SQLITE3_NUM)[0] ?? null; } return $return; } public function fetchArray($result) { $return = false; if ($result) { $return = $result->fetchArray(SQLITE3_ASSOC); } return $return; } public function fetchAll($result) { $return = []; if ($result) { while ($row = $result->fetchArray(SQLITE3_ASSOC)) { $return[] = $row; } } return $return; } public function query($sql) { if (! self :: $link) { $this->connect(); } $result = false; try { $result = self :: $link->query($sql); if (LOG_SQL_QUERIES) { error_log($sql); } if ($result) { $this->affected_rows = self :: $link->changes(); $this->insert_id = self :: $link->lastInsertRowID(); $this->num_rows = $result->numColumns() && $result->columnType(0) != SQLITE3_NULL; //$result->finalize(); } else { $message = $this->error() . "\n" . $sql . "\n - " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true); throw new \Exception($message, $this->errorCode()); } } catch (\Exception $e) { $message = $e->getMessage() . "\n$sql\n" . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true); throw new \Exception($message, $e->getCode()); } return $result; } public function multi_query($sql) { $results = []; $queries = preg_split('/;\n/', $sql); foreach ($queries as $query) { if (empty(trim($query))) { continue; } if (LOG_SQL_QUERIES) { error_log($sql); } try { $result = self :: $link->query("$query;"); if ($result) { $this->affected_rows = self :: $link->changes(); $this->insert_id = self :: $link->lastInsertRowID(); $this->num_rows = $result->numColumns() && $result->columnType(0) != SQLITE3_NULL; //$result->finalize(); } else { $message = $this->error() . "\n" . $sql . "\n - " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true); throw new \Exception($message, $this->errorCode()); } $results[] = $result; } catch (\Exception $e) { $message = $e->getMessage() . "\n$sql\n" . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true); throw new \Exception($message, $e->getCode()); } } return $results; } public function close() { if (self :: $link) { return self :: $link->close(); } } // Prepare public function execute($sql, $params = [], $paramTypes = []) { list($sql, $params) = Event::trigger(__CLASS__,__FUNCTION__, $sql, $params); //save orig sql for debugging info $origSql = $sql; if (! self :: $link) { $this->connect(); } list($parameters, $types) = $this->paramsToQmark($sql, $params, $paramTypes); try { $stmt = self::$link->prepare($sql); } catch (\Exception $e) { $message = $e->getMessage() . "\n" . $this->debugSql($origSql, $params, $paramTypes) . "\n - " . $origSql . "\n - " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true); throw new \Exception($message, $e->getCode()); } if ($stmt/* && ! empty($paramTypes)*/) { foreach ($parameters as $key => $value) { $type = $types[$key] ?? 's'; $type = ($type == 'i') ? SQLITE3_INTEGER : SQLITE3_TEXT; $index = (int)$key + 1; $stmt->bindValue($index, $value, $type); } } else { if (DEBUG) { error_log((self :: $link->lastErrorMsg ?? '') . ' ' . $this->debugSql($origSql, $params, $paramTypes)); } } if (LOG_SQL_QUERIES) { error_log($this->debugSql($origSql, $params, $paramTypes)); } if ($stmt) { $result = null; try { if ($result = $stmt->execute()) { $this->affected_rows = self :: $link->changes(); $this->insert_id = self :: $link->lastInsertRowID(); $this->num_rows = $result->numColumns() && $result->columnType(0) != SQLITE3_NULL; return $result; } else { error_log(print_r($result, 1)); error_log($this->debugSql($sql, $params, $paramTypes)); } } catch (\Exception $e) { $message = $e->getMessage() . "\n" . $origSql . "\n" . $this->debugSql($origSql, $params, $paramTypes) . "\n" . print_r($parameters, 1) . $types . "\n" . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true); throw new \Exception($message, $e->getCode()); } } else { error_log(print_r($stmt, 1)); error_log($this->debugSql($origSql, $params, $paramTypes)); } return $stmt; } // Bind public function bind($param, $value, $type = null) { $this->stmt->bindValue($param, $value, $type); } }