Finished messenger

This commit is contained in:
2026-01-12 10:41:05 +01:00
parent 674fabb715
commit a4d386f2c5
11 changed files with 2069 additions and 426 deletions

View File

@@ -0,0 +1,183 @@
<?php
/**
* Class DatabaseModel
*
* Model for database operations using PDO
*/
class DatabaseModel
{
/**
* Get all databases on the server
* @return array
*/
public static function getAllDatabases()
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SHOW DATABASES";
$query = $database->prepare($sql);
$query->execute();
$databases = $query->fetchAll(PDO::FETCH_COLUMN);
// Filter out system databases
$system_dbs = ['information_schema', 'performance_schema', 'mysql', 'sys'];
return array_diff($databases, $system_dbs);
}
/**
* Get all tables in a specific database
* @param string $database_name
* @return array
*/
public static function getTablesInDatabase($database_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SHOW TABLES FROM " . $database_name;
$query = $database->prepare($sql);
$query->execute();
return $query->fetchAll(PDO::FETCH_COLUMN);
}
/**
* Get detailed information about tables in a database
* @param string $database_name
* @return array
*/
public static function getTableDetails($database_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$tables = self::getTablesInDatabase($database_name);
$table_details = array();
foreach ($tables as $table) {
$sql = "SHOW TABLE STATUS FROM " . $database_name . " LIKE :table_name";
$query = $database->prepare($sql);
$query->execute(array(':table_name' => $table));
$details = $query->fetch(PDO::FETCH_ASSOC);
if ($details) {
$table_details[$table] = array(
'engine' => $details['Engine'],
'rows' => $details['Rows'],
'data_size' => self::formatBytes($details['Data_length']),
'index_size' => self::formatBytes($details['Index_length']),
'total_size' => self::formatBytes($details['Data_length'] + $details['Index_length']),
'collation' => $details['Collation'],
'comment' => $details['Comment']
);
}
}
return $table_details;
}
/**
* Get complete database structure (tables and columns)
* @param string $database_name
* @return array
*/
public static function getDatabaseStructure($database_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$structure = array();
$tables = self::getTablesInDatabase($database_name);
foreach ($tables as $table) {
$sql = "DESCRIBE " . $database_name . "." . $table;
$query = $database->prepare($sql);
$query->execute();
$columns = $query->fetchAll(PDO::FETCH_ASSOC);
$structure[$table] = $columns;
}
return $structure;
}
/**
* Create a new database
* @param string $database_name
* @return bool
*/
public static function createDatabase($database_name)
{
if (!$database_name || !preg_match('/^[a-zA-Z0-9_]+$/', $database_name)) {
return false;
}
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "CREATE DATABASE `" . $database_name . "` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
$query = $database->prepare($sql);
return $query->execute();
} catch (PDOException $e) {
return false;
}
}
/**
* Delete a database
* @param string $database_name
* @return bool
*/
public static function deleteDatabase($database_name)
{
if (!$database_name) {
return false;
}
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "DROP DATABASE `" . $database_name . "`";
$query = $database->prepare($sql);
return $query->execute();
} catch (PDOException $e) {
return false;
}
}
/**
* Get table columns with details
* @param string $database_name
* @param string $table_name
* @return array
*/
public static function getTableColumns($database_name, $table_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SHOW COLUMNS FROM " . $database_name . "." . $table_name;
$query = $database->prepare($sql);
$query->execute();
return $query->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Format bytes to human readable format
* @param int $bytes
* @return string
*/
private static function formatBytes($bytes)
{
if ($bytes >= 1073741824) {
return number_format($bytes / 1073741824, 2) . ' GB';
} elseif ($bytes >= 1048576) {
return number_format($bytes / 1048576, 2) . ' MB';
} elseif ($bytes >= 1024) {
return number_format($bytes / 1024, 2) . ' KB';
} elseif ($bytes > 1) {
return $bytes . ' bytes';
} elseif ($bytes == 1) {
return '1 byte';
} else {
return '0 bytes';
}
}
}

View File

@@ -0,0 +1,289 @@
<?php
/**
* Class SqlModel
*
* Model for executing raw SQL queries
*/
class SqlModel
{
/**
* Execute a SQL query and return the result
* @param string $database_name
* @param string $sql_query
* @param int $user_id
* @return array
*/
public static function executeQuery($database_name, $sql_query, $user_id = null)
{
$start_time = microtime(true);
// Save query to history if user_id is provided
if ($user_id) {
self::saveQueryToHistory($user_id, $database_name, $sql_query);
}
try {
$database = DatabaseFactory::getFactory()->getConnection();
// Determine query type
$query_type = self::getQueryType($sql_query);
// Execute the query
$query = $database->prepare($sql_query);
$query->execute();
$execution_time = number_format((microtime(true) - $start_time) * 1000, 2);
// Handle different query types
if ($query_type === 'SELECT' || $query_type === 'SHOW' || $query_type === 'DESCRIBE' || $query_type === 'EXPLAIN') {
// Return result set
$result = $query->fetchAll(PDO::FETCH_ASSOC);
$message = 'Query executed successfully. ' . count($result) . ' rows returned.';
return array(
'success' => true,
'message' => $message,
'result' => $result,
'query_type' => $query_type,
'execution_time' => $execution_time,
'affected_rows' => 0
);
} else {
// Return affected rows count
$affected_rows = $query->rowCount();
$message = 'Query executed successfully. ' . $affected_rows . ' row(s) affected.';
return array(
'success' => true,
'message' => $message,
'query_type' => $query_type,
'execution_time' => $execution_time,
'affected_rows' => $affected_rows,
'result' => array()
);
}
} catch (PDOException $e) {
return array(
'success' => false,
'message' => 'Query execution failed',
'error' => $e->getMessage(),
'query_type' => 'ERROR',
'execution_time' => 0,
'result' => array()
);
}
}
/**
* Save query to history
* @param int $user_id
* @param string $database_name
* @param string $sql_query
* @return bool
*/
private static function saveQueryToHistory($user_id, $database_name, $sql_query)
{
// Create history table if it doesn't exist
self::createHistoryTableIfNotExists();
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "INSERT INTO sql_query_history (user_id, database_name, query_text, query_timestamp)
VALUES (:user_id, :database_name, :query_text, NOW())";
$query = $database->prepare($sql);
$query->execute(array(
':user_id' => $user_id,
':database_name' => $database_name,
':query_text' => $sql_query
));
// Keep only last 50 queries per user
$sql = "DELETE FROM sql_query_history
WHERE user_id = :user_id
AND id NOT IN (
SELECT id FROM (
SELECT id FROM sql_query_history
WHERE user_id = :user_id
ORDER BY query_timestamp DESC
LIMIT 50
) AS temp
)";
$query = $database->prepare($sql);
$query->execute(array(':user_id' => $user_id));
return true;
} catch (PDOException $e) {
return false;
}
}
/**
* Create SQL query history table if it doesn't exist
*/
private static function createHistoryTableIfNotExists()
{
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "CREATE TABLE IF NOT EXISTS sql_query_history (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
database_name VARCHAR(64) NOT NULL,
query_text TEXT NOT NULL,
query_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_timestamp (user_id, query_timestamp)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
$database->exec($sql);
} catch (PDOException $e) {
// Table creation failed
}
}
/**
* Get query history for a user
* @param int $user_id
* @param int $limit
* @return array
*/
public static function getQueryHistory($user_id, $limit = 50)
{
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "SELECT database_name, query_text, query_timestamp
FROM sql_query_history
WHERE user_id = :user_id
ORDER BY query_timestamp DESC
LIMIT :limit";
$query = $database->prepare($sql);
$query->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$query->bindValue(':limit', $limit, PDO::PARAM_INT);
$query->execute();
return $query->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
return array();
}
}
/**
* Clear query history for a user
* @param int $user_id
* @return bool
*/
public static function clearQueryHistory($user_id)
{
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "DELETE FROM sql_query_history WHERE user_id = :user_id";
$query = $database->prepare($sql);
return $query->execute(array(':user_id' => $user_id));
} catch (PDOException $e) {
return false;
}
}
/**
* Get database schema for autocomplete
* @param string $database_name
* @return array
*/
public static function getDatabaseSchema($database_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$schema = array();
try {
// Get all tables
$sql = "SHOW TABLES FROM " . $database_name;
$query = $database->prepare($sql);
$query->execute();
$tables = $query->fetchAll(PDO::FETCH_COLUMN);
foreach ($tables as $table) {
// Get columns for each table
$sql = "SHOW COLUMNS FROM " . $database_name . "." . $table;
$query = $database->prepare($sql);
$query->execute();
$columns = $query->fetchAll(PDO::FETCH_ASSOC);
$schema[$table] = array_map(function($column) {
return $column['Field'];
}, $columns);
}
return $schema;
} catch (PDOException $e) {
return array();
}
}
/**
* Format SQL query (basic formatting)
* @param string $query
* @return string
*/
public static function formatQuery($query)
{
// Basic SQL formatting
$query = trim($query);
// Uppercase SQL keywords
$keywords = array(
'SELECT', 'FROM', 'WHERE', 'AND', 'OR', 'ORDER BY', 'GROUP BY',
'HAVING', 'LIMIT', 'OFFSET', 'INSERT', 'INTO', 'VALUES',
'UPDATE', 'SET', 'DELETE', 'CREATE', 'TABLE', 'ALTER', 'DROP',
'INDEX', 'PRIMARY KEY', 'FOREIGN KEY', 'REFERENCES', 'JOIN',
'INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'ON', 'AS', 'DISTINCT',
'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'EXISTS', 'IN', 'BETWEEN',
'LIKE', 'IS NULL', 'IS NOT NULL', 'UNION', 'ALL'
);
foreach ($keywords as $keyword) {
$query = preg_replace('/\b' . preg_quote($keyword) . '\b/i', $keyword, $query);
}
// Add line breaks for better readability
$query = preg_replace('/\b(FROM|WHERE|GROUP BY|ORDER BY|HAVING|LIMIT|UNION)\b/', "\n$1", $query);
$query = preg_replace('/,\s*(\w)/', ",\n $1", $query);
return $query;
}
/**
* Determine the type of SQL query
* @param string $sql_query
* @return string
*/
private static function getQueryType($sql_query)
{
$query = strtoupper(trim($sql_query));
if (strpos($query, 'SELECT') === 0) {
return 'SELECT';
} elseif (strpos($query, 'INSERT') === 0) {
return 'INSERT';
} elseif (strpos($query, 'UPDATE') === 0) {
return 'UPDATE';
} elseif (strpos($query, 'DELETE') === 0) {
return 'DELETE';
} elseif (strpos($query, 'CREATE') === 0) {
return 'CREATE';
} elseif (strpos($query, 'ALTER') === 0) {
return 'ALTER';
} elseif (strpos($query, 'DROP') === 0) {
return 'DROP';
} elseif (strpos($query, 'SHOW') === 0) {
return 'SHOW';
} elseif (strpos($query, 'DESCRIBE') === 0) {
return 'DESCRIBE';
} elseif (strpos($query, 'EXPLAIN') === 0) {
return 'EXPLAIN';
} else {
return 'OTHER';
}
}
}

View File

@@ -0,0 +1,284 @@
<?php
/**
* Class TableModel
*
* Model for table operations using PDO
*/
class TableModel
{
/**
* Get table rows with pagination
* @param string $database_name
* @param string $table_name
* @param int $page
* @param int $per_page
* @return array
*/
public static function getTableRows($database_name, $table_name, $page = 1, $per_page = 20)
{
$database = DatabaseFactory::getFactory()->getConnection();
$offset = ($page - 1) * $per_page;
$sql = "SELECT * FROM `" . $database_name . "`.`" . $table_name . "` LIMIT :offset, :per_page";
$query = $database->prepare($sql);
$query->bindParam(':offset', $offset, PDO::PARAM_INT);
$query->bindParam(':per_page', $per_page, PDO::PARAM_INT);
$query->execute();
return $query->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Get total number of rows in a table
* @param string $database_name
* @param string $table_name
* @return int
*/
public static function getTableRowCount($database_name, $table_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SELECT COUNT(*) as count FROM `" . $database_name . "`.`" . $table_name . "`";
$query = $database->prepare($sql);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
return (int)$result['count'];
}
/**
* Get table column information
* @param string $database_name
* @param string $table_name
* @return array
*/
public static function getTableColumns($database_name, $table_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SHOW COLUMNS FROM `" . $database_name . "`.`" . $table_name . "`";
$query = $database->prepare($sql);
$query->execute();
return $query->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Get table indexes
* @param string $database_name
* @param string $table_name
* @return array
*/
public static function getTableIndexes($database_name, $table_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SHOW INDEX FROM `" . $database_name . "`.`" . $table_name . "`";
$query = $database->prepare($sql);
$query->execute();
return $query->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Get table information
* @param string $database_name
* @param string $table_name
* @return array
*/
public static function getTableInfo($database_name, $table_name)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SHOW TABLE STATUS FROM `" . $database_name . "` LIKE :table_name";
$query = $database->prepare($sql);
$query->execute(array(':table_name' => $table_name));
$result = $query->fetch(PDO::FETCH_ASSOC);
if ($result) {
return array(
'engine' => $result['Engine'],
'rows' => $result['Rows'],
'data_size' => self::formatBytes($result['Data_length']),
'index_size' => self::formatBytes($result['Index_length']),
'total_size' => self::formatBytes($result['Data_length'] + $result['Index_length']),
'collation' => $result['Collation'],
'comment' => $result['Comment'],
'auto_increment' => $result['Auto_increment'],
'create_time' => $result['Create_time'],
'update_time' => $result['Update_time']
);
}
return array();
}
/**
* Create a new table
* @param string $database_name
* @param string $table_name
* @param array $columns
* @return bool
*/
public static function createTable($database_name, $table_name, $columns)
{
if (!$database_name || !$table_name || empty($columns)) {
return false;
}
$database = DatabaseFactory::getFactory()->getConnection();
// Build column definitions
$column_definitions = array();
foreach ($columns as $column) {
$definition = "`" . $column['name'] . "` " . $column['type'];
if (isset($column['null']) && $column['null'] === 'NO') {
$definition .= " NOT NULL";
}
if (isset($column['default']) && $column['default'] !== '') {
$definition .= " DEFAULT '" . $column['default'] . "'";
}
if (isset($column['extra']) && $column['extra'] === 'auto_increment') {
$definition .= " AUTO_INCREMENT";
}
$column_definitions[] = $definition;
}
// Handle primary key
foreach ($columns as $column) {
if (isset($column['key']) && $column['key'] === 'PRI') {
$column_definitions[] = "PRIMARY KEY (`" . $column['name'] . "`)";
break;
}
}
$columns_sql = implode(', ', $column_definitions);
try {
$sql = "CREATE TABLE `" . $database_name . "`.`" . $table_name . "` (" . $columns_sql . ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
$query = $database->prepare($sql);
return $query->execute();
} catch (PDOException $e) {
return false;
}
}
/**
* Delete a table
* @param string $database_name
* @param string $table_name
* @return bool
*/
public static function deleteTable($database_name, $table_name)
{
if (!$database_name || !$table_name) {
return false;
}
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "DROP TABLE `" . $database_name . "`.`" . $table_name . "`";
$query = $database->prepare($sql);
return $query->execute();
} catch (PDOException $e) {
return false;
}
}
/**
* Add a column to a table
* @param string $database_name
* @param string $table_name
* @param string $column_name
* @param string $column_type
* @param string $column_null
* @param string $column_key
* @param string $column_default
* @param string $column_extra
* @return bool
*/
public static function addColumn($database_name, $table_name, $column_name, $column_type, $column_null, $column_key, $column_default, $column_extra)
{
if (!$database_name || !$table_name || !$column_name || !$column_type) {
return false;
}
$database = DatabaseFactory::getFactory()->getConnection();
$definition = "`" . $column_name . "` " . $column_type;
if ($column_null === 'NO') {
$definition .= " NOT NULL";
}
if ($column_default !== '') {
$definition .= " DEFAULT '" . $column_default . "'";
}
if ($column_extra === 'auto_increment') {
$definition .= " AUTO_INCREMENT";
}
try {
$sql = "ALTER TABLE `" . $database_name . "`.`" . $table_name . "` ADD " . $definition;
$query = $database->prepare($sql);
return $query->execute();
} catch (PDOException $e) {
return false;
}
}
/**
* Drop a column from a table
* @param string $database_name
* @param string $table_name
* @param string $column_name
* @return bool
*/
public static function dropColumn($database_name, $table_name, $column_name)
{
if (!$database_name || !$table_name || !$column_name) {
return false;
}
$database = DatabaseFactory::getFactory()->getConnection();
try {
$sql = "ALTER TABLE `" . $database_name . "`.`" . $table_name . "` DROP COLUMN `" . $column_name . "`";
$query = $database->prepare($sql);
return $query->execute();
} catch (PDOException $e) {
return false;
}
}
/**
* Format bytes to human readable format
* @param int $bytes
* @return string
*/
private static function formatBytes($bytes)
{
if ($bytes >= 1073741824) {
return number_format($bytes / 1073741824, 2) . ' GB';
} elseif ($bytes >= 1048576) {
return number_format($bytes / 1048576, 2) . ' MB';
} elseif ($bytes >= 1024) {
return number_format($bytes / 1024, 2) . ' KB';
} elseif ($bytes > 1) {
return $bytes . ' bytes';
} elseif ($bytes == 1) {
return '1 byte';
} else {
return '0 bytes';
}
}
}