INSERT, UPDATE y DELETE con PHP y PDO: guardar, editar y eliminar datos


En la guía anterior conectamos PHP con MySQL utilizando PDO y aprendimos a leer datos con SELECT.

Ahora vamos a avanzar con las operaciones que permiten crear, modificar y eliminar registros. Es decir, vamos a empezar a trabajar con la parte operativa de una aplicación real.

¿Querés profundizar en la parte SQL?

En esta guía vamos a utilizar INSERT, UPDATE, DELETE y WHERE. La teoría completa de estas sentencias está desarrollada en nuestra ruta de aprendizaje SQL / MySQL.

Las tres operaciones que veremos

  • INSERT: crear registros nuevos;
  • UPDATE: modificar registros existentes;
  • DELETE: eliminar registros.

Las tres operaciones se realizarán con consultas preparadas mediante PDO.

Tabla de ejemplo

Seguimos trabajando con la tabla usuarios:

usuarios
-------------------------
id
nombre
email
edad

Insertar un usuario

La consulta SQL básica sería:

INSERT INTO usuarios (nombre, email, edad)
VALUES ('Ana', 'ana@email.com', 25);

Pero desde PHP no debemos concatenar directamente valores recibidos del usuario.

Utilizamos placeholders:

$sql =
    'INSERT INTO usuarios
        (nombre, email, edad)
     VALUES
        (:nombre, :email, :edad)';

$stmt = $pdo->prepare($sql);

Ejecutar el INSERT

$stmt->execute([
    'nombre' => $nombre,
    'email' => $email,
    'edad' => $edad
]);

Formulario de alta

<form method="post">

    <label for="nombre">Nombre:</label>
    <input
        type="text"
        id="nombre"
        name="nombre"
    >

    <br><br>

    <label for="email">Email:</label>
    <input
        type="email"
        id="email"
        name="email"
    >

    <br><br>

    <label for="edad">Edad:</label>
    <input
        type="number"
        id="edad"
        name="edad"
    >

    <br><br>

    <button type="submit">
        Guardar
    </button>

</form>

Procesar el formulario

<?php

require 'conexion.php';

$errores = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $nombre = trim($_POST['nombre'] ?? '');
    $email = trim($_POST['email'] ?? '');
    $edad = trim($_POST['edad'] ?? '');

    if ($nombre === '') {
        $errores[] = 'El nombre es obligatorio';
    }

    if (!filter_var(
        $email,
        FILTER_VALIDATE_EMAIL
    )) {
        $errores[] = 'El email no es válido';
    }

    if ($edad === '' || !is_numeric($edad)) {
        $errores[] = 'La edad no es válida';
    }

    if (empty($errores)) {

        $sql =
            'INSERT INTO usuarios
                (nombre, email, edad)
             VALUES
                (:nombre, :email, :edad)';

        $stmt = $pdo->prepare($sql);

        $stmt->execute([
            'nombre' => $nombre,
            'email' => $email,
            'edad' => $edad
        ]);

        echo 'Usuario guardado correctamente';
    }
}

Recuperar el ID insertado

Si la tabla utiliza una clave autoincremental, PDO puede devolver el último ID generado:

$id = $pdo->lastInsertId();

echo 'Nuevo usuario: ' . $id;

Esto puede ser útil si después queremos redirigir al detalle del registro recién creado.

Modificar un registro con UPDATE

Supongamos que queremos cambiar nombre y email de un usuario.

$sql =
    'UPDATE usuarios
     SET nombre = :nombre,
         email = :email,
         edad = :edad
     WHERE id = :id';

$stmt = $pdo->prepare($sql);

$stmt->execute([
    'nombre' => $nombre,
    'email' => $email,
    'edad' => $edad,
    'id' => $id
]);

¿Querés profundizar en la parte SQL?

En esta guía vamos a utilizar INSERT, UPDATE, DELETE y WHERE. La teoría completa de estas sentencias está desarrollada en nuestra ruta de aprendizaje SQL / MySQL.

¿Por qué WHERE es fundamental en UPDATE?

La cláusula WHERE indica qué registro debe modificarse.

Una consulta como:

UPDATE usuarios
SET nombre = 'Ana';

podría modificar todos los registros de la tabla.

Por eso, antes de ejecutar un UPDATE, debemos revisar con especial cuidado la condición utilizada.

Editar un usuario: primer paso

Normalmente recibimos el ID mediante GET:

editar.php?id=5

Lo validamos:

$id = filter_input(
    INPUT_GET,
    'id',
    FILTER_VALIDATE_INT
);

if ($id === false || $id === null) {
    exit('ID no válido');
}

Buscar el usuario antes de editar

$sql =
    'SELECT id, nombre, email, edad
     FROM usuarios
     WHERE id = :id';

$stmt = $pdo->prepare($sql);

$stmt->execute([
    'id' => $id
]);

$usuario = $stmt->fetch();

if (!$usuario) {
    exit('Usuario no encontrado');
}

Precargar el formulario

<form method="post">

    <input
        type="text"
        name="nombre"
        value="<?php echo htmlspecialchars(
            $usuario['nombre'],
            ENT_QUOTES,
            'UTF-8'
        ); ?>"
    >

    <input
        type="email"
        name="email"
        value="<?php echo htmlspecialchars(
            $usuario['email'],
            ENT_QUOTES,
            'UTF-8'
        ); ?>"
    >

    <input
        type="number"
        name="edad"
        value="<?php echo htmlspecialchars(
            $usuario['edad'],
            ENT_QUOTES,
            'UTF-8'
        ); ?>"
    >

    <button type="submit">
        Guardar cambios
    </button>

</form>

Procesar la edición

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $nombre = trim($_POST['nombre'] ?? '');
    $email = trim($_POST['email'] ?? '');
    $edad = trim($_POST['edad'] ?? '');

    if ($nombre === '') {
        $errores[] = 'El nombre es obligatorio';
    }

    if (!filter_var(
        $email,
        FILTER_VALIDATE_EMAIL
    )) {
        $errores[] = 'El email no es válido';
    }

    if (empty($errores)) {

        $sql =
            'UPDATE usuarios
             SET nombre = :nombre,
                 email = :email,
                 edad = :edad
             WHERE id = :id';

        $stmt = $pdo->prepare($sql);

        $stmt->execute([
            'nombre' => $nombre,
            'email' => $email,
            'edad' => $edad,
            'id' => $id
        ]);

        echo 'Usuario actualizado';
    }
}

Eliminar un registro

La operación DELETE también debe incluir una condición:

DELETE FROM usuarios
WHERE id = 5;

Desde PHP:

$sql =
    'DELETE FROM usuarios
     WHERE id = :id';

$stmt = $pdo->prepare($sql);

$stmt->execute([
    'id' => $id
]);

No eliminar mediante enlaces GET

No conviene hacer algo como:

<a href="eliminar.php?id=5">
    Eliminar
</a>

Un enlace representa naturalmente una navegación. Para una acción destructiva es preferible utilizar un formulario con POST.

Formulario para eliminar

<form
    method="post"
    action="eliminar.php"
>

    <input
        type="hidden"
        name="id"
        value="5"
    >

    <button type="submit">
        Eliminar
    </button>

</form>

Procesar la eliminación

<?php

require 'conexion.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit('Método no permitido');
}

$id = filter_input(
    INPUT_POST,
    'id',
    FILTER_VALIDATE_INT
);

if ($id === false || $id === null) {
    exit('ID no válido');
}

$sql =
    'DELETE FROM usuarios
     WHERE id = :id';

$stmt = $pdo->prepare($sql);

$stmt->execute([
    'id' => $id
]);

echo 'Usuario eliminado';

Validar que el registro exista

Antes de modificar o eliminar, podemos comprobar que el registro exista.

$stmt = $pdo->prepare(
    'SELECT id
     FROM usuarios
     WHERE id = :id'
);

$stmt->execute([
    'id' => $id
]);

if (!$stmt->fetch()) {
    exit('Usuario no encontrado');
}

Estructura sencilla de archivos

usuarios/
│
├── conexion.php
├── index.php
├── crear.php
├── editar.php
└── eliminar.php

Por ahora es una estructura simple y didáctica. Más adelante veremos cómo organizar aplicaciones más grandes.

index.php

Puede mostrar el listado de usuarios y los botones de acción:

<?php foreach ($usuarios as $usuario): ?>

    <p>

        <?php echo htmlspecialchars(
            $usuario['nombre'],
            ENT_QUOTES,
            'UTF-8'
        ); ?>

        <a href="editar.php?id=<?php
            echo $usuario['id'];
        ?>">
            Editar
        </a>

        <form
            method="post"
            action="eliminar.php"
            style="display:inline"
        >
            <input
                type="hidden"
                name="id"
                value="<?php
                    echo $usuario['id'];
                ?>"
            >

            <button type="submit">
                Eliminar
            </button>
        </form>

    </p>

<?php endforeach; ?>

Mensajes después de una operación

En una aplicación real suele ser más cómodo redirigir después de insertar, actualizar o eliminar.

header(
    'Location: index.php?mensaje=creado'
);

exit;

Luego podemos mostrar un mensaje:

$mensaje = $_GET['mensaje'] ?? '';

if ($mensaje === 'creado') {
    echo 'Usuario creado correctamente';
}

Por qué redirigir después de POST

Después de procesar un formulario, una redirección evita que el navegador intente repetir la operación si el usuario actualiza la página.

Este patrón se conoce habitualmente como:

POST
 ↓
procesamiento
 ↓
redirect
 ↓
GET

También se lo conoce como Post/Redirect/Get.

Una mejora importante: confirmar eliminaciones

Podemos pedir confirmación en el navegador:

<form
    method="post"
    action="eliminar.php"
    onsubmit="return confirm(
        '¿Seguro que querés eliminar este usuario?'
    );"
>

Esto mejora la experiencia, aunque la autorización real de la operación siempre debe controlarse también en el servidor.

Consultas preparadas en todas las operaciones

En las tres operaciones mantenemos el mismo patrón:

$sql = '... :valor ...';

$stmt = $pdo->prepare($sql);

$stmt->execute([
    'valor' => $dato
]);

Esto evita construir SQL concatenando datos externos.

Errores comunes

  • concatenar valores del usuario dentro de SQL;
  • olvidar el WHERE en un UPDATE;
  • olvidar el WHERE en un DELETE;
  • usar GET para ejecutar una eliminación;
  • no validar IDs;
  • no comprobar si el registro existe;
  • no validar el formulario antes de guardar;
  • no utilizar consultas preparadas;
  • actualizar o eliminar registros sin verificar permisos;
  • repetir un POST accidentalmente al recargar la página.

Buenas prácticas

  • validar siempre los datos antes de escribir en la base;
  • utilizar prepare() y execute();
  • validar IDs con filtros apropiados;
  • comprobar la existencia del registro;
  • usar POST para acciones que modifican datos;
  • redireccionar después de operaciones exitosas;
  • escapar datos al mostrarlos en HTML;
  • controlar permisos antes de modificar o eliminar;
  • revisar cuidadosamente las condiciones de UPDATE y DELETE.

Ejercicios

  1. crear un formulario para insertar usuarios;
  2. validar nombre, email y edad;
  3. guardar el usuario mediante PDO;
  4. mostrar el ID generado con lastInsertId();
  5. crear una página de edición;
  6. precargar el formulario con los datos actuales;
  7. actualizar mediante una consulta preparada;
  8. crear un formulario POST para eliminar;
  9. validar el ID recibido;
  10. mostrar mensajes después de cada operación;
  11. aplicar Post/Redirect/Get;
  12. agregar confirmación antes de eliminar.

Qué aprendimos

  • cómo insertar registros con PDO;
  • cómo recuperar el ID insertado;
  • cómo modificar registros con UPDATE;
  • cómo precargar un formulario;
  • cómo eliminar registros;
  • por qué debemos validar IDs;
  • por qué las operaciones destructivas no deberían ejecutarse por GET;
  • cómo combinar formularios, PDO y consultas preparadas;
  • qué es Post/Redirect/Get.

Continuá aprendiendo SQL / MySQL

Para profundizar en INSERT, UPDATE, DELETE, restricciones, relaciones y demás conceptos propios de la base de datos, podés seguir nuestra ruta completa:

👉 Ver la ruta SQL / MySQL

¿Qué sigue?

En la próxima guía vamos a integrar todo lo aprendido en un CRUD completo con PHP, MySQL y PDO: listado, alta, edición, eliminación y búsqueda dentro de una pequeña aplicación funcional.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó y querés apoyar a Club Programador, podés colaborar mediante:

☕ Apoyar con Mercado Pago

🌎 Apoyar con PayPal


Descubre más desde Club Programador

Suscríbete y recibe las últimas entradas en tu correo electrónico.

Deja un comentario

Descubre más desde Club Programador

Suscríbete ahora para seguir leyendo y obtener acceso al archivo completo.

Seguir leyendo