m1k1oblog/app/db.class.php

290 lines
6.3 KiB
PHP
Raw Normal View History

2016-12-27 20:25:32 +00:00
<?php
defined('PROJECT_PATH') OR exit('No direct script access allowed');
2016-12-27 20:25:32 +00:00
2016-12-31 13:16:49 +00:00
// v3.43 (+ query counter)
2016-12-27 20:25:32 +00:00
class DB
{
private static $_instance = null;
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
private $_PDO;
private $_query;
2019-12-20 17:38:48 +00:00
2016-12-31 13:16:49 +00:00
private $_query_counter;
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Handle instances
public final static function get_instance(){
2019-12-20 17:30:35 +00:00
if(self::$_instance === null){
2016-12-27 20:25:32 +00:00
self::$_instance = new static();
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
return self::$_instance;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Initialise PDO object
private final function __construct(){
$host = Config::get_safe('mysql_host', false);
2019-12-23 20:20:41 +00:00
$port = Config::get_safe('mysql_port', false);
2016-12-27 20:25:32 +00:00
$socket = Config::get_safe('mysql_socket', false);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
if($socket === false && $host === false){
2019-12-23 18:09:04 +00:00
throw new DBException("Mysql host or socket must be defined.");
2016-12-27 20:25:32 +00:00
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Try to connect
try {
$this->_PDO = new \PDO(
// Server
2019-12-23 20:20:41 +00:00
'mysql:'.
($socket !== false
? 'unix_socket='.$socket
: 'host='.$host.($port !== false ? ';port='.$port : '')
).
2016-12-27 20:25:32 +00:00
// DB
2019-12-23 20:20:41 +00:00
';dbname='.Config::get('db_name').
2016-12-27 20:25:32 +00:00
// Charset
2019-12-23 20:20:41 +00:00
';charset=utf8',
2016-12-27 20:25:32 +00:00
// Username
Config::get('mysql_user'),
// Password
2016-12-31 13:16:49 +00:00
Config::get_safe('mysql_pass', '')
2016-12-27 20:25:32 +00:00
);
2020-05-26 22:14:17 +00:00
$this->_PDO->exec(
// Set charset
'SET NAMES utf8;'.
// Set timezone
'SET time_zone="'.date('P').'";'
);
2016-12-31 13:16:49 +00:00
} catch (PDOException $e) {
2016-12-27 20:25:32 +00:00
throw new DBException($e->getMessage());
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// When is this not set, chat does dot work, odd behavior
$this->_PDO->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Throwing exceptions
$this->_PDO->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
//$this->_PDO->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Just flattern array to be binded : [key1, key2, [key3, [key4]]] => [key1, key2, key3, key4]
private final function bind_value($key, $value){
if(is_array($value)){
foreach($value as $one_value){
$key = $this->bind_value($key, $one_value);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
return $key;
}
2019-12-20 17:38:48 +00:00
2020-01-08 22:28:40 +00:00
// BUG: Force strings to be UTF-8
// remove all 4-bytes characters.
if(is_string($value)){
$value = preg_replace('/[\xF0-\xF7].../s', '', $value);
}
2016-12-27 20:25:32 +00:00
$this->_query->bindValue($key, $value);
return ++$key;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Process Query
// query ($sql)
// query ($sql, $bind_param_01, $bind_param_02, ...)
// query ($sql, [$bind_param_01, $bind_param_02, ...])
public final function query(){
// Second parm is binded values
$params = func_get_args();
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// First parameter is sql
$sql = $params[0];
unset($params[0]);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Debug mode
if(Config::get_safe('debug', false)){
echo "<!-- ".$sql." + ".json_encode($params)." -->\n";
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Try to prepare MySQL statement
try {
// Prepare PDO statement
$this->_query = $this->_PDO->prepare($sql);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Bind values
$this->bind_value(1, $params);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Execute
$this->_query->execute();
2016-12-31 13:16:49 +00:00
} catch (PDOException $e) {
2016-12-27 20:25:32 +00:00
throw new DBException($e->getMessage());
}
2019-12-20 17:38:48 +00:00
2016-12-31 13:16:49 +00:00
$this->_query_counter++;
2016-12-27 20:25:32 +00:00
return $this;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Insert into table
public final function insert($table_name, $fields = null){
// If empty line
if(empty($fields)){
return $this->query("INSERT INTO `{$table_name}` () VALUES ()");
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// If multiple
if(isset($fields[0])){
// Turn array into PDO prepered statement format
$keys = array_keys($fields[0]);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Build query
$query = "INSERT INTO `{$table_name}` (`".implode('`, `', $keys)."`) VALUES ";
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Insert values
$first = true;
$prepared_data = array();
foreach($fields as $field){
if($first){
$first = false;
} else {
$query .= ',';
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
end($field);
$last_key = key($field);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
$query .= '(';
foreach($field as $key => $value){
if($value === "NOW()"){
$query .= 'NOW()';
} else {
$query .= '?';
$prepared_data[] = $value;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
if($last_key != $key){
$query .= ',';
}
}
$query .= ')';
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Execute query
return $this->query($query, $prepared_data);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// If only single
return $this->insert($table_name, array($fields));
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Update table
// update ($table_name, $fields)
// update ($table_name, $fields, $sql)
// update ($table_name, $fields, $sql, $bind_param_01, $bind_param_02, ...)
// update ($table_name, $fields, $sql, [$bind_param_01, $bind_param_02, ...])
public final function update(){
// Fourt param is binded values
$params = func_get_args();
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// First is table_name
$table_name = $params[0];
unset($params[0]);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Second is fields
$fields = $params[1];
unset($params[1]);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Third is sql
$sql = $params[2];
unset($params[2]);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// If fields are not array, do nothing
if(!is_array($fields)){
return $this;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
end($fields);
$last_key = key($fields);
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Support for NOW()
$prepared_data = array();
$set_data = null;
foreach($fields as $key => $value){
if($value === "NOW()"){
$set_data .="`{$key}` = NOW()";
} else {
$set_data .= "`{$key}` = ?";
$prepared_data[] = $value;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
if($last_key != $key){
$set_data .= ',';
}
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// If params are not array, make it
if(!is_array($params)){
$params = array($params);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Merge fields array and additional SQL data
foreach($params as $param){
$prepared_data[] = $param;
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Build query
$query = "UPDATE `{$table_name}` SET {$set_data} ".$sql;
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Execute query
return $this->query($query, $prepared_data);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Alias for all
public final function results(){
trigger_error("Using deprecated method <strong>DB::results();</strong>. Use <strong>DB::all();</strong> instead.");
return $this->all();
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Get all rows
public final function all($type = \PDO::FETCH_ASSOC){
return $this->_query->fetchAll($type);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Get all values to one dimensional array
public final function columns($column = 0){
return $this->_query->fetchAll(\PDO::FETCH_COLUMN, $column);
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Get first row from result
public final function first($key = null){
$results = $this->all();
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
if($key !== null){
return @$results[0][$key];
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
return @$results[0];
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Get last inserted ID
public final function last_id(){
return $this->_PDO->lastInsertId();
}
2019-12-20 17:38:48 +00:00
2016-12-27 20:25:32 +00:00
// Exec
public final function exec($sql){
// Try to execute MySQL
try {
$this->_PDO->exec($sql);
2016-12-31 13:16:49 +00:00
} catch (PDOException $e) {
2016-12-27 20:25:32 +00:00
throw new DBException($e->getMessage());
}
2019-12-20 17:38:48 +00:00
2016-12-31 13:16:49 +00:00
return $this;
}
2019-12-20 17:38:48 +00:00
2016-12-31 13:16:49 +00:00
public final function total_queries(){
return $this->_query_counter;
2016-12-27 20:25:32 +00:00
}
}
// Handle DB errors
class DBException extends Exception{}