Skip to content

Commit

Permalink
PUSH
Browse files Browse the repository at this point in the history
-> Added backups :)
  • Loading branch information
NaysKutzu committed Aug 20, 2024
1 parent f53fed9 commit cf30a50
Show file tree
Hide file tree
Showing 23 changed files with 530 additions and 23 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ caches/last_settings_migrate_run
/storage/caches/*.log
/storage/caches/*/
/storage/logs/*.log
/frontend/node_modules
/frontend/node_modules
/storage/backups/database/*.sql
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
"ealready",
"ERRMODE",
"fklmnor",
"Ifsnop",
"Inno",
"jsyaml",
"Kutzu",
"Mysqldump",
"mythicalcore",
"mythicalframework",
"Nahh",
Expand Down
18 changes: 18 additions & 0 deletions .vscode/vscode.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,22 @@
],
"description": "Get a specific value from the config file!"
},
"AddRequirements": {
"prefix": "S_AddRequirements",
"scope": "php",
"body": [
"use MythicalSystemsFramework\\Kernel\\LoggerTypes;",
"use MythicalSystemsFramework\\Kernel\\LoggerLevels;",
"use MythicalSystemsFramework\\Kernel\\Logger;",
"use MythicalSystemsFramework\\Kernel\\Config;",
"use MythicalSystemsFramework\\Encryption\\XChaCha20;",
"use MythicalSystemsFramework\\User\\UserHelper;",
"use MythicalSystemsFramework\\Kernel\\Debugger;",
"use MythicalSystemsFramework\\Mail\\MailService;",
"use MythicalSystemsFramework\\Handlers\\ActivityHandler;",
"use MythicalSystemsFramework\\Managers\\Settings as settings;",
"use MythicalSystemsFramework\\Managers\\ConfigManager as cfg;",
"use MythicalSystemsFramework\\Database\\MySQL;"
]
}
}
96 changes: 96 additions & 0 deletions app/Backup/Backup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace MythicalSystemsFramework\Backup;

use Ifsnop\Mysqldump as IMysqldump;
use MythicalSystemsFramework\Kernel\LoggerTypes;
use MythicalSystemsFramework\Kernel\LoggerLevels;
use MythicalSystemsFramework\Kernel\Logger;
use MythicalSystemsFramework\Encryption\XChaCha20;
use MythicalSystemsFramework\User\UserHelper;
use MythicalSystemsFramework\Kernel\Debugger;
use MythicalSystemsFramework\Mail\MailService;
use MythicalSystemsFramework\Handlers\ActivityHandler;
use MythicalSystemsFramework\Database\MySQL;
use MythicalSystemsFramework\Managers\Settings as settings;
use MythicalSystemsFramework\Managers\ConfigManager as cfg;



class Backup extends Database implements Status
{
/**
* Take a backup of the MySQL database.
*
* @return int
*/
public static function take(): int
{
try {
$date = MySQL::getDateLikeMySQL();
$date = str_replace(" ", "_", $date);
$date = str_replace(":", "_", $date);
$date = str_replace("-", "_", $date);
$path = __DIR__ . '/../../storage/backups/database/backup_sql_' . $date . '.sql';

$dump = new IMysqldump\Mysqldump('mysql:host=' . cfg::get('database', 'host') . ';dbname=' . cfg::get('database', 'name'), cfg::get('database', 'username'), cfg::get('database', 'password'));
$dump->start($path);
return self::registerBackup($path);
} catch (\Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::BACKUP, "(App/Backup/Backup.php) Failed to take MySQL backup: " . $e->getMessage());
return 0;
}
}
/**
* Restore the backup from the database.
* @param int $backup_id
* @return void
*/
public static function restore(int $backup_id): void
{
try {
if (!self::doesBackupExist($backup_id)) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::BACKUP, "(App/Backup/Backup.php) Failed to restore MySQL backup: Backup does not exist.");
return;
}
$path = self::getBackupPath($backup_id);

$mysql = new MySQL();
$db = $mysql->connectPDO();

$db->exec('SET FOREIGN_KEY_CHECKS = 0');
$tables = $db->query('SHOW TABLES')->fetchAll(\PDO::FETCH_COLUMN);
foreach ($tables as $table) {
$db->exec("DROP TABLE IF EXISTS $table");
}
$db->exec('SET FOREIGN_KEY_CHECKS = 1');

$db->exec('SET FOREIGN_KEY_CHECKS = 0');
$sql = file_get_contents($path);
$db->exec($sql);
$db->exec('SET FOREIGN_KEY_CHECKS = 1');
unlink($path);
} catch (\Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::BACKUP, "(App/Backup/Backup.php) Failed to restore MySQL backup: " . $e->getMessage());
}
}
/**
* Remove a backup from the database / storage.
*
* @param int $backup_id
* @return void
*/
public static function remove(int $backup_id) {
try {
if (!self::doesBackupExist($backup_id)) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::BACKUP, "(App/Backup/Backup.php) Failed to remove MySQL backup: Backup does not exist.");
return;
}
$path = self::getBackupPath($backup_id);
unlink($path);
self::markAsDeleted($backup_id);
} catch (\Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::BACKUP, "(App/Backup/Backup.php) Failed to remove MySQL backup: " . $e->getMessage());
}
}
}
180 changes: 180 additions & 0 deletions app/Backup/Database.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php

namespace MythicalSystemsFramework\Backup;

use MythicalSystemsFramework\Database\MySQL;
use MythicalSystemsFramework\Kernel\Logger;
use MythicalSystemsFramework\Kernel\LoggerLevels;
use MythicalSystemsFramework\Kernel\LoggerTypes;
use Exception;

class Database implements Status
{
/**
* Register that a backup is being taken!
*
* @param string $path
* @return bool
*/
public static function registerBackup(string $path): int
{
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
$stmt = $conn->prepare("INSERT INTO framework_backups (backup_path) VALUES (?)");
$stmt->bind_param('s',$path);
$stmt->execute();
Logger::log(LoggerLevels::INFO, LoggerTypes::BACKUP, "A new backup has been started.");
return $stmt->insert_id;
} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to register backup: " . $e->getMessage());
return 0;
}
}

/**
* Does a backup exist in the database?
*
* @param int $id The id of the backup
*
* @return bool Does the backup exist?
*/
public static function doesBackupExist(int $id): bool
{
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
$stmt = $conn->prepare("SELECT * FROM framework_backups WHERE id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
return true;
} else {
return false;
}
} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to check if backup exists: " . $e->getMessage());
return false;
}
}

/**
* Mark a backup as completed
*
* @param int $id The id of the backup
*
* @return void
*/
public static function setBackupStatus(int $id, Status|string $status): void
{
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
if (self::doesBackupExist($id)) {
if (MySQL::getLock('framework_backups', $id) == false) {
Logger::log(LoggerLevels::ERROR, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to mark backup as completed: Failed to get lock.");
return;
}
MySQL::requestLock('framework_backups', $id);
$date = MySQL::getDateLikeMySQL();
$stmt = $conn->prepare("UPDATE framework_backups SET backup_status = ?, backup_date_end = ? WHERE id = ?");
$stmt->bind_param('ssi', $status, $date, $id);
$stmt->execute();
MySQL::requestUnLock('framework_backups', $id);
Logger::log(LoggerLevels::INFO, LoggerTypes::BACKUP, "Backup has been marked as completed.");
} else {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to mark backup as completed: Backup does not exist.");
}
} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to mark backup as completed: " . $e->getMessage());
}
}
/**
* Get the status of a backup
*
* @param int $id
* @return string
*/
public static function getBackupStatus(int $id): string
{
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
$stmt = $conn->prepare("SELECT backup_status FROM framework_backups WHERE id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
$status = $result->fetch_assoc();
return $status['backup_status'];
} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to get backup status: " . $e->getMessage());
return null;
}
}

/**
* Get all backups from the database
*
* @return array
*/
public static function getBackups(): array {
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
$result = $conn->query("SELECT * FROM framework_backups WHERE `deleted` = 'false'");
if ($result->num_rows == 0) {
return [];
} else {
$backups = [];
while ($row = $result->fetch_assoc()) {
$backups[] = $row;
}
return $backups;
}
} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to get backups: " . $e->getMessage());
return [];
}
}
/**
* Mark a backup as deleted
*
* @return void
*/
public static function markAsDeleted(int $id) : void {
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
$stmt = $conn->prepare("DELETE FROM framework_backups WHERE `framework_backups`.`id` = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER, "(App/Backup/Database.php) Failed to mark backup as deleted: " . $e->getMessage());
}
}
/**
* Get the backup path
* @param int $id
* @return array|bool|null
*/
public static function getBackupPath(int $id) {
try {
$db = new MySQL();
$conn = $db->connectMYSQLI();
$stmt = $conn->prepare("SELECT backup_path FROM framework_backups WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
return $row['backup_path'];
} else {
return null;
}

} catch (Exception $e) {
Logger::log(LoggerLevels::CRITICAL, LoggerTypes::OTHER,"Failed to get the backup path". $e->getMessage());
}
}
}
10 changes: 10 additions & 0 deletions app/Backup/Status.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace MythicalSystemsFramework\Backup;

interface Status {
public const IN_PROGRESS = 'IN_PROGRESS';
public const FAILED = 'FAILED';
public const DONE = 'DONE';

}
Loading

0 comments on commit cf30a50

Please sign in to comment.