Registro de usuarios

En este artículo explicaremos cómo realizar el registro de usuarios en nuestro sistema de login aplicando buenas prácticas de seguridad. Aunque el registro de usuarios no forma parte implícita de un sistema de login, he considerado interesante hacer este inciso para comprender cómo están registrados los usuarios antes de obtener sus datos de acceso.

El proceso de registro implica almacenar las contraseñas de forma cifrada y asegurarnos de que no se produzcan duplicados ni vulnerabilidades. Para ello, aplicaremos el conjunto de buenas prácticas de validación y seguridad de datos descrito en el artículo anterior, y continuaremos utilizando nuestro archivo de conexión MySQL con mysqli en modo procedural y el lenguaje de servidor PHP.

Este artículo forma parte de la serie Sistema de login con PHP, donde se explica paso a paso cómo construir un sistema completo de login de usuarios usando PHP y MySQL.

La tabla usuarios

Lo primero que necesitamos es crear una tabla en nuestra base de datos MySQL para almacenar los datos de los usuarios. Una estructura típica podría ser:

CREATE TABLE usuarios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    nivel ENUM('user','admin') DEFAULT 'user',
    fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Con esta estructura MySQL podemos crear un registro de usuarios con los siguientes campos:

  • id: identificador único del usuario.
  • nombre y email: datos de contacto.
  • password: contraseña cifrada (nunca debe almacenarse en texto plano).
  • nivel: define los permisos del usuario en la web (user o admin).
  • fecha_registro: fecha automática de registro.

Para el almacenamiento seguro de las contraseñas utilizaremos funciones nativas de PHP muy seguras:

  • password_hash(): genera un hash seguro de la contraseña. Este hash es lo que se almacena en la base de datos, nunca la contraseña en texto plano.
  • password_verify(): compara una contraseña con su hash almacenado.

Registro de nuevos usuarios

Para añadir nuevos usuarios a nuestra base de datos MySQL, lo haremos mediante un formulario validado antes de insertar los datos, tal y como explicamos en los artículos anteriores. En este caso, es fundamental comprobar si el usuario ya existe antes de registrarlo, para evitar duplicados o sobrescribir información.

Para este ejemplo vamos a utilizar los mismos archivos conexion.php y validar-login.php, ya que nos sirven perfectamente. En tus propias aplicaciones, el formulario de registro de usuarios probablemente incluya más campos, por lo que podrías adaptarlo o crear uno específico como validar-registro.php.

Para proteger nuestro código y evitar inyecciones SQL al usar mysqli en modo procedural, debemos emplear consultas preparadas. El código completo de nuestro registro de usuarios sería el siguiente:

<?php
  include("conexion.php"); // Datos de conexión -> $conn
  include("validar-login.php"); // Datos validados del formulario -> $nombre, $email, $password

  // Comprobamos si el usuario ya existe
  $stmt = mysqli_prepare($conn, "SELECT id FROM usuarios WHERE email = ?");
  mysqli_stmt_bind_param($stmt, "s", $email);
  mysqli_stmt_execute($stmt);
  mysqli_stmt_store_result($stmt); // Necesario para usar mysqli_stmt_num_rows

  if (mysqli_stmt_num_rows($stmt) > 0) {
    echo "El usuario ya existe";
    mysqli_stmt_close($stmt);
  } else {
    mysqli_stmt_close($stmt);

    // Hasheamos la contraseña
    $hash = password_hash($password, PASSWORD_DEFAULT);

    // Insertamos el nuevo usuario
    $stmt = mysqli_prepare($conn, "INSERT INTO usuarios (nombre, email, password) VALUES (?, ?, ?)");
    mysqli_stmt_bind_param($stmt, "sss", $nombre, $email, $hash);

    if (mysqli_stmt_execute($stmt)) {
      echo "Usuario registrado correctamente";
    } else {
      echo "Error al registrar usuario.";
      // Registrar el error internamente, pero sin mostrarlo al usuario
      error_log("MySQL Error: " . mysqli_stmt_error($stmt));
    }

    mysqli_stmt_close($stmt);
  }

  // Cerramos la conexión
  mysqli_close($conn);
?>

Explicación del código

Inclusión de archivos:

include("conexion.php");
include("validar-login.php");

Se incluyen los archivos con la conexión a la base de datos y la validación del formulario, lo que garantiza que disponemos de una conexión activa ($conn) y de los datos sanitizados ($nombre, $email, $password).

Comprobación de usuario existente:

$stmt = mysqli_prepare($conn, "SELECT id FROM usuarios WHERE email = ?");
mysqli_stmt_bind_param($stmt, "s", $email);
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);

Aquí se prepara una consulta segura para comprobar si ya existe un usuario registrado con el mismo email. Para ello, los placeholders (?) se reemplazan (interna y automáticamente) con los valores reales de forma segura. mysqli_stmt_bind_param() vincula las variables con los placeholders, define que son tipo string (s) e impide inyecciones SQL, aunque un atacante introduzca caracteres maliciosos. mysqli_stmt_execute() ejecuta la consulta y mysqli_stmt_store_result() permite contar las filas devueltas sin tener que recorrerlas.

NOTA: mysqli_stmt_store_result($stmt); es más rápido que mysqli_stmt_get_result($stmt); si sólo queremos saber el número de filas obtenidas en vez de obtener todos los datos.

Condicional: usuario ya existente

if (mysqli_stmt_num_rows($stmt) > 0) {
  echo "El usuario ya existe";
  mysqli_stmt_close($stmt);
}

Si el correo ya está registrado, se muestra un mensaje y se cierra la sentencia, evitando duplicar usuarios en el registro de la base de datos.

Inserción del nuevo usuario:

$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = mysqli_prepare($conn, "INSERT INTO usuarios (nombre, email, password) VALUES (?, ?, ?)");
mysqli_stmt_bind_param($stmt, "sss", $nombre, $email, $hash);

Antes de guardar la contraseña, se cifra con password_hash(). Esto asegura que, incluso si la base de datos se ve comprometida, las contraseñas no podrán leerse. Luego se prepara la consulta para insertar los datos de forma segura, tal y como hemos hecho al comprobar el email.

Ejecución y manejo del resultado:

if (mysqli_stmt_execute($stmt)) {
  echo "Usuario registrado correctamente";
} else {
  echo "Error al registrar usuario.";
  error_log("MySQL Error: " . mysqli_stmt_error($stmt));
}

Si la inserción tiene éxito, se muestra un mensaje al usuario. Si ocurre un error, se muestra un mensaje genérico y se guarda el error real en el log del servidor mediante error_log(), sin revelar información sensible.

Limpieza final:

mysqli_stmt_close($stmt);
mysqli_close($conn);

Finalmente, se cierran las sentencias y la conexión con la base de datos, liberando los recursos abiertos.

Registro de usuarios

Con este artículo hemos completado una parte esencial del sistema de login: el registro de nuevos usuarios. Hemos aprendido cómo crear la tabla de usuarios en MySQL, cómo validar y sanitizar los datos recibidos desde el formulario, y cómo insertar los registros en la base de datos de forma segura mediante consultas preparadas. Todo ello aplicando buenas prácticas de seguridad modernas en PHP, como el uso de password_hash() para el cifrado de contraseñas y el manejo de errores sin exponer información sensible.

Además, hemos visto cómo evitar vulnerabilidades comunes como el SQL Injection, asegurándonos de que cada inserción en nuestro registro de usuarios sea fiable y de que no existan duplicados en la base de datos. Gracias a las consultas preparadas y a la validación previa de los datos, nuestro sistema se vuelve más robusto y menos propenso a ataques o fallos lógicos.

A partir de esta base sólida, ya podemos avanzar al siguiente paso: la validación del login y la creación de sesiones de usuario. Con ello, nuestro sistema pasará de registrar y proteger datos a autenticar usuarios de forma segura y mantener su sesión activa, completando así el ciclo básico de un sistema de autenticación profesional en PHP y MySQL.

¡ Espero que este artículo sea de vuestro interés !

Deja un comentario