📋 Formularios, sesiones y cookies

Métodos GET y POST

PHP recoge datos de formularios mediante los arrays superglobales $_GET y $_POST:

Formulario con GET

<!-- formulario.html -->
<form action="procesar.php" method="GET">
    <label>Nombre: <input type="text" name="nombre"></label>
    <label>Edad: <input type="number" name="edad"></label>
    <button type="submit">Enviar</button>
</form>

<!-- procesar.php -->
<?php
$nombre = $_GET["nombre"] ?? "Sin nombre";
$edad = $_GET["edad"] ?? 0;

echo "Hola, $nombre. Tienes $edad años.";

// URL generada: procesar.php?nombre=Ana&edad=25
?>

Formulario con POST

<form action="procesar.php" method="POST">
    <label>Usuario: <input type="text" name="usuario"></label>
    <label>Contraseña: <input type="password" name="password"></label>
    <button type="submit">Iniciar sesión</button>
</form>

<?php
// procesar.php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $usuario = $_POST["usuario"] ?? "";
    $password = $_POST["password"] ?? "";
    // Procesar...
}
?>

$_REQUEST y $_SERVER

<?php
// $_REQUEST combina GET, POST y COOKIE (orden según variables_order en php.ini)
$nombre = $_REQUEST["nombre"] ?? "Invitado";

// $_SERVER contiene información del servidor y la petición
echo $_SERVER["REQUEST_METHOD"];     // GET / POST
echo $_SERVER["REMOTE_ADDR"];        // IP del cliente
echo $_SERVER["HTTP_USER_AGENT"];    // Navegador del cliente
echo $_SERVER["PHP_SELF"];           // Script actual
?>

Validación de formularios

<?php
$errores = [];
$nombre = $email = $edad = "";

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // Validar nombre (requerido, mínimo 2 caracteres)
    $nombre = trim($_POST["nombre"] ?? "");
    if (empty($nombre)) {
        $errores[] = "El nombre es obligatorio";
    } elseif (strlen($nombre) < 2) {
        $errores[] = "El nombre debe tener al menos 2 caracteres";
    }

    // Validar email
    $email = trim($_POST["email"] ?? "");
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errores[] = "Email no válido";
    }

    // Validar edad (número entre 1 y 120)
    $edad = $_POST["edad"] ?? 0;
    if (!filter_var($edad, FILTER_VALIDATE_INT, ["options" => ["min_range" => 1, "max_range" => 120]])) {
        $errores[] = "Edad no válida (1-120)";
    }

    if (empty($errores)) {
        echo "Formulario válido. Bienvenido, $nombre!";
    }
}
?>

<!-- Formulario con feedback de errores -->
<?php if (!empty($errores)): ?>
    <ul style="color:red">
    <?php foreach ($errores as $error): ?>
        <li><?= htmlspecialchars($error) ?></li>
    <?php endforeach; ?>
    </ul>
<?php endif; ?>

<form method="POST">
    <label>Nombre: <input type="text" name="nombre" value="<?= htmlspecialchars($nombre) ?>"></label><br>
    <label>Email: <input type="email" name="email" value="<?= htmlspecialchars($email) ?>"></label><br>
    <label>Edad: <input type="number" name="edad" value="<?= htmlspecialchars($edad) ?>"></label><br>
    <button type="submit">Enviar</button>
</form>

Sanitización de datos

<?php
// Limpiar y filtrar entradas
$email = filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL);
$url = filter_input(INPUT_GET, "url", FILTER_SANITIZE_URL);
$numero = filter_input(INPUT_POST, "cantidad", FILTER_SANITIZE_NUMBER_INT);
$texto = filter_input(INPUT_POST, "comentario", FILTER_SANITIZE_STRING);

// Sanitizar para HTML (¡imprescindible antes de mostrar!)
$usuario_input = "<script>alert('hack')</script>";
$seguro = htmlspecialchars($usuario_input, ENT_QUOTES, "UTF-8");
echo $seguro; // &lt;script&gt;... (no se ejecuta)

// Eliminar etiquetas HTML
$limpio = strip_tags($usuario_input, "<b><i>"); // Solo permite <b> e <i>
?>

Protección contra XSS (Cross-Site Scripting)

<?php
// NUNCA confíes en datos del usuario
// MAL: echo "Hola, " . $_GET["nombre"];
// BIEN:
echo "Hola, " . htmlspecialchars($_GET["nombre"] ?? "", ENT_QUOTES, "UTF-8");

// Para JSON
$datos = json_encode(["nombre" => $nombre], JSON_HEX_TAG | JSON_HEX_AMP);

// Política de seguridad CSP en cabeceras
header("Content-Security-Policy: default-src 'self'; script-src 'self'");
?>

$_SESSION — Sesiones

Las sesiones guardan datos del usuario en el servidor, identificados por una cookie con el ID de sesión:

<?php
// Iniciar sesión (al principio del script, antes de cualquier salida HTML)
session_start();

// Guardar datos en la sesión
$_SESSION["usuario"] = "Ana";
$_SESSION["rol"] = "admin";
$_SESSION["ultimo_acceso"] = time();

// Leer datos de la sesión
if (isset($_SESSION["usuario"])) {
    echo "Bienvenido de nuevo, " . $_SESSION["usuario"];
}

// Eliminar un dato concreto
unset($_SESSION["rol"]);

// Destruir toda la sesión
session_destroy();
?>

Ejemplo: carrito de la compra

<?php
session_start();

// Inicializar carrito
if (!isset($_SESSION["carrito"])) {
    $_SESSION["carrito"] = [];
}

// Añadir producto
function agregar_al_carrito(int $id, string $nombre, float $precio, int $cantidad = 1): void {
    if (isset($_SESSION["carrito"][$id])) {
        $_SESSION["carrito"][$id]["cantidad"] += $cantidad;
    } else {
        $_SESSION["carrito"][$id] = [
            "nombre" => $nombre,
            "precio" => $precio,
            "cantidad" => $cantidad
        ];
    }
}

// Eliminar producto
function quitar_del_carrito(int $id): void {
    unset($_SESSION["carrito"][$id]);
}

// Total carrito
function total_carrito(): float {
    $total = 0;
    foreach ($_SESSION["carrito"] as $item) {
        $total += $item["precio"] * $item["cantidad"];
    }
    return $total;
}

// Añadir ejemplo
agregar_al_carrito(1, "Camiseta", 19.99, 2);
agregar_al_carrito(2, "Pantalón", 39.99);
echo "Total: " . total_carrito() . "€";
?>

Cookies

Las cookies guardan datos en el navegador del cliente:

<?php
// Crear una cookie: setcookie(nombre, valor, expiración, ruta)
setcookie("idioma", "es", time() + 3600 * 24 * 30, "/"); // 30 días

// Cookie que expira al cerrar el navegador (sin expiración)
setcookie("temporal", "valor");

// Leer cookies
$idioma = $_COOKIE["idioma"] ?? "es";

// Eliminar una cookie (poner expiración en el pasado)
setcookie("temporal", "", time() - 3600, "/");

// Array de cookies
setcookie("preferencias[color]", "oscuro", time() + 86400);
setcookie("preferencias[fuente]", "grande", time() + 86400);
if (isset($_COOKIE["preferencias"])) {
    echo "Color: " . $_COOKIE["preferencias"]["color"];
}
?>

Login básico con sesiones

<?php
session_start();

// Simular base de datos de usuarios
$usuarios = [
    "ana" => password_hash("1234", PASSWORD_DEFAULT),
    "luis" => password_hash("secreto", PASSWORD_DEFAULT),
];

// Login
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["login"])) {
    $usuario = trim($_POST["usuario"] ?? "");
    $password = $_POST["password"] ?? "";

    if (isset($usuarios[$usuario]) && password_verify($password, $usuarios[$usuario])) {
        $_SESSION["usuario"] = $usuario;
        $_SESSION["logged_in"] = true;
        header("Location: panel.php");
        exit;
    } else {
        $error = "Usuario o contraseña incorrectos";
    }
}

// Logout
if (isset($_GET["logout"])) {
    session_destroy();
    header("Location: login.php");
    exit;
}

// Verificar si está logueado (protección de rutas)
function requiere_login(): void {
    if (empty($_SESSION["logged_in"])) {
        header("Location: login.php");
        exit;
    }
}
?>

<!-- login.php -->
<form method="POST">
    <label>Usuario: <input type="text" name="usuario" required></label><br>
    <label>Contraseña: <input type="password" name="password" required></label><br>
    <button type="submit" name="login">Entrar</button>
    <?php if (isset($error)): ?>
        <p style="color:red"><?= htmlspecialchars($error) ?></p>
    <?php endif; ?>
</form>

<!-- panel.php (protegido) -->
<?php
session_start();
requiere_login();
?>
<h1>Panel de control</h1>
<p>Bienvenido, <?= htmlspecialchars($_SESSION["usuario"]) ?></p>
<a href="?logout=1">Cerrar sesión</a>

$_FILES — Subida de archivos

<!-- formulario con enctype multipart/form-data -->
<form action="subir.php" method="POST" enctype="multipart/form-data">
    <input type="file" name="documento" accept=".pdf,.doc">
    <button type="submit">Subir</button>
</form>

<?php
// subir.php
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_FILES["documento"])) {
    $archivo = $_FILES["documento"];

    // Comprobar errores
    if ($archivo["error"] !== UPLOAD_ERR_OK) {
        die("Error al subir el archivo");
    }

    // Validar tipo (seguridad)
    $tipos_permitidos = ["application/pdf", "application/msword"];
    if (!in_array($archivo["type"], $tipos_permitidos)) {
        die("Tipo de archivo no permitido");
    }

    // Validar tamaño (máximo 5MB)
    if ($archivo["size"] > 5 * 1024 * 1024) {
        die("Archivo demasiado grande (máx 5MB)");
    }

    // Mover a ubicación definitiva
    $nombre_seguro = uniqid() . "_" . basename($archivo["name"]);
    $ruta_destino = __DIR__ . "/uploads/" . $nombre_seguro;

    if (move_uploaded_file($archivo["tmp_name"], $ruta_destino)) {
        echo "Archivo subido correctamente: $nombre_seguro";
    } else {
        echo "Error al mover el archivo";
    }
}
?>

Token CSRF

Protección contra Cross-Site Request Forgery:

<?php
session_start();

// Generar token
if (empty($_SESSION["csrf_token"])) {
    $_SESSION["csrf_token"] = bin2hex(random_bytes(32));
}

$token = $_SESSION["csrf_token"];
?>

<form method="POST">
    <input type="hidden" name="csrf_token" value="<?= $token ?>">
    <button type="submit" name="accion" value="eliminar_cuenta">Eliminar cuenta</button>
</form>

<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // Validar token CSRF
    $csrf = $_POST["csrf_token"] ?? "";
    if (!hash_equals($_SESSION["csrf_token"], $csrf)) {
        die("Token CSRF inválido");
    }
    // Procesar acción...
}
?>

Resumen de superglobales

SuperglobalContenidoRiesgo de seguridad
$_GETParámetros de la URLXSS, inyección
$_POSTDatos del cuerpo HTTPXSS, inyección
$_SESSIONDatos de sesión (servidor)Secuestro de sesión
$_COOKIECookies del navegadorManipulación, XSS
$_FILESArchivos subidosSubida maliciosa
$_SERVERCabeceras y entornoBajo

Ejercicios

  1. Crea un formulario de registro con nombre, email, contraseña y confirma contraseña. Valida todos los campos y muestra errores si los hay.
  2. Implementa un contador de visitas por sesión que muestre "Has visitado esta página N veces".
  3. Crea un sistema de login básico con 2 usuarios hardcodeados y contraseñas hasheadas.
  4. Añade una cookie de "última visita" que muestre al usuario cuándo entró por última vez.
  5. Protege el formulario de login con un token CSRF.

← Volver al curso