| 1 |
<?php
// ============================================================
// SIDE - ARC 1.0
// Archivo: procesar_importacion.php
// ============================================================
require_once 'conexion.php';
require_once 'helpers.php';
requerir_admin();
// --- Solo POST ---
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: /apps/side-arc/index.php');
exit;
}
// --- Validar CSRF ---
if (
empty($_POST['csrf_token']) ||
empty($_SESSION['csrf_token']) ||
!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])
) {
header('Location: /apps/side-arc/index.php');
exit;
}
unset($_SESSION['csrf_token']);
// --- Validar parent_id ---
if (!isset($_POST['parent_id']) || !is_numeric($_POST['parent_id'])) {
header('Location: /apps/side-arc/cuadro_clasificacion.php');
exit;
}
$parent_id = (int) $_POST['parent_id'];
// --- Cargar nivel del padre ---
$stmt = mysqli_prepare($conexion,
"SELECT nivel_descripcion FROM descripcion_isadg WHERE id = ? LIMIT 1");
mysqli_stmt_bind_param($stmt, 'i', $parent_id);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$padre = mysqli_fetch_assoc($res);
mysqli_free_result($res);
mysqli_stmt_close($stmt);
if (!$padre) {
header('Location: /apps/side-arc/cuadro_clasificacion.php');
exit;
}
$nivel_padre = $padre['nivel_descripcion'];
$niveles_validos = niveles_permitidos_bajo($nivel_padre);
// ============================================================
// VALIDAR ARCHIVO CSV
// ============================================================
$redir_base = '/apps/side-arc/importar.php?parent_id=' . $parent_id;
if (
empty($_FILES['archivo_csv']) ||
$_FILES['archivo_csv']['error'] !== UPLOAD_ERR_OK
) {
$_SESSION['importar_reporte'] = [
'total' => 0, 'insertadas' => 0, 'rechazadas' => 0,
'errores' => [['fila'=>0,'titulo'=>'','motivo'=>'No se recibió el archivo CSV.']]
];
header('Location: ' . $redir_base);
exit;
}
$archivo = $_FILES['archivo_csv'];
$tmp_path = $archivo['tmp_name'];
$tamanio = $archivo['size'];
$ext = strtolower(pathinfo($archivo['name'], PATHINFO_EXTENSION));
if ($ext !== 'csv' || $tamanio > 5 * 1024 * 1024) {
$_SESSION['importar_reporte'] = [
'total' => 0, 'insertadas' => 0, 'rechazadas' => 0,
'errores' => [['fila'=>0,'titulo'=>'','motivo'=>
'Archivo inválido. Solo CSV de hasta 5 MB.']]
];
header('Location: ' . $redir_base);
exit;
}
// ============================================================
// LEER Y PROCESAR EL CSV
// ============================================================
$handle = fopen($tmp_path, 'r');
// Eliminar BOM UTF-8 si existe
$bom = fread($handle, 3);
if ($bom !== "\xEF\xBB\xBF") {
rewind($handle);
}
// Leer cabecera
$cabecera = fgetcsv($handle, 0, ',', '"');
if (!$cabecera) {
fclose($handle);
$_SESSION['importar_reporte'] = [
'total' => 0, 'insertadas' => 0, 'rechazadas' => 0,
'errores' => [['fila'=>1,'titulo'=>'','motivo'=>
'No se pudo leer la cabecera del CSV.']]
];
header('Location: ' . $redir_base);
exit;
}
$cabecera = array_map(fn($c) => strtolower(trim($c)), $cabecera);
// Verificar columnas mínimas requeridas
foreach (['codigo_referencia', 'titulo', 'nivel_descripcion'] as $col_req) {
if (!in_array($col_req, $cabecera, true)) {
fclose($handle);
$_SESSION['importar_reporte'] = [
'total' => 0, 'insertadas' => 0, 'rechazadas' => 0,
'errores' => [['fila'=>1,'titulo'=>'','motivo'=>
"Falta columna requerida: '$col_req' en la cabecera del CSV."]]
];
header('Location: ' . $redir_base);
exit;
}
}
// ============================================================
// PREPARAR INSERT
// ============================================================
$sql_insert = "INSERT INTO descripcion_isadg (
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
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
$stmt_ins = mysqli_prepare($conexion, $sql_insert);
// ============================================================
// HELPER: obtener valor de columna del CSV
// ============================================================
function col(array $fila, array $cabecera, string $nombre): ?string {
$idx = array_search($nombre, $cabecera, true);
if ($idx === false) return null;
$val = trim($fila[$idx] ?? '');
return $val === '' ? null : $val;
}
// ============================================================
// PROCESAR FILAS
// ============================================================
$reporte = [
'total' => 0,
'insertadas' => 0,
'rechazadas' => 0,
'errores' => [],
];
$num_fila = 1;
while (($fila = fgetcsv($handle, 0, ',', '"')) !== false) {
$num_fila++;
$reporte['total']++;
if (count(array_filter($fila, fn($v) => trim($v) !== '')) === 0) {
$reporte['rechazadas']++;
$reporte['errores'][] = ['fila' => $num_fila, 'titulo' => '', 'motivo' => 'Fila vacía, omitida.'];
continue;
}
$titulo = col($fila, $cabecera, 'titulo');
$codigo_ref = col($fila, $cabecera, 'codigo_referencia');
$nivel = col($fila, $cabecera, 'nivel_descripcion');
if (empty($titulo)) {
$reporte['rechazadas']++;
$reporte['errores'][] = ['fila' => $num_fila, 'titulo' => '', 'motivo' => 'Falta el campo "titulo".'];
continue;
}
if (empty($codigo_ref)) {
$reporte['rechazadas']++;
$reporte['errores'][] = ['fila' => $num_fila, 'titulo' => $titulo, 'motivo' => 'Falta el campo "codigo_referencia".'];
continue;
}
if (empty($nivel)) {
$reporte['rechazadas']++;
$reporte['errores'][] = ['fila' => $num_fila, 'titulo' => $titulo, 'motivo' => 'Falta el campo "nivel_descripcion".'];
continue;
}
if (!in_array($nivel, $niveles_validos, true)) {
$reporte['rechazadas']++;
$reporte['errores'][] = ['fila' => $num_fila, 'titulo' => $titulo, 'motivo' => "Nivel \"$nivel\" no permitido para un hijo de \"$nivel_padre\"."];
continue;
}
$fechas = col($fila, $cabecera, 'fechas');
$volumen_soporte = col($fila, $cabecera, 'volumen_soporte');
$nombre_productor = col($fila, $cabecera, 'nombre_productor');
$historia_institucional = col($fila, $cabecera, 'historia_institucional');
$alcance_contenido = col($fila, $cabecera, 'alcance_contenido');
$valoracion_eliminacion = col($fila, $cabecera, 'valoracion_eliminacion');
$organizacion = col($fila, $cabecera, 'organizacion');
$condiciones_acceso = col($fila, $cabecera, 'condiciones_acceso');
$condiciones_reproduccion= col($fila, $cabecera, 'condiciones_reproduccion');
$lengua_escritura = col($fila, $cabecera, 'lengua_escritura');
$caracteristicas_fisicas = col($fila, $cabecera, 'caracteristicas_fisicas');
$unidades_relacionadas = col($fila, $cabecera, 'unidades_relacionadas');
$notas = col($fila, $cabecera, 'notas');
$fechas_descripciones = col($fila, $cabecera, 'fechas_descripciones');
$estado = col($fila, $cabecera, 'estado');
$nombre_descriptor = col($fila, $cabecera, 'nombre_descriptor');
$nota_archivero = col($fila, $cabecera, 'nota_archivero');
$fecha_creacion_revision = col($fila, $cabecera, 'fecha_creacion_revision');
$reglas_normas = col($fila, $cabecera, 'reglas_normas');
$pa_nombre = col($fila, $cabecera, 'pa_nombre');
$pa_geografico = col($fila, $cabecera, 'pa_geografico');
$pam_materia = col($fila, $cabecera, 'pam_materia');
$fecha_ingreso = col($fila, $cabecera, 'fecha_ingreso_registro');
if ($fecha_ingreso !== null &&
!preg_match('/^\d{4}-\d{2}-\d{2}$/', $fecha_ingreso)) {
$fecha_ingreso = null;
}
$anio_ini_raw = col($fila, $cabecera, 'fecha_inicial_filtro');
$anio_fin_raw = col($fila, $cabecera, 'fecha_final_filtro');
$fecha_inicial_filtro = ($anio_ini_raw !== null && is_numeric($anio_ini_raw)) ? (int) $anio_ini_raw : null;
$fecha_final_filtro = ($anio_fin_raw !== null && is_numeric($anio_fin_raw)) ? (int) $anio_fin_raw : null;
mysqli_stmt_bind_param(
$stmt_ins,
'issssssssssssssssssssssssssii',
$parent_id,
$codigo_ref,
$titulo,
$fechas,
$nivel,
$volumen_soporte,
$nombre_productor,
$historia_institucional,
$alcance_contenido,
$valoracion_eliminacion,
$organizacion,
$condiciones_acceso,
$condiciones_reproduccion,
$lengua_escritura,
$caracteristicas_fisicas,
$unidades_relacionadas,
$notas,
$fecha_ingreso,
$fechas_descripciones,
$estado,
$nombre_descriptor,
$nota_archivero,
$fecha_creacion_revision,
$reglas_normas,
$pa_nombre,
$pa_geografico,
$pam_materia,
$fecha_inicial_filtro,
$fecha_final_filtro
);
if (mysqli_stmt_execute($stmt_ins)) {
$reporte['insertadas']++;
} else {
$reporte['rechazadas']++;
$reporte['errores'][] = [
'fila' => $num_fila,
'titulo' => $titulo,
'motivo' => 'Error SQL: ' . mysqli_stmt_error($stmt_ins),
];
}
}
fclose($handle);
mysqli_stmt_close($stmt_ins);
mysqli_close($conexion);
$_SESSION['importar_reporte'] = $reporte;
header('Location: ' . $redir_base);
exit;
|