Después de aprender a trabajar con formularios, PDO y un CRUD completo, el siguiente paso natural en PHP es entender cómo mantener información de un usuario entre distintas páginas.
Para eso PHP ofrece dos mecanismos fundamentales:
- sesiones, mediante
$_SESSION; - cookies, almacenadas en el navegador del usuario.
En esta guía vamos a utilizarlas para construir la base de un sistema de login y logout con PHP y MySQL.
¿Qué problema resuelven las sesiones?
HTTP es un protocolo sin estado. Eso significa que, por defecto, cada petición que hacemos a una página web es independiente de la anterior.
Si un usuario inicia sesión en login.php y después entra a panel.php, necesitamos alguna forma de recordar que ese usuario ya fue autenticado.
Las sesiones permiten guardar información del usuario en el servidor y asociarla a sus siguientes peticiones.
Iniciar una sesión con session_start()
Antes de utilizar $_SESSION debemos iniciar la sesión:
<?php session_start(); ?>
En general, session_start() debe ejecutarse antes de enviar contenido HTML al navegador.
Guardar datos en $_SESSION
Podemos guardar valores como si se tratara de un array asociativo:
<?php session_start(); $_SESSION['usuario_id'] = 15; $_SESSION['usuario_nombre'] = 'Ana'; ?>
Estos valores estarán disponibles en otras páginas mientras la sesión continúe activa.
Leer datos de sesión
<?php session_start(); if (isset($_SESSION['usuario_id'])) { echo 'Usuario autenticado: ' . $_SESSION['usuario_nombre']; } ?>
Crear la tabla de usuarios
Para construir un login necesitamos almacenar los usuarios en la base de datos.
CREATE TABLE usuarios (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
activo BOOLEAN DEFAULT TRUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
La columna password tendrá suficiente espacio para almacenar el hash generado por PHP.
Nunca guardar contraseñas en texto plano
Una contraseña no debe almacenarse directamente en la base de datos.
PHP incluye password_hash(), que genera un hash seguro:
<?php $password = 'MiClaveSegura123'; $hash = password_hash($password, PASSWORD_DEFAULT); echo $hash; ?>
El resultado será diferente de la contraseña original y es lo que debemos guardar en la base.
Registrar un usuario con PDO
<?php $nombre = $_POST['nombre'] ?? ''; $email = $_POST['email'] ?? ''; $password = $_POST['password'] ?? ''; $hash = password_hash($password, PASSWORD_DEFAULT); $sql = 'INSERT INTO usuarios (nombre, email, password) VALUES (:nombre, :email, :password)'; $stmt = $pdo->prepare($sql); $stmt->execute([ 'nombre' => $nombre, 'email' => $email, 'password' => $hash ]); ?>
Formulario de login
<form method="POST" action="login.php"> <label>Email</label> <input type="email" name="email" required> <label>Contraseña</label> <input type="password" name="password" required> <button type="submit">Ingresar</button> </form>
Buscar al usuario por email
Cuando recibimos el formulario, buscamos al usuario mediante una consulta preparada:
<?php session_start(); $email = $_POST['email'] ?? ''; $password = $_POST['password'] ?? ''; $sql = 'SELECT id, nombre, email, password, activo FROM usuarios WHERE email = :email LIMIT 1'; $stmt = $pdo->prepare($sql); $stmt->execute([ 'email' => $email ]); $usuario = $stmt->fetch(PDO::FETCH_ASSOC); ?>
Validar la contraseña con password_verify()
No debemos comparar la contraseña ingresada con el hash utilizando ==.
PHP proporciona password_verify():
if ( $usuario && $usuario['activo'] && password_verify($password, $usuario['password']) ) { // Login correcto }
Crear la sesión después del login
Si los datos son correctos, guardamos solo la información necesaria en la sesión:
if ( $usuario && $usuario['activo'] && password_verify($password, $usuario['password']) ) { session_regenerate_id(true); $_SESSION['usuario_id'] = $usuario['id']; $_SESSION['usuario_nombre'] = $usuario['nombre']; header('Location: panel.php'); exit; }
session_regenerate_id(true) ayuda a reducir el riesgo de ataques de fijación de sesión después de autenticar al usuario.
Ejemplo completo de login.php
<?php session_start(); require 'conexion.php'; $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $email = trim($_POST['email'] ?? ''); $password = $_POST['password'] ?? ''; $sql = 'SELECT id, nombre, password, activo FROM usuarios WHERE email = :email LIMIT 1'; $stmt = $pdo->prepare($sql); $stmt->execute([ 'email' => $email ]); $usuario = $stmt->fetch(PDO::FETCH_ASSOC); if ( $usuario && $usuario['activo'] && password_verify($password, $usuario['password']) ) { session_regenerate_id(true); $_SESSION['usuario_id'] = $usuario['id']; $_SESSION['usuario_nombre'] = $usuario['nombre']; header('Location: panel.php'); exit; } $error = 'Email o contraseña incorrectos'; } ?>
Es mejor mostrar un mensaje genérico como “Email o contraseña incorrectos” en lugar de revelar si el email existe o no.
Proteger una página privada
En panel.php podemos verificar si existe la sesión:
<?php session_start(); if (!isset($_SESSION['usuario_id'])) { header('Location: login.php'); exit; } ?>
Después podemos mostrar información del usuario:
<h1>
Bienvenido,
<?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
</h1>
Crear logout.php
Para cerrar sesión:
<?php session_start(); $_SESSION = []; session_destroy(); header('Location: login.php'); exit; ?>
¿Qué es una cookie?
Una cookie es un pequeño valor almacenado por el navegador y enviado posteriormente al servidor.
Podemos crear una cookie con setcookie():
<?php setcookie( 'tema', 'oscuro', [ 'expires' => time() + 3600 * 24 * 30, 'path' => '/', 'httponly' => true, 'samesite' => 'Lax' ] ); ?>
Leer una cookie
<?php $tema = $_COOKIE['tema'] ?? 'claro'; echo $tema; ?>
Sesiones vs cookies
Aunque están relacionadas, no cumplen exactamente la misma función.
Sesiones
- los datos principales se mantienen en el servidor;
- son apropiadas para identificar a un usuario autenticado;
- normalmente el navegador conserva solo un identificador de sesión.
Cookies
- se almacenan en el navegador;
- pueden sobrevivir al cierre del navegador según su fecha de expiración;
- son útiles para preferencias y otras necesidades persistentes;
- el usuario puede modificarlas, por lo que nunca debemos confiar ciegamente en su contenido.
No guardar contraseñas en cookies
Nunca debemos hacer algo como:
setcookie('password', $password);
Las contraseñas no deben almacenarse en cookies, sesiones, archivos de texto ni registros de log en texto plano.
¿Y la opción “Recordarme”?
Una función de “Recordarme” no debería guardar directamente el identificador del usuario ni su contraseña como mecanismo de autenticación.
Una implementación seria utiliza un token aleatorio almacenado de forma segura en la base de datos y una cookie asociada a ese token.
Ese tema merece una implementación específica y es mejor abordarlo después de comprender bien sesiones, seguridad y autenticación.
Configurar cookies de sesión de forma más segura
En una aplicación servida mediante HTTPS podemos mejorar la configuración de la cookie de sesión:
<?php session_set_cookie_params([ 'httponly' => true, 'secure' => true, 'samesite' => 'Lax' ]); session_start(); ?>
secure debe utilizarse cuando el sitio trabaja mediante HTTPS.
Evitar guardar información innecesaria en la sesión
No necesitamos guardar el registro completo del usuario.
Normalmente alcanza con almacenar identificadores y algunos datos mínimos:
$_SESSION['usuario_id'] = $usuario['id']; $_SESSION['usuario_nombre'] = $usuario['nombre'];
Si necesitamos información actualizada, podemos consultar nuevamente la base utilizando el identificador.
Errores comunes
- olvidar ejecutar
session_start(); - enviar HTML antes de utilizar
header()osetcookie(); - guardar contraseñas en texto plano;
- comparar contraseñas sin
password_verify(); - guardar datos sensibles dentro de cookies;
- no regenerar el identificador de sesión después del login;
- no verificar la sesión en cada página privada;
- mostrar mensajes que permiten descubrir si una cuenta existe;
- confiar en valores provenientes de cookies como si fueran datos seguros.
Ejercicio práctico
Creá un pequeño sistema con estas páginas:
registro.php: crear un usuario utilizandopassword_hash();login.php: validar email y contraseña;panel.php: permitir el acceso solo a usuarios autenticados;logout.php: finalizar la sesión;- una cookie para recordar una preferencia como el tema claro u oscuro.
¿Qué sigue?
En la próxima guía podemos avanzar con autenticación y autorización en PHP: roles, permisos, protección de rutas y control de acceso para distintos tipos de usuarios.
¿Te sirvió esta guía? ☕
Si este contenido te ayudó y querés apoyar a Club Programador para seguir publicando ejercicios, proyectos y guías gratuitas, podés colaborar mediante:
Descubre más desde Club Programador
Suscríbete y recibe las últimas entradas en tu correo electrónico.