Programación Web • ITI-07 •
Práctica: Mini Sistema Web Universitario - 3
Práctica: Mini Sistema Web Universitario - 3
Cierre de sesión y subida de archivos
logout.php
<?html
/**
* logout.php - Cierre de sesión seguro
* Destruye la sesión y redirige al login
*/
session_start();
// Limpiar todas las variables de sesión
$_SESSION = [];
// Destruir la cookie de sesión si existe
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), "", time() - 3600, "/");
}
// Destruir la sesión
session_destroy();
// Redirigir al login con mensaje
header("Location: index.php");
exit();
?>
upload.php
<?php
/**
* upload.php - Procesamiento de subida de archivos
* Implementa validaciones de seguridad y manejo de archivos
*/
session_start();
// SEGURIDAD: Verificar autenticación
if (!isset($_SESSION["usuario_id"])) {
header("Location: index.php");
exit();
}
// SEGURIDAD: Solo aceptar peticiones POST
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
header("Location: dashboard.php");
exit();
}
require_once "config/conexion.php";
// Configuración de subida
$directorio_destino = "uploads/";
$tamano_maximo = 5 * 1024 * 1024; // 5 MB en bytes
$extensiones_permitidas = ["pdf"];
// Crear directorio si no existe
if (!file_exists($directorio_destino)) {
mkdir($directorio_destino, 0755, true);
}
// Función para sanitizar nombres de archivo
function sanitizarNombreArchivo($nombre)
{
// Eliminar caracteres especiales y espacios
$nombre = preg_replace("/[^a-zA-Z0-9._-]/", "_", $nombre);
$nombre = preg_replace("/\.+/", ".", $nombre);
return $nombre;
}
// Función para generar nombre único de archivo
function generarNombreUnico($extension)
{
return uniqid("tarea_", true) . "_" . time() . "." . $extension;
}
// Validar que se haya enviado un archivo
if (
!isset($_FILES["archivo"]) ||
$_FILES["archivo"]["error"] === UPLOAD_ERR_NO_FILE
) {
header(
"Location: dashboard.php?error=" .
urlencode("No se seleccionó ningún archivo"),
);
exit();
}
$archivo = $_FILES["archivo"];
// VALIDACIÓN 1: Verificar errores de subida
if ($archivo["error"] !== UPLOAD_ERR_OK) {
$errores = [
UPLOAD_ERR_INI_SIZE => "El archivo supera el tamaño máximo permitido por el servidor",
UPLOAD_ERR_FORM_SIZE => "El archivo supera el tamaño máximo permitido",
UPLOAD_ERR_PARTIAL => "El archivo se subió parcialmente",
UPLOAD_ERR_NO_TMP_DIR => "Falta la carpeta temporal",
UPLOAD_ERR_CANT_WRITE => "Error al escribir el archivo en el disco",
UPLOAD_ERR_EXTENSION => "Una extensión de PHP detuvo la subida",
];
$mensaje_error =
$errores[$archivo["error"]] ?? "Error desconocido al subir el archivo";
header("Location: dashboard.php?error=" . urlencode($mensaje_error));
exit();
}
// VALIDACIÓN 2: Verificar tamaño del archivo
if ($archivo["size"] > $tamano_maximo) {
$tamano_mb = round($tamano_maximo / (1024 * 1024), 2);
header(
"Location: dashboard.php?error=" .
urlencode("El archivo supera el tamaño máximo de {$tamano_mb} MB"),
);
exit();
}
// VALIDACIÓN 3: Verificar extensión del archivo
$nombre_original = $archivo["name"];
$extension = strtolower(pathinfo($nombre_original, PATHINFO_EXTENSION));
if (!in_array($extension, $extensiones_permitidas)) {
header(
"Location: dashboard.php?error=" .
urlencode("Solo se permiten archivos PDF"),
);
exit();
}
// VALIDACIÓN 4: Verificar tipo MIME real del archivo
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $archivo["tmp_name"]);
finfo_close($finfo);
$mimes_permitidos = ["application/pdf"];
if (!in_array($mime_type, $mimes_permitidos)) {
header(
"Location: dashboard.php?error=" .
urlencode("El archivo no es un PDF válido"),
);
exit();
}
// VALIDACIÓN 5: Verificar que el archivo no esté vacío
if ($archivo["size"] === 0) {
header(
"Location: dashboard.php?error=" . urlencode("El archivo está vacío"),
);
exit();
}
// Generar nombre único y sanitizado para el archivo
$nombre_archivo_unico = generarNombreUnico($extension);
$ruta_completa = $directorio_destino . $nombre_archivo_unico;
// Intentar mover el archivo al directorio de destino
if (move_uploaded_file($archivo["tmp_name"], $ruta_completa)) {
// Guardar información en la base de datos
$usuario_id = $_SESSION["usuario_id"];
$nombre_original_sanitizado = sanitizarNombreArchivo($nombre_original);
$tamano_bytes = $archivo["size"];
// Usar prepared statement para prevenir SQL Injection
$stmt = $conexion->prepare(
"INSERT INTO tareas (usuario_id, nombre_archivo, nombre_original, tamano_bytes) VALUES (?, ?, ?, ?)",
);
$stmt->bind_param(
"issi",
$usuario_id,
$nombre_archivo_unico,
$nombre_original_sanitizado,
$tamano_bytes,
);
if ($stmt->execute()) {
// Éxito total
$stmt->close();
header(
"Location: dashboard.php?mensaje=" .
urlencode("Tarea subida correctamente"),
);
exit();
} else {
// Error al guardar en base de datos - eliminar archivo
$stmt->close();
unlink($ruta_completa);
header(
"Location: dashboard.php?error=" .
urlencode("Error al registrar la tarea en la base de datos"),
);
exit();
}
} else {
// Error al mover el archivo
header(
"Location: dashboard.php?error=" .
urlencode("Error al guardar el archivo en el servidor"),
);
exit();
}
// Cerrar conexión
cerrarConexion();
?>