Files
ByteCenter/app/controllers/configuracionController.php
2026-08-04 19:20:18 -03:00

495 lines
18 KiB
PHP

<?php
// Validacion de token
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { // Recorre todos los caracteres (siempre) y retorna true or false
$_SESSION['flash_error'] = 'Acción inválida.';
header('Location: index.php?opt=inicio_operador');
exit;
}
}
// Requiero helper que contiene métodos para encriptar y desencriptar contraseñas
require_once __DIR__ . '/../helpers/crypto.php';
// Requiero modelo de configuración
require __DIR__ . '/../models/configuracionModel.php';
$configuracionmodel = new configuracionModel();
// Validar sesión
if (!isset($_SESSION['user'])) {
header("Location: index.php?opt=login_operador");
exit;
}
$user = $_SESSION['user']; // Defino el array del usuario dentro de una variable
$rol = $user['rol']; // Defino el rol dentro de la variable
$esAdmin = ($rol === 'admin'); // Variable booleana, true = admin
// Verifico rol del usuarios (solo se permite admin)
if (!$esAdmin) {
header("Location: index.php?opt=inicio_operador");
exit;
}
$opt = $_GET['opt'] ?? null;
// Manejo de opt
switch ($opt) {
// OBTENER CONFIGURACIÓN
case 'configuracion':
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$configuracion = $configuracionmodel->obtenerConfiguracion();
// Desencriptación de contraseña emisor
if (isset($configuracion['contrasenia_emisor'])) {
$configuracion['contrasenia_emisor_formateada'] = decryptData($configuracion['contrasenia_emisor']);
} else {
$configuracion['contrasenia_emisor_formateada'] = 'Sin Setear';
}
// Saneamiento de email emisor
if (isset($configuracion['email_emisor'])) {
$configuracion['email_emisor'] = $configuracion['email_emisor'];
} else {
$configuracion['email_emisor'] = 'Sin Setear';
}
// Validaciones
if (empty($configuracion)) {
$_SESSION['flash_error'] = 'Ocurrió un error al cargar la configuración.';
header("Location: index.php?opt=configuracion");
exit;
}
// Saneamiento de fecha
if (!empty($configuracion['inicio_act'])) {
$dt = new DateTime($configuracion['inicio_act']);
$configuracion['inicio_act_formateada'] = $dt->format('d/m/Y');
} else {
$configuracion['inicio_act_formateada'] = '-';
}
ob_start();
require_once __DIR__ . '/../views/configuracion/configuracionView.php';
return ob_get_clean();
}
// ACTUALIZAR CONFIGURACIÓN
case 'actualizar_config':
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$configuracion = [
'nombre' => trim($_POST['nombre'] ?? ''),
'direccion' => trim($_POST['direccion'] ?? ''),
'ciudad' => trim($_POST['ciudad'] ?? ''),
'codigo_postal' => trim($_POST['codigo_postal'] ?? ''),
'provincia' => trim($_POST['provincia'] ?? ''),
'telefono' => trim($_POST['telefono'] ?? ''),
'email' => trim($_POST['email'] ?? ''),
'cond_iva' => trim($_POST['cond_iva'] ?? 'responsable_inscripto'),
'cuit' => ($_POST['cuit_1'] ?? '') . ($_POST['cuit_2'] ?? '') . ($_POST['cuit_3'] ?? ''),
'iva' => $_POST['iva'] ?? 21,
'hora_apertura_maniana' => trim($_POST['hora_apertura_maniana'] ?? ''),
'hora_cierre_maniana' => trim($_POST['hora_cierre_maniana'] ?? ''),
'hora_apertura_tarde' => trim($_POST['hora_apertura_tarde'] ?? ''),
'hora_cierre_tarde' => trim($_POST['hora_cierre_tarde'] ?? ''),
'mail_automatico' => isset($_POST['mail_automatico']) ? 1 : 0,
'cargo_cancelacion_servicio' => $_POST['cargo_cancelacion_servicio'] ?? 0,
'email_emisor' => trim($_POST['email_emisor'] ?? ''),
'contrasenia_emisor' => trim($_POST['contrasenia_emisor'] ?? ''),
];
$errores = [];
// Validaciones
// NOMBRE
if ($configuracion['nombre'] === '') {
$errores[] = "El nombre no puede estar vacío.";
} else if (!preg_match('/^[A-Za-zÁÉÍÓÚáéíóú0-9\s\.\-]{2,100}$/', $configuracion['nombre'])) {
$errores[] = "El nombre contiene caracteres inválidos.";
} else if (strlen($configuracion['nombre']) < 2) {
$errores[] = "El nombre debe tener al menos 2 caracteres.";
} else if (strlen($configuracion['nombre']) > 50) {
$errores[] = "El nombre no puede superar los 50 caracteres.";
}
// DIRECCIÓN
if ($configuracion['direccion'] === '') {
$errores[] = "La dirección no puede estar vacía.";
} else if (strlen($configuracion['direccion']) < 3) {
$errores[] = "La dirección debe tener al menos 3 caracteres.";
} else if (strlen($configuracion['direccion']) > 100) {
$errores[] = "La dirección no puede superar los 100 caracteres.";
}
// CIUDAD
if ($configuracion['ciudad'] === '') {
$errores[] = "La ciudad no puede estar vacía.";
} else if (!preg_match('/^[A-Za-zÁÉÍÓÚáéíóúñÑ\s]{2,100}$/', $configuracion['ciudad'])) {
$errores[] = "La ciudad solo puede contener letras y espacios.";
}
// CODIGO POSTAL
if ($configuracion['codigo_postal'] === '') {
$errores[] = "El código postal no puede estar vacío.";
} else if (!preg_match('/^[0-9]{4}$/', $configuracion['codigo_postal'])) {
$errores[] = "El código postal debe tener 4 dígitos.";
}
// PROVINCIA
if ($configuracion['provincia'] === '') {
$errores[] = "La provincia no puede estar vacía.";
} else if (!preg_match('/^[A-Za-zÁÉÍÓÚáéíóúñÑ\s]{2,100}$/', $configuracion['provincia'])) {
$errores[] = "La provincia contiene caracteres inválidos.";
}
// TELÉFONO
if ($configuracion['telefono'] === '') {
$errores[] = "El teléfono no puede estar vacío.";
} else if (!preg_match('/^[0-9]{10}$/', $configuracion['telefono'])) {
$errores[] = "El teléfono debe tener 10 dígitos.";
}
// EMAIL
if ($configuracion['email'] === '') {
$errores[] = "El email no puede estar vacío.";
} else if (!filter_var($configuracion['email'], FILTER_VALIDATE_EMAIL)) {
$errores[] = "Formato de email inválido.";
} else if (strlen($configuracion['email']) > 100) {
$errores[] = "El email no puede superar los 100 caracteres.";
}
// CONDICIÓN_IVA
$condicionesValidas = [
'consumidor_final',
'responsable_inscripto',
'monotributo'
];
if (!in_array($configuracion['cond_iva'], $condicionesValidas)) {
$errores[] = "Condición de IVA inválida.";
}
// CUIT
if (!preg_match('/^\d{10,11}$/', $configuracion['cuit'])) {
$errores[] = 'CUIT inválido. Debe contener solo números.';
}
// IVA
if (!is_numeric($configuracion['iva'])) {
$errores[] = "El IVA debe ser numérico.";
}
// HORA DE APERTURA Y CIERRE
if ($configuracion['hora_apertura_maniana'] && $configuracion['hora_cierre_maniana']) {
if ($configuracion['hora_apertura_maniana'] >= $configuracion['hora_cierre_maniana']) {
$errores[] = "El horario de apertura debe ser menor al de cierre.";
}
}
if ($configuracion['hora_apertura_tarde'] && $configuracion['hora_cierre_tarde']) {
if ($configuracion['hora_apertura_tarde'] >= $configuracion['hora_cierre_tarde']) {
$errores[] = "El horario de apertura debe ser menor al de cierre.";
}
}
// CARGO POR CANCELACIÓN DE SERVICIO
if (!is_numeric($configuracion['cargo_cancelacion_servicio'])) {
$errores[] = "El cargo por cancelación debe ser numérico.";
}
// EMAIL EMISOR
if ($configuracion['email_emisor'] === '') {
$errores[] = "El email no puede estar vacío.";
} else if (!filter_var($configuracion['email_emisor'], FILTER_VALIDATE_EMAIL)) {
$errores[] = "Formato de email inválido.";
} else if (strlen($configuracion['email_emisor']) > 100) {
$errores[] = "El email no puede superar los 100 caracteres.";
}
// CONTRASEÑA EMISOR
if (strlen($configuracion['contrasenia_emisor']) > 100) {
$errores[] = "Contraseña demasiado larga.";
}
if (!empty($errores)) {
$_SESSION['flash_error'] = implode('<br>', $errores); // Se guarda en $_SESSION el error
header("Location: index.php?opt=configuracion");
exit;
}
// ENCRIPTACION DE CONTRASEÑA
if ($configuracion['contrasenia_emisor'] !== '') {
$passLimpia = str_replace(' ', '', $configuracion['contrasenia_emisor']);
$configuracion['contrasenia_emisor'] = encryptData($passLimpia);
}
// Actualizamos datos de configuración
if ($configuracionmodel->actualizarConfiguracion($configuracion)) {
$_SESSION['flash_success'] = 'Configuración actualizada correctamente.';
header("Location: index.php?opt=configuracion");
exit;
} else {
$_SESSION['flash_error'] = 'Error al actualizar la configuración.';
header("Location: index.php?opt=configuracion");
exit;
}
}
// GENERAR BACKUP
case 'generar_backup':
// Obtenemos desde donde viene la petición (puede ser backup automático)
$return = $_GET['from'] ?? 'backups';
$backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');
$fecha = date('Y-m-d_H-i-s');
$archivo = "backup_$fecha.sql"; // Generación de nombre de archivo con extensión
$rutaBackup = $backupDir . $archivo; // Generación de ruta completa de archivo backup
// Datos de conexión
$rutaBackup = escapeshellarg($rutaBackup); // Permite omitir espacios o caracteres no deseados (puede romper ruta o comando)
$host = escapeshellarg($_ENV['DB_HOST']);
$usuario = escapeshellarg($_ENV['DB_USER']);
$database = escapeshellarg($_ENV['DB_NAME']);
$password = escapeshellarg($_ENV['DB_PASSWORD']);
// Comando pg_dump
$comando = "PGPASSWORD=$password pg_dump --clean --if-exists --no-owner -h $host -U $usuario -d $database > $rutaBackup"; // Guardamos el comando a ejecutar mediante pg_dump
exec($comando, $output, $resultado); // Lo ejecutamos
if ($resultado === 0) { // Entra al if solo si el (exec) dio como resultado 0 (éxito) en la variable $resultado
// Limitar cantidad de backups
$maxBackups = 4;
$archivos = glob($backupDir . '*.sql'); // Permite obtener todos los archivos ubicados en esa ruta
if (count($archivos) > $maxBackups) { // Contamos la cantidad de archivos (comparando con la cantidad máxima definida)
usort($archivos, function ($a, $b) {
return filemtime($a) - filemtime($b);
}); // Se ordenan en base a la fecha de modificación de mas antiguo a mas nuevo
while (count($archivos) > $maxBackups) {
$archivoEliminar = array_shift($archivos); // Se elimina el archivo del array
unlink($archivoEliminar); // Se elimina fisicamente el archivo
}
}
if (isset($_GET['auto'])) {
$_SESSION['flash_success'] = "Copia de seguridad automática generada con éxito.";
} else {
$_SESSION['flash_success'] = "Backup generado correctamente.";
}
} else {
$_SESSION['flash_error'] = "Error al generar el backup.";
}
header("Location: index.php?opt=$return");
exit;
// LISTAR BACKUPS
case 'backups':
$backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');
$archivos = glob($backupDir . '*.sql');
$backups = [];
$totalSize = 0;
$ultimoBackup = null;
if ($archivos) {
usort($archivos, function ($a, $b) {
return filemtime($b) <=> filemtime($a);
});
$ultimoBackup = date('d/m/Y H:i', filemtime($archivos[0])); // Guardamos el archivo mas reciente para informar en la vista
foreach ($archivos as $archivo) {
$size = filesize($archivo); // Obtenemos el tamaño total del archivo
$backups[] = [
'nombre' => basename($archivo), // Obtenemos nombre de archivo
'fecha' => date('d/m/Y H:i', filemtime($archivo)), // Obtenemos la fecha del archivo
'size' => round($size / 1024, 2) . ' KB' // Obtenemos el tamaño del archivo en KB
];
$totalSize += $size; // Acumulamos el tamaño de los archivos para obtener el total
}
}
$totalSize = round($totalSize / 1024 / 1024, 2); // Total utilizado en MB
ob_start();
require __DIR__ . '/../views/configuracion/buckupsView.php';
return ob_get_clean();
// DESCARGAR BACKUP
case 'descargar_backup':
$file = basename($_GET['file']);
$backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');
$ruta = $backupDir . $file;
if (!file_exists($ruta)) {
header("Location: index.php?opt=backups");
exit;
}
header('Content-Type: application/sql'); // Indica el tipo de contenido del archivo (SQL en este caso)
header('Content-Disposition: attachment; filename="' . $file . '"'); // Fuerza la descarga del archivo en lugar de mostrarlo en el navegador y define el nombre con el que se va a guardar
header('Content-Length: ' . filesize($ruta)); // Informa el tamaño del archivo (mejora la descarga/progreso)
readfile($ruta); // Envía el contenido del archivo al navegador
exit;
// ELIMINAR BACKUP
case 'eliminar_backup':
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');
$archivo = basename($_POST['file']); // Evita rutas maliciosas
$rutaArchivo = $backupDir . $archivo;
if (file_exists($rutaArchivo)) {
unlink($rutaArchivo);
$_SESSION['flash_success'] = "Backup eliminado correctamente.";
} else {
$_SESSION['flash_error'] = "El archivo no existe.";
}
header("Location: index.php?opt=backups");
exit;
}
// RESTAURAR BACKUP
case 'restaurar_backup':
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');
$archivo = basename($_POST['file']);
$rutaBackup = $backupDir . $archivo;
if (!file_exists($rutaBackup)) {
$_SESSION['flash_error'] = "El archivo de backup no existe.";
header("Location: index.php?opt=backups");
exit;
}
$host = escapeshellarg($_ENV['DB_HOST']);
$usuario = escapeshellarg($_ENV['DB_USER']);
$database = escapeshellarg($_ENV['DB_NAME']);
$password = escapeshellarg($_ENV['DB_PASSWORD']);
// 1. BACKUP AUTOMÁTICO PREVIO
$backupSeguridad = $backupDir . 'auto_pre_restore_' . date('Y-m-d_H-i-s') . '.sql';
$backupSeguridadEscaped = escapeshellarg($backupSeguridad);
$comandoBackup = "PGPASSWORD=$password pg_dump --clean --if-exists --no-owner -h $host -U $usuario -d $database > $backupSeguridadEscaped";
exec($comandoBackup, $outBackup, $resultadoBackup);
if ($resultadoBackup !== 0) {
$_SESSION['flash_error'] = "No se pudo crear el backup de seguridad antes de restaurar.";
header("Location: index.php?opt=backups");
exit;
}
// 2. RESTAURAR COPIA DE SEGURIDAD SELECCIONADA
$rutaBackupEscaped = escapeshellarg($rutaBackup);
$comandoRestore = "PGPASSWORD=$password psql -h $host -U $usuario -d $database < $rutaBackupEscaped";
exec($comandoRestore, $output, $resultadoRestore);
if ($resultadoRestore === 0) {
$_SESSION['flash_success'] = "Backup restaurado correctamente. Se creó una copia de seguridad previa.";
} else {
$_SESSION['flash_error'] = "Error al restaurar el backup.";
}
header("Location: index.php?opt=backups");
exit;
}
}