| 1 |
<?php
// ============================================================
// SIDE - ARC 1.0
// Archivo: exportar.php
// Propósito: Exportación contextual recursiva a CSV.
// Recupera el registro raíz indicado y TODOS sus
// subordinados en cascada mediante WITH RECURSIVE.
// El CSV resultante es compatible con importar.php.
// Protegido: solo administradores.
// ============================================================
require_once 'conexion.php';
require_once 'helpers.php';
requerir_admin();
// --- Validar ID del registro raíz de la exportación ---
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
header('Location: /apps/side-arc/cuadro_clasificacion.php');
exit;
}
$id_raiz = (int) $_GET['id'];
// --- Verificar que el registro existe ---
$stmt = mysqli_prepare($conexion,
"SELECT id, titulo FROM descripcion_isadg WHERE id = ? LIMIT 1");
mysqli_stmt_bind_param($stmt, 'i', $id_raiz);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$registro = mysqli_fetch_assoc($res);
mysqli_free_result($res);
mysqli_stmt_close($stmt);
if (!$registro) {
header('Location: /apps/side-arc/cuadro_clasificacion.php');
exit;
}
// ============================================================
// CONSULTA RECURSIVA: registro raíz + todos sus descendientes
// WITH RECURSIVE desciende por parent_id hasta las hojas.
// Se añade la columna 'profundidad' para ordenar el árbol
// correctamente en el CSV (raíz primero, hojas al final).
// ============================================================
$sql = "
WITH RECURSIVE descendientes AS (
-- Caso base: el registro raíz seleccionado
SELECT
id, parent_id, codigo_referencia, titulo, fechas,
nivel_descripcion, volumen_soporte, nombre_productor,
historia_institucional, alcance_contenido,
valoracion_eliminacion, organizacion,
condiciones_acceso, condiciones_reproduccion,
lengua_escritura, caracteristicas_fisicas,
unidades_relacionadas, notas,
fecha_ingreso_registro, fechas_descripciones,
estado, nombre_descriptor, nota_archivero,
fecha_creacion_revision, reglas_normas,
pa_nombre, pa_geografico, pam_materia,
fecha_inicial_filtro, fecha_final_filtro,
0 AS profundidad
FROM descripcion_isadg
WHERE id = ?
UNION ALL
-- Caso recursivo: hijos de cada nodo ya encontrado
SELECT
d.id, d.parent_id, d.codigo_referencia, d.titulo, d.fechas,
d.nivel_descripcion, d.volumen_soporte, d.nombre_productor,
d.historia_institucional, d.alcance_contenido,
d.valoracion_eliminacion, d.organizacion,
d.condiciones_acceso, d.condiciones_reproduccion,
d.lengua_escritura, d.caracteristicas_fisicas,
d.unidades_relacionadas, d.notas,
d.fecha_ingreso_registro, d.fechas_descripciones,
d.estado, d.nombre_descriptor, d.nota_archivero,
d.fecha_creacion_revision, d.reglas_normas,
d.pa_nombre, d.pa_geografico, d.pam_materia,
d.fecha_inicial_filtro, d.fecha_final_filtro,
desc2.profundidad + 1
FROM descripcion_isadg d
INNER JOIN descendientes desc2 ON d.parent_id = desc2.id
)
SELECT * FROM descendientes
ORDER BY profundidad ASC, titulo ASC
";
$stmt2 = mysqli_prepare($conexion, $sql);
mysqli_stmt_bind_param($stmt2, 'i', $id_raiz);
mysqli_stmt_execute($stmt2);
$res2 = mysqli_stmt_get_result($stmt2);
// ============================================================
// COLUMNAS DEL CSV
// Coinciden exactamente con las columnas de importar.php
// para garantizar compatibilidad de ida y vuelta.
// Las columnas de sistema (id, parent_id, objeto_digital,
// profundidad) se excluyen del CSV exportable.
// ============================================================
$columnas_csv = [
'codigo_referencia', 'titulo', 'fechas', 'nivel_descripcion',
'volumen_soporte', 'nombre_productor', 'historia_institucional',
'alcance_contenido', 'valoracion_eliminacion', 'organizacion',
'condiciones_acceso', 'condiciones_reproduccion', 'lengua_escritura',
'caracteristicas_fisicas', 'unidades_relacionadas', 'notas',
'fecha_ingreso_registro', 'fechas_descripciones', 'estado',
'nombre_descriptor', 'nota_archivero', 'fecha_creacion_revision',
'reglas_normas', 'pa_nombre', 'pa_geografico', 'pam_materia',
'fecha_inicial_filtro', 'fecha_final_filtro',
];
// ============================================================
// GENERAR NOMBRE DEL ARCHIVO
// Usa el título del registro raíz saneado para el nombre.
// ============================================================
$titulo_seguro = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $registro['titulo']);
$titulo_seguro = substr($titulo_seguro, 0, 60);
$nombre_archivo = 'exportacion_' . $titulo_seguro . '_' . date('Ymd_His') . '.csv';
// ============================================================
// ENVIAR CABECERAS HTTP PARA DESCARGA
// ============================================================
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $nombre_archivo . '"');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// ============================================================
// ESCRIBIR CSV DIRECTAMENTE A LA SALIDA
// ============================================================
$out = fopen('php://output', 'w');
// BOM UTF-8 para compatibilidad con Excel
fputs($out, "\xEF\xBB\xBF");
// Fila de cabecera
fputcsv($out, $columnas_csv, ',', '"');
// Contador de registros exportados
$total_exportados = 0;
// Filas de datos
while ($fila = mysqli_fetch_assoc($res2)) {
$fila_csv = [];
foreach ($columnas_csv as $col) {
// Convertir NULL a cadena vacía en el CSV
$fila_csv[] = $fila[$col] ?? '';
}
fputcsv($out, $fila_csv, ',', '"');
$total_exportados++;
}
fclose($out);
mysqli_free_result($res2);
mysqli_stmt_close($stmt2);
mysqli_close($conexion);
// La salida ya fue enviada como descarga: no hay más HTML.
exit;
|