23. Hoy vamos a continuar con el tema de Lectura de Datos con PDO, Parte 2.

  tutorial número 23. Hoy vamos a continuar con el tema de Lectura de Datos con PDO, Parte 2.

Vamos a tomar todo el código de las imágenes y el texto que me has proporcionado para construir un sistema de login funcional, paso a paso. Explicaremos cada error y cada corrección en el camino, porque de los errores se aprende mucho.

Objetivo del Tutorial: Conectar el formulario de ingreso con la base de datos para verificar si el usuario y la contraseña existen y coinciden. Si coinciden, que nos lleve a una página de "usuarios". Si no, que nos muestre un mensaje de "fallo".


Paso 1: Preparar el Formulario de Ingreso (ingresar.php)

Lo primero es tener nuestro formulario HTML. Es importante que los name de los campos coincidan exactamente con lo que vamos a buscar en PHP.

php
<!-- ingresar.php -->
<h1>INGRESAR</h1>

<form method="post">
    <input type="text" placeholder="Usuario" name="usuarioIngreso" required>
    <input type="password" placeholder="Contraseña" name="passwordIngreso" required>
    <input type="submit" value="Enviar">
</form>

<?php
// Aquí llamaremos al controlador más adelante
$ingreso = new MvcController();
$ingreso -> ingresosUsuarioController();
?>

<?php
// Este código mostrará un mensaje si el login falla
if (isset($_GET["action"])) {
    if ($_GET["action"] == "fallo") {
        echo "Fallo al ingresar";
    }
}
?>

Explicación para el alumno:

  • Creamos un formulario simple que envía los datos por método POST.

  • Los nombres de los campos (usuarioIngresopasswordIngreso) son los que usaremos en el controlador para capturar los datos.

  • Al final, veremos un código PHP que muestra un mensaje si en la URL aparece ?action=fallo.


Paso 2: El Modelo - La Consulta a la Base de Datos (modelo.php)

El modelo es el encargado de hablar con la base de datos. Aquí usaremos PDO para preparar una consulta SELECT que busque un usuario específico.

php
<?php
// modelo.php
require_once "conexion.php";

class Datos extends Conexion{

    // MODELO PARA EL INGRESO DE USUARIOS
    public function ingresosUsuarioModel($datosModel, $tabla){

        // 1. Preparar la sentencia SQL
        // Seleccionamos usuario y password de la tabla que coincidan con el :usuario
        $stmt = Conexion::conectar()->prepare("SELECT usuario, password FROM $tabla WHERE usuario = :usuario");

        // 2. Enlazar los parámetros
        // Vinculamos el marcador :usuario con el valor real que viene del formulario
        $stmt->bindParam(":usuario", $datosModel["usuario"], PDO::PARAM_STR);

        // 3. Ejecutar la consulta
        $stmt->execute();

        // 4. Devolver el resultado
        // fetch(): Obtiene una sola fila del resultado. La devuelve como un arreglo.
        return $stmt->fetch();
    }
}
?>

Explicación para el alumno:

  • prepare(): Preparamos la consulta SQL. Usamos SELECT para leer datos, a diferencia del INSERT que usábamos para registrar.

  • :usuario: Es un parámetro de sustitución (un marcador). Evita que los usuarios malintencionados puedan inyectar código SQL.

  • bindParam(): Enlaza el marcador :usuario con el valor real que el usuario escribió en el input usuarioIngreso. Es como decir: "Donde dice :usuario, pon el valor que viene en $datosModel["usuario"]".

  • execute(): Ejecuta la consulta ya armada.

  • fetch(): Este método es muy importante. Trae UNA SOLA FILA de la base de datos como un arreglo. Si el usuario existe, nos devolverá sus datos. Si no existe, devolverá false.


Paso 3: El Controlador - La Lógica de Negocio (controlador.php)

El controlador recibe los datos del formulario, se los pasa al modelo y, con la respuesta, decide qué hacer.

3.1 Primera versión del controlador (para ver qué nos devuelve el modelo)

Primero, vamos a hacer una prueba simple para ver qué datos nos está devolviendo el modelo. Esto nos ayudará a entender el error que vimos en la explicación.

php
<?php
// controlador.php
require_once "modelo.php";

class MvcController{

    // CONTROLADOR PARA EL INGRESO DE USUARIOS
    public function ingresosUsuarioController(){

        // Preguntamos si los datos del formulario están llegando
        if(isset($_POST["usuarioIngreso"])){

            // Organizamos los datos del formulario en un arreglo
            $datosController = array(
                "usuario" => $_POST["usuarioIngreso"],
                "password" => $_POST["passwordIngreso"]
            );

            // Llamamos al modelo y le enviamos los datos
            $respuesta = Datos::ingresosUsuarioModel($datosController, "usuarios");

            // Mostramos lo que el modelo nos devolvió
            var_dump($respuesta);
        }
    }
}
?>

Prueba y Error Común:

  1. Abre tu navegador, ve a ingresar.php y escribe un usuario existente (ej: "pepe") y su contraseña.

  2. Haz clic en "Enviar".

  3. Resultado esperado: Un var_dump() del arreglo que devuelve la base de datos.

    • array(4) { ["usuario"]=> string(4) "pepe" [0]=> string(4) "pepe" ["password"]=> string(4) "1234" [1]=> string(4) "1234" }

    • ¡Perfecto! El fetch() nos devuelve un arreglo con los datos, accesibles tanto por el nombre de la columna ($respuesta["usuario"]) como por su índice numérico ($respuesta[0]).

  4. Prueba con un usuario que NO existe:

    • Escribe un usuario falso, ej: "juanito".

    • El var_dump() mostrará bool(false). El modelo no encontró nada.


Paso 4: Versión Final del Controlador con la Validación

Ahora que sabemos que la respuesta del modelo puede ser un array (si el usuario existe) o false (si no existe), podemos crear la lógica final.

php
<?php
// controlador.php
require_once "modelo.php";

class MvcController{

    // CONTROLADOR PARA EL INGRESO DE USUARIOS (VERSIÓN FINAL)
    public function ingresosUsuarioController(){

        if(isset($_POST["usuarioIngreso"])){

            $datosController = array(
                "usuario" => $_POST["usuarioIngreso"],
                "password" => $_POST["passwordIngreso"]
            );

            $respuesta = Datos::ingresosUsuarioModel($datosController, "usuarios");

            // --- LÓGICA DE VALIDACIÓN ---
            // Preguntamos: ¿La respuesta es un arreglo? (es decir, ¿encontró al usuario?)
            // Y luego, ¿el usuario de la BD es igual al del POST?
            // ¿Y la contraseña de la BD es igual a la del POST?
            if(is_array($respuesta) &&
                $respuesta["usuario"] == $_POST["usuarioIngreso"] &&
                $respuesta["password"] == $_POST["passwordIngreso"]){

                // SI TODO COINCIDE: Redirigimos a la página de usuarios
                header("location:index.php?action=usuarios");

            }else{
                // SI ALGO FALLA: Redirigimos al login con un mensaje de error
                header("location:index.php?action=fallo");
            }
            // ----------------------------
        }
    }
}
?>

Explicación de la validación:

  1. is_array($respuesta): Primero nos aseguramos de que el modelo nos haya devuelto un usuario. Si es false, esta condición falla de inmediato.

  2. $respuesta["usuario"] == $_POST["usuarioIngreso"]: Comparamos el nombre de usuario que trajo la BD contra el que el usuario escribió en el formulario. Aunque la BD ya nos devolvió el usuario que coincidía con :usuario, esta doble verificación es una buena práctica de seguridad.

  3. $respuesta["password"] == $_POST["passwordIngreso"]: Comparamos la contraseña. NOTA IMPORTANTE: En un proyecto real, las contraseñas NUNCA se guardan en texto plano como "1234". Se guardan encriptadas con funciones como password_hash(). La comparación se haría con password_verify(). Pero para este ejemplo didáctico, las comparamos directamente.

  4. header("location:..."): Esta función de PHP redirige al usuario a otra página. Es crucial usarla antes de que haya cualquier salida de HTML en la página.


Paso 5: Ajuste Final en el Archivo de Enlaces (enlaces.php)

Para que la redirección funcione, necesitamos que nuestro sistema de "enlaces" (o controlador de vistas) reconozca la nueva acción fallo y muestre la vista correcta.

Asumiendo que tienes un archivo enlaces.php que carga las páginas según $_GET["action"], debes asegurarte de incluir el caso para "fallo".

php
<?php
// enlaces.php (fragmento)

$pagina = $_GET["action"] ?? "ingresar"; // Si no hay action, va a ingresar

switch ($pagina) {
    case 'usuarios':
        include 'vistas/usuarios.php'; // La página a donde va si el login es exitoso
        break;
    case 'fallo':
        include 'vistas/ingresar.php'; // Volvemos a la página de login
        break;
    case 'registro':
        include 'vistas/registro.php';
        break;
    // ... otros casos
    default:
        include 'vistas/ingresar.php';
}
?>

Explicación:

  • Cuando el login es exitoso, el header nos manda a index.php?action=usuarios. El enlaces.php carga la página de usuarios.

  • Cuando el login falla, el header nos manda a index.php?action=fallo. El enlaces.php vuelve a cargar ingresar.php. Y como en ingresar.php tenemos el código que mira si $_GET["action"] == "fallo", mostrará el mensaje "Fallo al ingresar".


Resumen y Conceptos Clave

  1. PDO y SELECT: Para leer datos de la BD usamos SELECT con prepare()bindParam() y execute().

  2. fetch(): Método de PDO que devuelve una sola fila de resultados como un arreglo. Si no hay resultados, devuelve false.

  3. Flujo del Login:

    • Vista (Formulario): Captura los datos del usuario.

    • Controlador: Recibe los datos, los envía al Modelo y toma decisiones.

    • Modelo: Ejecuta la consulta SQL y devuelve el resultado.

  4. Errores como Maestros: Aprendimos a interpretar un var_dump() para entender la estructura de los datos que devuelve la BD y a usar is_array() para validar si un usuario existe.

¡Y así es como hemos creado un sistema de login funcional leyendo datos con PDO! En el próximo tutorial, veremos cómo mejorar la seguridad manejando sesiones y encriptando contraseñas.

Comentarios

Entradas más populares de este blog

token

¿Qué es un token y cómo se utiliza en una API?

Generación de Credenciales API