VvebOIDC/system/db/mysqli.php

407 lines
9.0 KiB
PHP

<?php
/**
* Vvveb
*
* Copyright (C) 2022 Ziadin Givan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Vvveb\System\Db;
use Vvveb\System\Event;
/*
Define and use mysqli_result if native is missing
*/
class mysqli_result {
private $stmt;
private $meta;
public function __construct($stmt) {
$this->stmt = $stmt;
}
public function fetch_all() {
return $this->fetch_assoc();
}
public function fetch_array($resulttype) {
return $this->fetch_assoc();
}
public function fetch_assoc() {
//$meta = $this->stmt->store_result();
$meta = $this->stmt->result_metadata();
$row = [];
while ($field = $meta->fetch_field()) {
$params[] = &$row[$field->name];
}
call_user_func_array([$this->stmt, 'bind_result'], $params);
while ($this->stmt->fetch()) {
$c = [];
foreach ($row as $key => $val) {
$c[$key] = $val;
}
$result[] = $c;
}
//$this->stmt->free_result();
//$this->stmt->close();
return $result;
}
public function fetch_field() {
}
public function fetch_fields() {
}
public function fetchRow() {
return $this->fetch_assoc();
}
}
class Mysqli extends DBDriver {
private static $link = null;
//public $error;
private $stmt;
public $affected_rows = 0;
public $insert_id = null;
public $quote = '`';
public $prefix = ''; //'vv_';
public static function version() {
if (self :: $link) {
return mysqli_get_server_version(self :: $link);
}
}
public static function info() {
if (self :: $link) {
return mysqli_get_server_info(self :: $link);
}
}
public function error() {
if (self :: $link) {
return self :: $link->error;
}
}
public function errorCode() {
if (self :: $link) {
return self :: $link->errno;
}
}
public function get_result($stmt) {
$result = new mysqli_result($stmt);
return $result;
}
public function __construct($host = DB_HOST, $dbname = DB_NAME, $user = DB_USER, $pass = DB_PASS, $port = DB_PORT, $prefix = DB_PREFIX) {
//return $this->connect($host, $dbname, $user, $pass, $port, $prefix);
}
public function connect($host = DB_HOST, $dbname = DB_NAME, $user = DB_USER, $pass = DB_PASS, $port = DB_PORT, $prefix = DB_PREFIX) {
//mysqli_report(MYSQLI_REPORT_OFF);
//connect to database
if (self :: $link) {
return self :: $link;
}
$this->prefix = $prefix;
\mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
self :: $link = new \Mysqli(/*'p:' . */$host, $user, $pass, $dbname, $port);
//self :: $link = $this;
} catch (\mysqli_sql_exception $e) {
$errorMessage = str_replace($pass,'*****', $e->getMessage());
throw new \Exception($errorMessage, $e->getCode());
}
// check if a connection established
if (\mysqli_connect_errno()) {
$error = mysqli_connect_error();
$errorMessage = str_replace($pass,'*****', $error);
throw new \Exception($errorMessage, mysqli_connect_errno());
}
if ((! self :: $link instanceof \MySQLi)) {
throw new \Exception('Mysqli not an object', mysqli_connect_errno());
}
return self :: $link;
}
/*
* Get all columns for a table used for sanitizing input
*/
function getColumnsMeta($tableName, $comment = false) {
$sql =
'SELECT COLUMN_NAME as name, COLUMN_DEFAULT as d, IS_NULLABLE as n, DATA_TYPE as t, EXTRA as e, CHARACTER_MAXIMUM_LENGTH as l'
. ($comment ? ', COLUMN_COMMENT as c' : '') .
' FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`= "' . DB_NAME . '"
AND `TABLE_NAME`="' . $tableName . '"';
if ($result = $this->query($sql)) {
//$columns = $result->fetch_all(MYSQLI_ASSOC);
$columns = [];
while ($row = $result->fetch_assoc()) {
$columns[$row['name']] = $row;
}
/* free result set */
$result->close();
return $columns;
} else {
}
return false;
}
function getTableNames($db = DB_NAME) {
$sql ="SELECT table_name as name
FROM information_schema.tables
WHERE table_schema = '$db' ORDER BY table_name";
if ($result = $this->query($sql)) {
//$names = $result->fetch_all(MYSQLI_ASSOC);
$names = [];
while ($row = $result->fetch_assoc()) {
$names[] = $row['name'];
}
/* free result set */
$result->close();
return $names;
} else {
}
return false;
}
public function select_db($db) {
return self :: $link->select_db($db);
}
public function query($sql) {
if (! self :: $link) {
$this->connect();
}
if (LOG_SQL_QUERIES) {
error_log($sql);
}
try {
$result = self :: $link->query($sql);
} catch (\mysqli_sql_exception $e) {
$message = $e->getMessage() . "\n" . $sql . "\n - " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true);
throw new \Exception($message, $e->getCode());
}
if ($result) {
$this->affected_rows = self :: $link->affected_rows;
$this->insert_id = self :: $link->insert_id;
}
return $result;
}
public function multi_query($sql) {
if (! self :: $link) {
$this->connect();
}
$result = self :: $link->multi_query($sql);
if ($result) {
$this->affected_rows = self :: $link->affected_rows;
$this->insert_id = self :: $link->insert_id;
}
return $result;
}
public function escape($string) {
if (is_string($string)) {
return self :: $link->real_escape_string($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 fetchArray($stmt) {
$data = [];
$statement = (get_class($stmt) === 'mysqli_stmt');
if ($statement) {
$this->store_result();
$result = $stmt->get_result();
} else {
$result = $stmt;
}
if ($result) {
$data = $result->fetch_array(MYSQLI_ASSOC);
if ($statement && $stmt->more_results()) {
$stmt->next_result();
}
}
return $data;
}
public function fetchAll($stmt) {
$data = [];
$statement = (get_class($stmt) === 'mysqli_stmt');
if ($statement) {
$this->store_result();
$result = $stmt->get_result();
} else {
$result = $stmt;
}
if ($result) {
$data = $result->fetch_all(MYSQLI_ASSOC);
}
return $data;
}
public function store_result() {
return self :: $link->store_result();
}
public function more_results() {
return self :: $link->more_results();
}
public function next_result() {
return self :: $link->next_result();
}
public function close() {
if ((self :: $link instanceof \MySQLi)/* && self :: $link->ping()*/) {
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 (\mysqli_sql_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($types)) {
array_unshift($parameters, $types);
//hack for php 7.x bind_param "expected to be a reference, value given" stupid warning
$referenceArray = [];
foreach ($parameters as $key => $value) {
$referenceArray[$key] = &$parameters[$key];
}
@call_user_func_array([$stmt, 'bind_param'], $referenceArray);
}
if (LOG_SQL_QUERIES) {
error_log($this->debugSql($origSql, $params, $paramTypes));
}
if ($stmt) {
try {
if ($stmt->execute()) {
$this->affected_rows = self :: $link->affected_rows;
$this->insert_id = self :: $link->insert_id;
return $stmt;
} else {
error_log(print_r($stmt, 1));
error_log($this->debugSql($sql, $params, $paramTypes));
}
} catch (\mysqli_sql_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);
}
}