
CRUD básico en PHP
Contenidos
Introducción
Un CRUD es un acrónimo que significa Create, Read, Update y Delete.
Es un conjunto de operaciones básicas que se pueden realizar en una base de datos o en un sistema de gestión de bases de datos relacionales, y suele ser la base de cualquier aplicación, ya que permite al usuario interactuar con la información almacenada en la base de datos.
En este tutorial trabajaremos un CRUD básico en PHP, utilizando MySQL como sistema de gestión de bases de datos (aunque puede cambiarse a otro SGBD si se desea).
Este tutorial asume que tienes conocimientos básicos de PHP y SQL.
Requisitos
Para poder seguir este tutorial necesitamos tener instalado:
- Un servidor web (como Apache) 1
- PHP 8.1 o superior
- Un sistema de gestión de bases de datos (como MySQL, PostgreSQL o SQLite)
- Un editor de código, como Visual Studio Code
- El navegador web de tu elección.
Claramente, todos los requisitos pueden cambiarse por alternativas más potentes o avanzadas como un hosting en la nube, un container de Docker, etc., pero para este tutorial, nos enfocaremos en lo básico.
Sobre el servidor web
No entraré a los detalles de como levantar el servidor y servir nuestro proyecto desde Apache, XAMPP o WAMP, aunque si contamos con PHP instalado en nuestra línea de comandos, esto se puede hacer realmente fácil.
cd /ruta/a/mi/proyecto
php -S localhost:8000
Con esto, tendremos un servidor web corriendo en el puerto 8000
y podremos acceder a nuestro proyecto en http://localhost:8000
.
Crear la base de datos
Antes de empezar a codificar, necesitamos crear la base de datos que vamos a utilizar, en este caso, trabajaré con MySQL aunque en realidad puedes usar cualquier sistema de gestión de bases de datos.
CREATE DATABASE crud_php;
USE crud_php;
-- Crearemos una tabla llamada `users` con los siguientes campos
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Nota: Asegurate de ajustar la sintaxis, nombres y tipos de datos según tu sistema de gestión de bases de datos.
Una vez que hemos creado la base de datos y la tabla, podemos empezar a codificar el CRUD.
Estructura del proyecto
Para mantener las cosas organizadas, crearemos una estructura de directorios simple para nuestra aplicación:
crud-php/
├── assets/
│ ├── css/
│ │ └── app.css
│ └── js/
│ └── app.js
├── inc/
│ ├── db.php
│ ├── header.php
│ └── footer.php
├── index.php
├── new.php
├── save.php
├── view.php
├── update.php
└── delete.php
- El directorio
assets
contendrá los archivos CSS y JavaScript. - El directorio
inc
contendrá los archivos parciales que se incluirán en las páginas principales.- El archivo
db.php
contendrá la conexión a la base de datos.
- El archivo
- Los archivos
index.php
,new.php
,save.php
,view.php
,update.php
ydelete.php
contendrán el código PHP para las operaciones CRUD.- Si tuvieramos más tablas, sería recomendable agregar un prefijo o sufijo al nombre del archivo para identificar la tabla con la que trabaja. P.e.
users_index.php
,products_index.php
, etc.
- Si tuvieramos más tablas, sería recomendable agregar un prefijo o sufijo al nombre del archivo para identificar la tabla con la que trabaja. P.e.
Diseño de la interfaz
Puesto que no es el objetivo de este tutorial, no entraremos mucho en temas de diseño, utilizaremos la estructura básica propuesta por el micro framework PicoCSS, para que se aplique un diseño simple y limpio a nuestra aplicación.
Vamos a empezar por separar nuestro layout en dos archivos: header.php
y footer.php
.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CRUD en PHP</title>
<!-- Utilice la versión default de PicoCSS pero puedes elegir otro color -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
>
<link rel="stylesheet" href="assets/css/style.css" />
</head>
<body>
<header class="container">
<h1>Gestor de Usuarios</h1>
</header>
<main class="container">
</main>
<footer class="container">
<p>© 2024 - Todos los derechos reservados</p>
</footer>
</body>
</html>
Reutilizaremos estos archivos en cada página para mantener la consistencia en el diseño.
Conexión a la base de datos
Para conectarnos a la base de datos, crearemos un archivo llamado db.php
en el directorio inc
:
<?php
$host = 'localhost'; // Cambiar si es necesario
$dbname = 'crud_php'; // Nombre de la base de datos
$username = 'root'; // Usuario de la base de datos
$password = 'miPasswordIndescifrable2024'; // Contraseña de la base de datos
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Error: " . $e->getMessage());
}
El servidor de base de datos debe estar en ejecución, de lo contrario la conexión no podrá establecerse.
En este código, estamos creando una instancia de la clase PDO
de PHP y estableciendo el modo de error a ERRMODE_EXCEPTION
, lo que nos permitirá capturar cualquier error que ocurra durante la ejecución de las consultas SQL.
Dado que estamos usando MySQL, bien podríamos usar la extensión mysqli
de PHP, pero con la intención de mantener el código compatible con otros gestores de bases de datos nos mantendremos con PDO
.2
Cabe mencionar que la clase PDO
se incorporó desde la versión 5.1 de PHP como una alternativa segura y eficiente para conectarse a la base de datos, y se ha convertido en la forma recomendada de interactuar con la base de datos en PHP.3
De la misma manera que se usa mysql
en la cadena de conexión, se puede usar otro gestor, como pgsql
o sqlite
.
Listar usuarios
Empezaremos por listar los usuarios que tenemos en la base de datos, para ello, crearemos un archivo llamado index.php
en la raíz del proyecto (o lo editamos, si ya lo habías creado):
<?php
require_once 'inc/db.php';
$stmt = $pdo->query('SELECT * FROM users');
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<?php include_once 'inc/header.php'; ?>
<h2>Lista de Usuarios</h2>
<div class="overflow">
<table>
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Email</th>
<th>Fecha de Creación</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach($users as $user):?>
<tr>
<td><?= $user['id']; ?></td>
<td><?= $user['name']; ?></td>
<td><?= $user['email']; ?></td>
<td><?= $user['created_at']; ?></td>
<td>
<a href="update.php?id=<?= $user['id']; ?>">Editar</a>
<a href="delete.php?id=<?= $user['id']; ?>">Eliminar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php include_once 'inc/footer.php'; ?>
Vamos a desglosar el código:
- La línea 2 incluye el archivo
db.php
que contiene la conexión a la base de datos, se utilizarequire_once
para asegurarnos de que el archivo se incluya solo una vez y si no se encuentra, se detiene la ejecución del script. - La línea 4 ejecuta una consulta SQL para seleccionar todos los registros de la tabla
users
, el resultado se almacena en la variable$stmt
. - La línea 5 obtiene todas las filas del resultado como un array asociativo y lo almacena en la variable
$users
. 4 - Las líneas 23-34 generan una nueva fila en la tabla HTML para cada usuario en el array
$users
, mostrando los datos de cada usuario en las columnas correspondientes. - En las líneas 29-32 se crean enlaces para editar y eliminar cada usuario, pasando el
id
del usuario como parámetro en la URL (lo usaremos más adelante).
Crear un nuevo usuario
Continuaremos con la creación de un nuevo usuario, para ello, trabajaremos en el archivo new.php
en la raíz del proyecto, este archivo contendrá un formulario para agregar un nuevo usuario a la base de datos:
<?php include_once 'inc/header.php'; ?>
<h2>Agregar Usuario</h2>
<form action="save.php" method="post">
<fieldset>
<label for="name">Nombre:</label>
<input type="text" name="name" id="name" required>
</fieldset>
<fieldset>
<label for="email">Email:</label>
<input type="email" name="email" id="email" required>
</fieldset>
<fieldset>
<button type="submit">Guardar</button>
</fieldset>
</form>
<?php include_once 'inc/footer.php'; ?>
Este formulario es relativamente simple, consta de dos campos de texto para el nombre y el email del usuario, y un botón para enviar el formulario.
El formulario envía los datos a un archivo llamado save.php
mediante el método POST
, que es donde procesaremos los datos y los guardaremos en la base de datos.
Guardar un nuevo usuario
Ahora, trabajaremos en el archivo save.php
en la raíz del proyecto para procesar los datos del formulario y guardar un nuevo usuario en la base de datos:
<?php
require_once 'inc/db.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
[$name, $email] = $_POST;
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute(['name' => $name, 'email' => $email]);
header('Location: index.php');
exit;
}
?>
Desglosemos el código:
- En la línea 2 incluímos la conexión a la base de datos, puesto que la utilizaremos.
- En la línea 4 verificamos si el servidor recibió una solicitud de tipo
POST
, de ser así, podemos proceder a procesar el formulario. - En la línea 5 desestructuramos el array
$_POST
para obtener los valores de los camposname
yemail
del formulario, es decir, tomamos los valores de los índicesname
yemail
y los asignamos a las variables$name
y$email
, respectivamente. - En la línea 7 preparamos una consulta SQL para insertar un nuevo usuario en la tabla
users
, utilizando marcadores de posición con los nombres de los campos (:name
y:email
) para evitar la inyección de SQL. - En la línea 8 ejecutamos la consulta SQL, pasando un array asociativo con los valores de los campos
name
yemail
. - Finalmente, en la línea 10 redirigimos al usuario a la página
index.php
después de guardar el nuevo usuario en la base de datos.
Nota sobre el guardado de datos
Lo primero que debemos tener en cuenta al ejecutar cualquier consulta SQL es la posibilidad de inyección de SQL, por lo que siempre debemos utilizar marcadores de posición en nuestras consultas para evitar este tipo de ataques.
PDO nos permite utilizar marcadores de posición con los nombres de los campos, lo que hace que nuestras consultas sean más seguras y menos propensas a errores.
Adicionalmente, por brevedad del código, se omitió el manejo de excepciones, mismo que debería ser implementado para manejar cualquier error que pueda ocurrir durante la ejecución de la consulta SQL.
Ver un usuario
Ahora, vamos a trabajar en la funcionalidad para ver un usuario específico, para ello, crearemos un archivo llamado view.php
en la raíz del proyecto.
Este archivo será relativamente sencillo, ya que sólo mostrará los datos del usuario en modo texto, aunque podríamos mejorar el diseño para hacerlo más atractivo.
<?php
require_once 'inc/db.php';
$id = $_GET['id'] ?? null;
if (!$id) {
header('Location: index.php');
exit;
}
// Obtenemos el usuario con el ID proporcionado
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
header('Location: index.php');
exit;
}
?>
<?php include_once 'inc/header.php'; ?>
<h2>Detalles del Usuario</h2>
<a href="index.php">« Volver</a>
<dl>
<dt>ID:</dt>
<dd><?= $user['id']; ?></dd>
<dt>Nombre:</dt>
<dd><?= $user['name']; ?></dd>
<dt>Email:</dt>
<dd><?= $user['email']; ?></dd>
<dt>Fecha de Creación:</dt>
<dd><?= $user['created_at']; ?></dd>
</dl>
<?php include_once 'inc/footer.php'; ?>
Nota: Para este punto, ya deberías tener una idea de cómo funciona el código, por lo que no entraré en detalles sobre cada línea.
Revisemos lo que hicimos en este archivo:
- Primero verificamos si se ha proporcionado un
id
en la URL, si no es así, redirigimos al usuario a la páginaindex.php
. - Luego, preparamos una consulta SQL para seleccionar un usuario específico de la tabla
users
utilizando elid
proporcionado en la URL. - Si el usuario no existe en la base de datos, redirigimos al usuario a la página
index.php
. - Finalmente, mostramos los detalles del usuario en una lista de definición (
<dl>
) con los camposID
,Nombre
,Email
yFecha de Creación
.
Actualizar un usuario
Ahora, vamos a trabajar en la funcionalidad para actualizar un usuario existente, para ello, crearemos un archivo llamado update.php
en la raíz del proyecto.
Este archivo contendrá un formulario similar al de new.php
, pero con los datos del usuario que queremos actualizar.
<?php
require_once 'inc/db.php';
$id = $_GET['id'] ?? null;
if (!$id) {
header('Location: index.php');
exit;
}
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
header('Location: index.php');
exit;
}
?>
<?php include_once 'inc/header.php'; ?>
<h2>Editar Usuario</h2>
<a href="index.php">« Volver</a>
<form action="save.php" method="post">
<input type="hidden" name="id" value="<?= $user['id']; ?>"> <!-- Campo oculto para el ID -->
<fieldset>
<label for="name">Nombre:</label>
<input type="text" name="name" id="name" value="<?= $user['name']; ?>" required>
</fieldset>
<fieldset>
<label for="email">Email:</label>
<input type="email" name="email" id="email" value="<?= $user['email']; ?>" required>
</fieldset>
<fieldset>
<button type="submit">Actualizar</button>
</fieldset>
</form>
<?php include_once 'inc/footer.php'; ?>
Desglosemos el código:
- Primero, verificamos si se ha proporcionado un
id
en la URL, si no es así, redirigimos al usuario a la páginaindex.php
, my similar a lo que hicimos enview.php
. - Luego, preparamos una consulta SQL para seleccionar un usuario específico de la tabla
users
utilizando elid
proporcionado en la URL.- Es importante notar que usamos el método
fetch
en lugar defetchAll
para obtener un solo registro.
- Es importante notar que usamos el método
- Si el usuario no existe en la base de datos, redirigimos al usuario a la página
index.php
. - Finalmente, mostramos un formulario similar al de
new.php
, pero con los datos del usuario que queremos actualizar, y un campo oculto para elid
del usuario.
Guardar la actualización de un usuario
Para completar la funcionalidad de actualización de un usuario, necesitamos modificar el archivo save.php
para manejar la actualización de los datos del usuario.
<?php
require_once 'inc/db.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Si hay un ID es una actualización
if (isset($_POST['id'])) {
[$id, $name, $email] = $_POST;
$stmt = $pdo->prepare('UPDATE users SET name = :name, email = :email WHERE id = :id');
$stmt->execute(['id' => $id, 'name' => $name, 'email' => $email]);
} else {
[$name, $email] = $_POST;
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute(['name' => $name, 'email' => $email]);
}
}
header('Location: index.php');
exit;
?>
Con el código anterior, hemos modificado la lógica para manejar tanto la creación de un nuevo usuario como la actualización de un usuario existente, dependiendo de si se proporciona un id
en el formulario.
Con esto se reutiliza el mismo archivo save.php
para manejar ambas operaciones, lo que simplifica el código y evita la duplicación de lógica.
Eliminar un usuario
Finalmente, vamos a trabajar en la funcionalidad para eliminar un usuario de la base de datos, para ello, usaremos el archivo llamado delete.php
en la raíz del proyecto.
<?php
require_once 'inc/db.php';
$id = $_GET['id'] ?? null;
if (!$id) {
header('Location: index.php');
exit;
}
$stmt = $pdo->prepare('DELETE FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
header('Location: index.php');
exit;
?>
Veamos el código:
- En este archivo, verificamos si se ha proporcionado un
id
en la URL, si no es así, redirigimos al usuario a la páginaindex.php
.- Aunque hemos hecho esta validación en otros archivos, aquí es extremadamente importante, puesto que involucra una operación irreversible.
- Luego, preparamos una consulta SQL para eliminar un usuario específico de la tabla
users
utilizando elid
proporcionado en la URL. - Finalmente, redirigimos al usuario a la página
index.php
después de eliminar el usuario de la base de datos.
Et voilà!
Con esto hemos completado la implementación de un CRUD básico en PHP, utilizando MySQL como sistema de gestión de bases de datos.
En este tutorial revisamos los conceptos básicos de un CRUD, desde la creación de una base de datos, la conexión a la base de datos, la creación de un nuevo usuario, la visualización de un usuario, la actualización de un usuario y la eliminación de un usuario.
Al utilizar PDO, la conexión a la base de datos y la gestión de la información, se vuelve muy sencilla e intuitiva.
Cabe mencionar que este es un CRUD muy básico y que se puede mejorar y extender de muchas maneras, como agregar validaciones de datos, paginación, búsqueda, filtros, etc.
Adicionalmente, se podría agregar un sistema de autenticación para proteger las operaciones CRUD y permitir que sólo los usuarios autenticados puedan acceder a ellas, pero eso ya es tema para otra guía. 😉
Footnotes
-
Si no tienes un servidor web instalado, puedes usar XAMPP o WampServer, que incluyen Apache, PHP y MySQL. ↩
-
Mientras que
mysqli
es específica para MySQL,PDO
proporciona una interfaz de acceso a la base de datos que es independiente del gestor de base de datos, además de tener algunas otras diferencias. ↩ -
Con la publicación de PHP 8.4 se mantienen las mejoras en la clase
PDO
y se añaden algunas nuevas características. ↩ -
Que sea un array asociativo significa que los índices del array son los nombres de las columnas de la tabla, lo que es más fácil de leer y entender. ↩