2013-11-09 17:24:03 +01:00
|
|
|
<?php
|
|
|
|
|
2014-04-27 21:31:55 +02:00
|
|
|
namespace ManiaControl\Database;
|
2014-03-20 16:19:09 +01:00
|
|
|
|
2014-03-12 13:27:14 +01:00
|
|
|
use ManiaControl\Callbacks\TimerListener;
|
2014-08-05 01:03:48 +02:00
|
|
|
use ManiaControl\Logger;
|
2014-04-27 21:31:55 +02:00
|
|
|
use ManiaControl\ManiaControl;
|
2013-11-09 17:24:03 +01:00
|
|
|
|
|
|
|
/**
|
2014-04-12 12:14:37 +02:00
|
|
|
* Database Connection Class
|
2013-11-09 17:24:03 +01:00
|
|
|
*
|
2014-05-02 17:40:47 +02:00
|
|
|
* @author ManiaControl Team <mail@maniacontrol.com>
|
2020-01-22 10:39:35 +01:00
|
|
|
* @copyright 2014-2020 ManiaControl Team
|
2014-05-02 17:40:47 +02:00
|
|
|
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
|
2013-11-09 17:24:03 +01:00
|
|
|
*/
|
2014-03-20 16:19:09 +01:00
|
|
|
class Database implements TimerListener {
|
2014-04-12 12:14:37 +02:00
|
|
|
/*
|
2014-07-25 16:28:47 +02:00
|
|
|
* Public properties
|
2013-11-09 17:24:03 +01:00
|
|
|
*/
|
2014-10-24 20:08:21 +02:00
|
|
|
/** @var \mysqli $mysqli
|
|
|
|
* @deprecated
|
|
|
|
* @see Database::getMysqli()
|
|
|
|
*/
|
2013-11-09 17:24:03 +01:00
|
|
|
public $mysqli = null;
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2014-04-12 12:14:37 +02:00
|
|
|
/*
|
2014-07-25 16:28:47 +02:00
|
|
|
* Private properties
|
2013-11-09 17:24:03 +01:00
|
|
|
*/
|
2014-08-02 22:31:46 +02:00
|
|
|
/** @var ManiaControl $maniaControl */
|
2013-11-10 02:55:08 +01:00
|
|
|
private $maniaControl = null;
|
2014-06-20 19:06:55 +02:00
|
|
|
/** @var Config $config */
|
2014-05-27 10:46:32 +02:00
|
|
|
private $config = null;
|
2014-08-02 22:31:46 +02:00
|
|
|
/** @var MigrationHelper $migrationHelper */
|
|
|
|
private $migrationHelper = null;
|
2013-11-09 17:24:03 +01:00
|
|
|
|
|
|
|
/**
|
2014-05-09 17:30:31 +02:00
|
|
|
* Construct a new Database Connection
|
|
|
|
*
|
|
|
|
* @param ManiaControl $maniaControl
|
2013-11-09 17:24:03 +01:00
|
|
|
*/
|
2013-11-10 02:55:08 +01:00
|
|
|
public function __construct(ManiaControl $maniaControl) {
|
|
|
|
$this->maniaControl = $maniaControl;
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2014-03-20 16:19:09 +01:00
|
|
|
// Enable mysqli Reconnect
|
2014-03-12 13:27:14 +01:00
|
|
|
ini_set('mysqli.reconnect', 'on');
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2013-11-09 17:24:03 +01:00
|
|
|
// Open database connection
|
2014-05-27 10:46:32 +02:00
|
|
|
$this->loadConfig();
|
|
|
|
$this->mysqli = @new \mysqli($this->config->host, $this->config->user, $this->config->pass, null, $this->config->port);
|
2014-08-03 01:34:18 +02:00
|
|
|
if ($connectError = $this->getMysqli()->connect_error) {
|
|
|
|
$message = "Couldn't connect to Database: '{$connectError}'";
|
2014-05-09 14:08:39 +02:00
|
|
|
$this->maniaControl->quit($message, true);
|
2017-04-22 08:27:40 +02:00
|
|
|
return;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2014-08-13 11:05:52 +02:00
|
|
|
$this->getMysqli()->set_charset("utf8");
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2013-11-09 17:24:03 +01:00
|
|
|
$this->initDatabase();
|
2013-11-10 02:55:08 +01:00
|
|
|
$this->optimizeTables();
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2014-03-20 16:19:09 +01:00
|
|
|
// Register Method which checks the Database Connection every 5 seconds
|
2014-08-13 11:05:52 +02:00
|
|
|
$this->maniaControl->getTimerManager()->registerTimerListening($this, 'checkConnection', 5000);
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2014-08-03 01:34:18 +02:00
|
|
|
// Children
|
2014-04-27 21:31:55 +02:00
|
|
|
$this->migrationHelper = new MigrationHelper($maniaControl);
|
2014-03-12 13:27:14 +01:00
|
|
|
}
|
|
|
|
|
2013-11-09 17:24:03 +01:00
|
|
|
/**
|
2014-05-27 10:46:32 +02:00
|
|
|
* Load the Database Config
|
|
|
|
*/
|
|
|
|
private function loadConfig() {
|
2014-08-13 11:05:52 +02:00
|
|
|
$databaseElements = $this->maniaControl->getConfig()->xpath('database');
|
2014-05-27 10:46:32 +02:00
|
|
|
if (!$databaseElements) {
|
2014-08-05 02:08:11 +02:00
|
|
|
$this->maniaControl->quit('No Database configured!', true);
|
2014-05-27 10:46:32 +02:00
|
|
|
}
|
|
|
|
$databaseElement = $databaseElements[0];
|
|
|
|
|
|
|
|
// Host
|
|
|
|
$hostElements = $databaseElement->xpath('host');
|
|
|
|
if (!$hostElements) {
|
2014-08-05 02:08:11 +02:00
|
|
|
$this->maniaControl->quit("Invalid database configuration (Host).", true);
|
2014-05-27 10:46:32 +02:00
|
|
|
}
|
2014-10-24 20:08:21 +02:00
|
|
|
$host = (string) $hostElements[0];
|
2014-05-27 10:46:32 +02:00
|
|
|
|
|
|
|
// Port
|
|
|
|
$portElements = $databaseElement->xpath('port');
|
|
|
|
if (!$portElements) {
|
2014-08-05 02:08:11 +02:00
|
|
|
$this->maniaControl->quit("Invalid database configuration (Port).", true);
|
2014-05-27 10:46:32 +02:00
|
|
|
}
|
2014-10-24 20:08:21 +02:00
|
|
|
$port = (string) $portElements[0];
|
2014-05-27 10:46:32 +02:00
|
|
|
|
|
|
|
// User
|
|
|
|
$userElements = $databaseElement->xpath('user');
|
|
|
|
if (!$userElements) {
|
2014-08-05 02:08:11 +02:00
|
|
|
$this->maniaControl->quit("Invalid database configuration (User).", true);
|
2014-05-27 10:46:32 +02:00
|
|
|
}
|
2014-10-24 20:08:21 +02:00
|
|
|
$user = (string) $userElements[0];
|
2014-05-27 10:46:32 +02:00
|
|
|
|
|
|
|
// Pass
|
|
|
|
$passElements = $databaseElement->xpath('pass');
|
|
|
|
if (!$passElements) {
|
2014-08-05 02:08:11 +02:00
|
|
|
$this->maniaControl->quit("Invalid database configuration (Pass).", true);
|
2014-05-27 10:46:32 +02:00
|
|
|
}
|
2014-10-24 20:08:21 +02:00
|
|
|
$pass = (string) $passElements[0];
|
2014-05-27 10:46:32 +02:00
|
|
|
|
|
|
|
// Name
|
|
|
|
$nameElements = $databaseElement->xpath('name');
|
|
|
|
if (!$nameElements) {
|
|
|
|
$nameElements = $databaseElement->xpath('db_name');
|
|
|
|
}
|
|
|
|
if (!$nameElements) {
|
2014-08-05 02:08:11 +02:00
|
|
|
$this->maniaControl->quit("Invalid database configuration (Name).", true);
|
2014-05-27 10:46:32 +02:00
|
|
|
}
|
2014-10-24 20:08:21 +02:00
|
|
|
$name = (string) $nameElements[0];
|
2014-05-27 10:46:32 +02:00
|
|
|
|
|
|
|
// Create config object
|
2014-06-20 19:06:55 +02:00
|
|
|
$config = new Config($host, $port, $user, $pass, $name);
|
2014-05-27 10:46:32 +02:00
|
|
|
if (!$config->validate()) {
|
|
|
|
$this->maniaControl->quit("Your config file doesn't seem to be maintained properly. Please check the database configuration again!", true);
|
|
|
|
}
|
|
|
|
$this->config = $config;
|
|
|
|
}
|
|
|
|
|
2014-10-24 20:08:21 +02:00
|
|
|
/**
|
|
|
|
* Return the mysqli instance
|
|
|
|
*
|
|
|
|
* @return \mysqli
|
|
|
|
*/
|
|
|
|
public function getMysqli() {
|
|
|
|
return $this->mysqli;
|
|
|
|
}
|
|
|
|
|
2014-05-27 10:46:32 +02:00
|
|
|
/**
|
|
|
|
* Connect to the defined Database
|
2013-11-10 02:55:08 +01:00
|
|
|
*
|
|
|
|
* @return bool
|
2013-11-09 17:24:03 +01:00
|
|
|
*/
|
|
|
|
private function initDatabase() {
|
|
|
|
// Try to connect
|
2014-08-13 11:05:52 +02:00
|
|
|
$result = $this->getMysqli()->select_db($this->config->name);
|
2014-05-02 17:40:47 +02:00
|
|
|
if ($result) {
|
|
|
|
return true;
|
|
|
|
}
|
2014-08-05 01:49:13 +02:00
|
|
|
Logger::logInfo("Database '{$this->config->name}' doesn't exist! Trying to create it...");
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2013-11-10 02:55:08 +01:00
|
|
|
// Create database
|
2014-08-13 11:05:52 +02:00
|
|
|
$databaseQuery = "CREATE DATABASE " . $this->getMysqli()->escape_string($this->config->name) . ";";
|
|
|
|
$this->getMysqli()->query($databaseQuery);
|
2014-08-03 01:34:18 +02:00
|
|
|
if ($this->getMysqli()->error) {
|
|
|
|
$this->maniaControl->quit($this->getMysqli()->error, true);
|
2013-11-10 02:55:08 +01:00
|
|
|
return false;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2013-11-10 02:55:08 +01:00
|
|
|
// Connect to new database
|
2014-08-13 11:05:52 +02:00
|
|
|
$this->getMysqli()->select_db($this->config->name);
|
2014-08-03 01:34:18 +02:00
|
|
|
if ($error = $this->getMysqli()->error) {
|
|
|
|
$message = "Couldn't select database '{$this->config->name}'. {$error}";
|
2014-05-09 14:08:39 +02:00
|
|
|
$this->maniaControl->quit($message, true);
|
2013-11-10 02:55:08 +01:00
|
|
|
return false;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2014-05-27 10:46:32 +02:00
|
|
|
|
2013-11-10 02:55:08 +01:00
|
|
|
return true;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-05-27 10:46:32 +02:00
|
|
|
* Optimize all existing Tables
|
2013-11-09 17:24:03 +01:00
|
|
|
*
|
2013-11-10 02:55:08 +01:00
|
|
|
* @return bool
|
2013-11-09 17:24:03 +01:00
|
|
|
*/
|
2013-11-10 02:55:08 +01:00
|
|
|
private function optimizeTables() {
|
2014-08-03 01:34:18 +02:00
|
|
|
$showQuery = 'SHOW TABLES;';
|
2014-08-13 11:05:52 +02:00
|
|
|
$result = $this->getMysqli()->query($showQuery);
|
2014-08-03 01:34:18 +02:00
|
|
|
if ($error = $this->getMysqli()->error) {
|
2014-08-03 13:29:54 +02:00
|
|
|
Logger::logError($error);
|
2013-11-10 02:55:08 +01:00
|
|
|
return false;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2013-11-10 02:55:08 +01:00
|
|
|
$count = $result->num_rows;
|
|
|
|
if ($count <= 0) {
|
2014-05-18 23:34:47 +02:00
|
|
|
$result->free();
|
2013-11-10 02:55:08 +01:00
|
|
|
return true;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2014-08-03 01:34:18 +02:00
|
|
|
$optimizeQuery = 'OPTIMIZE TABLE ';
|
2014-05-02 17:40:47 +02:00
|
|
|
$index = 0;
|
2013-11-10 02:55:08 +01:00
|
|
|
while ($row = $result->fetch_row()) {
|
|
|
|
$tableName = $row[0];
|
|
|
|
$optimizeQuery .= "`{$tableName}`";
|
|
|
|
if ($index < $count - 1) {
|
2014-08-03 01:34:18 +02:00
|
|
|
$optimizeQuery .= ',';
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2013-11-10 02:55:08 +01:00
|
|
|
$index++;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2014-05-18 23:34:47 +02:00
|
|
|
$result->free();
|
2014-08-03 01:34:18 +02:00
|
|
|
$optimizeQuery .= ';';
|
2014-08-13 11:05:52 +02:00
|
|
|
$this->getMysqli()->query($optimizeQuery);
|
2014-08-03 01:34:18 +02:00
|
|
|
if ($error = $this->getMysqli()->error) {
|
2014-08-03 13:29:54 +02:00
|
|
|
Logger::logError($error);
|
2013-11-10 02:55:08 +01:00
|
|
|
return false;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2013-11-10 02:55:08 +01:00
|
|
|
return true;
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|
2014-05-02 17:40:47 +02:00
|
|
|
|
2014-07-25 16:28:47 +02:00
|
|
|
/**
|
|
|
|
* Return the database config
|
|
|
|
*
|
|
|
|
* @return Config
|
|
|
|
*/
|
|
|
|
public function getConfig() {
|
|
|
|
return $this->config;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the migration helper
|
|
|
|
*
|
|
|
|
* @return MigrationHelper
|
|
|
|
*/
|
|
|
|
public function getMigrationHelper() {
|
|
|
|
return $this->migrationHelper;
|
|
|
|
}
|
|
|
|
|
2014-05-02 17:40:47 +02:00
|
|
|
/**
|
2014-05-27 10:46:32 +02:00
|
|
|
* Check whether the Database Connection is still open
|
2014-05-02 17:40:47 +02:00
|
|
|
*/
|
2014-05-27 10:46:32 +02:00
|
|
|
public function checkConnection() {
|
2014-10-24 20:08:58 +02:00
|
|
|
if (!$this->getMysqli() || !@$this->getMysqli()->ping()) {
|
2014-05-27 10:46:32 +02:00
|
|
|
$this->maniaControl->quit('The MySQL Server has gone away!', true);
|
2014-05-02 17:40:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-05-27 10:46:32 +02:00
|
|
|
* Destruct Database Connection
|
2014-05-02 17:40:47 +02:00
|
|
|
*/
|
|
|
|
public function __destruct() {
|
2014-08-03 01:34:18 +02:00
|
|
|
if ($this->getMysqli() && !$this->getMysqli()->connect_error) {
|
2014-08-13 11:05:52 +02:00
|
|
|
$this->getMysqli()->close();
|
2014-05-02 17:40:47 +02:00
|
|
|
}
|
|
|
|
}
|
2013-11-09 17:24:03 +01:00
|
|
|
}
|