275 lines
7.4 KiB
PHP
Executable File
275 lines
7.4 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* 🗄️ DATABASE CONNECTION MANAGER
|
|
* Version: 1.0 - Février 2026
|
|
*/
|
|
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
class DatabaseConnection {
|
|
private static $instance = null;
|
|
private $pdo;
|
|
private $lastQuery;
|
|
private $queryCount = 0;
|
|
|
|
/**
|
|
* Private constructor - singleton pattern
|
|
*/
|
|
private function __construct() {
|
|
try {
|
|
$dsn = "pgsql:host=" . DB_HOST . ";port=" . DB_PORT . ";dbname=" . DB_NAME . ";";
|
|
$this->pdo = new PDO($dsn, DB_USER, DB_PASS, [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
PDO::ATTR_PERSISTENT => false
|
|
]);
|
|
|
|
logMessage('INFO', 'Database', 'Connection established successfully');
|
|
|
|
} catch (PDOException $e) {
|
|
logMessage('CRITICAL', 'Database', 'Connection failed: ' . $e->getMessage());
|
|
|
|
// Fallback: create SQLite database for emergency
|
|
$this->createEmergencyDatabase();
|
|
throw new Exception('Database connection failed. Emergency mode activated.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get singleton instance
|
|
*/
|
|
public static function getInstance() {
|
|
if (self::$instance === null) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Execute query with parameters
|
|
*/
|
|
public function query($sql, $params = []) {
|
|
$this->queryCount++;
|
|
$this->lastQuery = ['sql' => $sql, 'params' => $params];
|
|
|
|
try {
|
|
$stmt = $this->pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
|
|
// Log slow queries
|
|
$start = microtime(true);
|
|
$stmt->execute($params);
|
|
$duration = (microtime(true) - $start) * 1000;
|
|
|
|
if ($duration > 1000) { // > 1 second
|
|
logMessage('WARNING', 'Database', 'Slow query detected', [
|
|
'duration' => round($duration, 2) . 'ms',
|
|
'sql' => $sql,
|
|
'params' => $params
|
|
]);
|
|
}
|
|
|
|
return $stmt;
|
|
|
|
} catch (PDOException $e) {
|
|
logMessage('ERROR', 'Database', 'Query failed: ' . $e->getMessage(), [
|
|
'sql' => $sql,
|
|
'params' => $params
|
|
]);
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Insert data into table
|
|
*/
|
|
public function insert($table, $data) {
|
|
$columns = implode(', ', array_keys($data));
|
|
$placeholders = ':' . implode(', :', array_keys($data));
|
|
|
|
$sql = "INSERT INTO $table ($columns) VALUES ($placeholders) RETURNING id";
|
|
|
|
$stmt = $this->query($sql, $data);
|
|
$result = $stmt->fetch();
|
|
|
|
return $result['id'] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Update data in table
|
|
*/
|
|
public function update($table, $data, $where, $whereParams = []) {
|
|
$setParts = [];
|
|
foreach ($data as $key => $value) {
|
|
$setParts[] = "$key = :$key";
|
|
}
|
|
|
|
$setClause = implode(', ', $setParts);
|
|
$sql = "UPDATE $table SET $setClause WHERE $where";
|
|
|
|
$params = array_merge($data, $whereParams);
|
|
$this->query($sql, $params);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Delete from table
|
|
*/
|
|
public function delete($table, $where, $params = []) {
|
|
$sql = "DELETE FROM $table WHERE $where";
|
|
$this->query($sql, $params);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Select with pagination
|
|
*/
|
|
public function select($table, $columns = '*', $where = '1=1', $params = [], $orderBy = null, $limit = null, $offset = 0) {
|
|
$sql = "SELECT $columns FROM $table WHERE $where";
|
|
|
|
if ($orderBy) {
|
|
$sql .= " ORDER BY $orderBy";
|
|
}
|
|
|
|
if ($limit) {
|
|
$sql .= " LIMIT $limit OFFSET $offset";
|
|
}
|
|
|
|
$stmt = $this->query($sql, $params);
|
|
return $stmt->fetchAll();
|
|
}
|
|
|
|
/**
|
|
* Get single row
|
|
*/
|
|
public function getRow($table, $columns = '*', $where = '1=1', $params = []) {
|
|
$rows = $this->select($table, $columns, $where, $params, null, 1);
|
|
return $rows[0] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Get count
|
|
*/
|
|
public function count($table, $where = '1=1', $params = []) {
|
|
$sql = "SELECT COUNT(*) as count FROM $table WHERE $where";
|
|
$stmt = $this->query($sql, $params);
|
|
$result = $stmt->fetch();
|
|
|
|
return (int) ($result['count'] ?? 0);
|
|
}
|
|
|
|
/**
|
|
* Begin transaction
|
|
*/
|
|
public function beginTransaction() {
|
|
return $this->pdo->beginTransaction();
|
|
}
|
|
|
|
/**
|
|
* Commit transaction
|
|
*/
|
|
public function commit() {
|
|
return $this->pdo->commit();
|
|
}
|
|
|
|
/**
|
|
* Rollback transaction
|
|
*/
|
|
public function rollback() {
|
|
return $this->pdo->rollBack();
|
|
}
|
|
|
|
/**
|
|
* Get last inserted ID
|
|
*/
|
|
public function lastInsertId() {
|
|
return $this->pdo->lastInsertId();
|
|
}
|
|
|
|
/**
|
|
* Get query count
|
|
*/
|
|
public function getQueryCount() {
|
|
return $this->queryCount;
|
|
}
|
|
|
|
/**
|
|
* Get last query
|
|
*/
|
|
public function getLastQuery() {
|
|
return $this->lastQuery;
|
|
}
|
|
|
|
/**
|
|
* Check if table exists
|
|
*/
|
|
public function tableExists($tableName) {
|
|
try {
|
|
$sql = "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = :table)";
|
|
$stmt = $this->query($sql, ['table' => $tableName]);
|
|
$result = $stmt->fetch();
|
|
|
|
return $result['exists'] === 't';
|
|
} catch (Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create emergency SQLite database
|
|
*/
|
|
private function createEmergencyDatabase() {
|
|
$sqlitePath = TEMP_DIR . 'weval-mind-emergency.db';
|
|
|
|
try {
|
|
$this->pdo = new PDO("sqlite:$sqlitePath");
|
|
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
logMessage('EMERGENCY', 'Database', 'Emergency SQLite database created at: ' . $sqlitePath);
|
|
|
|
} catch (PDOException $e) {
|
|
logMessage('CRITICAL', 'Database', 'Emergency database creation failed: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Health check
|
|
*/
|
|
public function healthCheck() {
|
|
try {
|
|
$stmt = $this->query("SELECT 1 as health_check");
|
|
$result = $stmt->fetch();
|
|
|
|
return [
|
|
'status' => 'healthy',
|
|
'query_count' => $this->queryCount,
|
|
'last_query' => $this->lastQuery['sql'] ?? null
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
return [
|
|
'status' => 'unhealthy',
|
|
'error' => $e->getMessage(),
|
|
'emergency_mode' => true
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper function to get database instance
|
|
function getDB() {
|
|
return DatabaseConnection::getInstance();
|
|
}
|
|
|
|
// Test connection on include
|
|
try {
|
|
$db = getDB();
|
|
logMessage('INFO', 'Database', 'Database module loaded successfully');
|
|
} catch (Exception $e) {
|
|
logMessage('ERROR', 'Database', 'Database module failed to load: ' . $e->getMessage());
|
|
}
|
|
?>
|