set('defaultFont', 'DejaVu Sans'); $options->setIsHtml5ParserEnabled(true); $options->setIsFontSubsettingEnabled(true); $dompdf = new \Dompdf\Dompdf($options); $dompdf->loadHtml($html); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); $filename = 'Oficio_' . preg_replace('/[^A-Za-z0-9\-_]/', '_', $oficio['numero_oficio']) . '_' . date('Ymd') . '.pdf'; $dompdf->stream($filename, ['Attachment' => true]); } else { // Fallback: HTML descargable header('Content-Type: text/html; charset=utf-8'); header('Content-Disposition: attachment; filename="oficio_' . $oficio['id'] . '.html"'); echo $html; } exit(); } /** * Genera HTML del oficio para PDF */ private static function htmlOficio(array $o): string { $logo = file_exists(LOGO_PATH) ? '' : ''; $fecha = date('d/m/Y H:i'); $vence = $o['fecha_vencimiento'] ? date('d/m/Y', strtotime($o['fecha_vencimiento'])) : 'Sin fecha'; $recep = date('d/m/Y', strtotime($o['fecha_recepcion'])); $etiquetas = $o['etiquetas'] ?? '—'; $colorPrioridad = ['alta' => '#d32f2f', 'media' => '#fbc02d', 'baja' => '#388e3c']; $colorEstado = ['recibido' => '#2e7d32', 'en_proceso' => '#fbc02d', 'respondido' => '#0288d1', 'vencido' => '#d32f2f', 'archivado' => '#64748b']; $pColor = $colorPrioridad[$o['prioridad']] ?? '#64748b'; $eColor = $colorEstado[$o['estado']] ?? '#64748b'; return <<
OFICIO DTIC
{$o['numero_oficio']}  ·  {$o['tipo']}
$logo
{INSTITUCION_NOMBRE}
{$o['numero_oficio']}
{$o['asunto']}
Remitente
{$o['remitente']}
Destinatario
{$o['destinatario']}
Fecha de Recepción
$recep
Fecha de Vencimiento
$vence
Prioridad
{$o['prioridad']}
Estado
{$o['estado']}
Responsable
{$o['responsable_nombre']}
Etiquetas
$etiquetas
Descripción
{$o['descripcion']}
HTML; } /** * Descarga backup de la BD como SQL */ public static function descargarBackupSQL(): void { $dbName = env('DB_NAME', 'gestion_documentos'); $dbHost = env('DB_HOST', 'localhost'); $dbUser = env('DB_USER', 'root'); $dbPass = env('DB_PASS', ''); $fecha = date('Ymd_His'); $archivo = "$dbName-backup-$fecha.sql"; $backupDir = BASE_PATH . '/exports/backups/'; if (!is_dir($backupDir)) mkdir($backupDir, 0755, true); $cmd = sprintf( 'mysqldump --host=%s --user=%s --password=%s %s > %s', escapeshellarg($dbHost), escapeshellarg($dbUser), escapeshellarg($dbPass), escapeshellarg($dbName), escapeshellarg($backupDir . $archivo) ); system($cmd, $ret); if ($ret === 0 && file_exists($backupDir . $archivo)) { header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $archivo . '"'); header('Content-Length: ' . filesize($backupDir . $archivo)); readfile($backupDir . $archivo); } else { http_response_code(500); echo 'Error al generar el respaldo. Verifique mysqldump en el servidor.'; } exit(); } } // Dispatcher si se invoca directamente if (basename($_SERVER['PHP_SELF']) === 'ReporteController.php') { AuthController::requerirAdmin(); $action = $_GET['action'] ?? ''; if ($action === 'backup_sql') ReporteController::descargarBackupSQL(); redirect(APP_URL . '/views/reportes/index.php'); }