Files
safekat/ci4/app/Controllers/Sistema/Backups.php
imnavajas 7aa577f316 Avances
2025-06-10 15:10:19 +02:00

237 lines
7.7 KiB
PHP

<?php
namespace App\Controllers\Sistema;
use App\Controllers\BaseController;
use App\Models\Sistema\BackupModel;
use phpseclib3\Net\SFTP;
use ZipArchive;
class Backups extends BaseController
{
protected $backupModel;
public function __construct()
{
$this->backupModel = new BackupModel();
}
public function index()
{
helper('filesystem');
$entries = $this->backupModel->orderBy('created_at', 'DESC')->findAll();
$backups = [];
foreach ($entries as $entry) {
$file = $entry['filename'];
$localPath = $entry['path_local'];
$remotePath = $entry['path_remote'];
$isLocal = $localPath && file_exists($localPath);
$isRemote = !empty($remotePath);
if ($isLocal) {
$fecha = date('Y-m-d H:i', filemtime($localPath));
$tamano = filesize($localPath);
$tamanoFmt = number_format($tamano / 1024, 2) . ' KB';
// Actualizar la BD si ha cambiado
if ($entry['size'] != $tamano) {
$this->backupModel->update($entry['id'], [
'size' => $tamano,
]);
}
} else {
$fecha = $entry['created_at'] ?? '-';
$tamano = $entry['size'] ?? null;
$tamanoFmt = $tamano ? number_format($tamano / 1024, 2) . ' KB' : '-';
}
$backups[] = [
'id' => $entry['id'],
'filename' => $file,
'fecha' => $fecha,
'tamano' => $tamanoFmt,
'local' => $isLocal,
'remoto' => $isRemote,
];
}
return view('themes/vuexy/form/backups/backupList', ['backups' => $backups]);
}
public function create()
{
helper('filesystem');
$timestamp = date('Ymd_His');
$sqlFilename = "backup_{$timestamp}.sql";
$zipFilename = "backup_{$timestamp}.zip";
$sqlPath = WRITEPATH . 'backups/' . $sqlFilename;
$zipPath = WRITEPATH . 'backups/' . $zipFilename;
$dbConfig = config('Database')->default;
$host = $dbConfig['hostname'];
$username = $dbConfig['username'];
$password = $dbConfig['password'];
$database = $dbConfig['database'];
$command = "mysqldump -h {$host} -u{$username} -p'{$password}' {$database} > {$sqlPath}";
system($command, $retval);
if ($retval !== 0) {
throw new \RuntimeException("Error al crear el backup.");
}
// Crear el zip
$zip = new ZipArchive();
if ($zip->open($zipPath, ZipArchive::CREATE) === TRUE) {
$zip->addFile($sqlPath, $sqlFilename);
$zip->close();
unlink($sqlPath); // eliminar el .sql original
} else {
throw new \RuntimeException("Error al comprimir el backup.");
}
// Insertar en BD
$backupId = $this->backupModel->insert([
'filename' => $zipFilename,
'type' => 'manual',
'path_local' => $zipPath,
'path_remote' => null,
'size' => filesize($zipPath),
'status' => 'pendiente',
'created_at' => date('Y-m-d H:i:s')
], true);
// Enviar a SFTP
$this->sendToSFTP($zipPath, $zipFilename);
// Actualizar BD
$remotePath = "/users/erp2019/backups_erp/" . $zipFilename;
$this->backupModel->update($backupId, [
'path_remote' => $remotePath,
'status' => 'subido'
]);
return redirect()->to(route_to('backupsList'))->with('message', 'Backup creado, comprimido y enviado.');
}
public function restoreLocal($file)
{
$path = WRITEPATH . 'backups/' . $file;
if (!file_exists($path)) {
throw new \CodeIgniter\Exceptions\PageNotFoundException("Backup no encontrado.");
}
$zip = new ZipArchive();
if ($zip->open($path) === TRUE) {
$extractPath = WRITEPATH . 'backups/tmp_restore/';
if (!is_dir($extractPath)) {
mkdir($extractPath, 0775, true);
}
$zip->extractTo($extractPath);
$zip->close();
$sqlFiles = glob($extractPath . '*.sql');
if (count($sqlFiles) === 0) {
throw new \RuntimeException("No se encontró ningún archivo .sql en el ZIP");
}
$db = \Config\Database::connect();
$sql = file_get_contents($sqlFiles[0]);
$db->query('SET FOREIGN_KEY_CHECKS=0;');
$db->query($sql);
$db->query('SET FOREIGN_KEY_CHECKS=1;');
array_map('unlink', glob($extractPath . '*'));
rmdir($extractPath);
return redirect()->to('/backups')->with('message', 'Backup restaurado correctamente.');
} else {
throw new \RuntimeException("No se pudo abrir el archivo ZIP");
}
}
public function deleteLocal($id)
{
$backup = $this->backupModel->find($id);
if ($backup && $backup['path_local'] && file_exists($backup['path_local'])) {
unlink($backup['path_local']);
$this->backupModel->update($id, ['path_local' => null]);
return redirect()->to(route_to('backupsList'))->with('message', 'Backup local eliminado.');
}
return redirect()->to(route_to('backupsList'))->with('error', 'Archivo no encontrado.');
}
public function restoreRemote($filename)
{
helper('filesystem');
// Buscar el backup en la base de datos
$backup = $this->backupModel->where('filename', $filename)->first();
if (!$backup || empty($backup['path_remote'])) {
return redirect()->to(route_to('backupsList'))->with('error', 'Backup remoto no encontrado en la base de datos.');
}
// Parámetros SFTP
$sftpHost = 'sftp.hidrive.ionos.com';
$sftpUser = 'erp2019';
$sftpPass = 'Z2CjX7kd2h';
$remotePath = $backup['path_remote'];
$localPath = WRITEPATH . 'backups/' . $filename;
// Conectar al SFTP
$sftp = new SFTP($sftpHost);
if (!$sftp->login($sftpUser, $sftpPass)) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo autenticar en el servidor SFTP.');
}
// Descargar el archivo
$fileContents = $sftp->get($remotePath);
if ($fileContents === false) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo descargar el archivo remoto.');
}
// Guardar localmente
if (write_file($localPath, $fileContents) === false) {
return redirect()->to(route_to('backupsList'))->with('error', 'No se pudo guardar el archivo localmente.');
}
// Actualizar la base de datos para marcar el archivo como local
$this->backupModel->update($backup['id'], [
'path_local' => $localPath,
]);
// Restaurar usando el método local
return $this->restoreLocal($filename);
}
private function sendToSFTP($localPath, $remoteFilename)
{
$sftpHost = 'sftp.hidrive.ionos.com';
$sftpUser = 'erp2019';
$sftpPass = 'Z2CjX7kd2h';
$remotePath = '/users/erp2019/backups_erp/' . $remoteFilename;
$sftp = new SFTP($sftpHost);
if (!$sftp->login($sftpUser, $sftpPass)) {
throw new \RuntimeException('Error de autenticación SFTP');
}
$fileContents = file_get_contents($localPath);
if (!$sftp->put($remotePath, $fileContents)) {
throw new \RuntimeException("No se pudo subir el backup al servidor SFTP.");
}
}
}