Cómo Crear Una Aplicación CRUD Con PHP y MySQL
Cómo Crear Una Aplicación CRUD Con PHP y MySQL
En este tutorial vamos a ver cómo crear una aplicación CRUD con PHP y MySQL. Crearemos
tanto el backend como el frontend de la aplicación. No usaremos ningún framework, sino las
extensiones y los métodos nativos de PHP. La aplicación soportará la lectura, la escritura, la
actualización y el borrado de registros en la base de datos. Para las vistas usaremos
únicamente HTML y CSS.
Este es un tutorial de introducción especialmente creado para aquellas personas que se estén
iniciando con el desarrollo de aplicaciones con PHP. Por ello, no crearemos un gestor de rutas
ni usaremos composer. Tampoco dividiremos la aplicación en modelos, vistas y controladores
tal y como dicta el patrón de diseño MVC, siendo algo que dejaremos para otro tutorial.
#Contenidos
1 Introducción
5.2.3 Búsqueda
5.2.4 Acciones
6 Protección CSRF
7 Conclusión
1.Introducción
Vamos a crear una sencilla aplicación que permita gestionar los datos de los
alumnos de un colegio. Necesitamos agregar las funcionalidades que nos
permitan crear un alumno, mostrar una lista de alumnos, editar los datos de un
alumno y eliminar un alumno.
Lo primero que veremos en este tutorial será cómo conectarnos a una base de
datos MySQL con PHP usando PDO (PHP Data Objects). Seguidamente
crearemos un script que cree tanto la base de datos como las tablas de la
misma. Luego crearemos un formulario HTML que envíe datos al servidor. En
el servidor, usaremos sentencias preparadas para insertar registros en la base
de datos. Finalmente obtendremos los datos de la base de datos y los
mostraremos en una tabla HTML.
Lo primero que tenemos que hacer es crear un host virtual en nuestro sistema,
que es en donde crearemos el proyecto. Usaremos el servidor Apache, que se
instala con Wamp, que es la herramienta que utilizo en este proyecto. Si no
sabes cómo crear un host virtual, consulta el tutorial en donde explico cómo
crear un host virtual con Apache. En caso de que uses algún paquete todo en
uno, consulta una de estas guías.
Host virtual con Wamp: Cómo crear un host virtual con Wamp
Host virtual con MAMP: Cómo crear un host virtual con MAMP
Host virtual con XAMPP: Cómo crear un host virtual con XAMPP
Primero tenemos que crear una plantilla HTML para la aplicación junto con un
pequeño menú. No es el objetivo de este tutorial el de aprender CSS, por lo que
nos limitaremos a usar Bootstrap para los estilos.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-
scale=1" />
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/boo
tstrap.min.css" />
</head>
<body>
<h1>Aplicación CRUD PHP</h1>
<!-- Aquí el código HTML de la aplicación -->
</body>
</html>
Sin embargo, vamos a dividir la plantilla HTML en una cabecera y un pie que
compartirán todas las páginas de nuestra aplicación, por lo que, por ahora, es
mejor que dejes el archivo index.php vacío.
Para ello, crea un directorio llamado /templates, en cuyo interior debes crear
un archivo llamado header.php y otro llamado footer.php.
En archivo header.php contendrá la cabecera de la aplicación, por lo que debes
agregar este código HTML:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-
scale=1" />
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/boo
tstrap.min.css" />
</head>
<body>
Lo único que hemos hecho es agregar la declaración DOCTYPE y la
sección head de la aplicación, en donde hemos agregado el título y también
hemos incluido Bootstrap desde su CDN.
</body>
</html>
Luego edita el archivo index.php y modifícalo para que contenga únicamente
este código, en donde agregamos el header y el footer que hemos creado:
Para crear la base datos puedes usar alguna aplicación como MySQL
Workbench, SequelPro, Adminer o phpMyAdmin. En este tutorial, primero
crearemos la base de datos mediante una consulta SQL.
use tutorial_crud;
Vamos a crear un script que nos permita conectarnos a MySQL para crear la
base de datos. Podemos usar la interfaz PDO (PHP Data Objects) o podemos
usar MySQLi. La diferencia consiste en que con PDO nos podemos conectar a
más bases de datos que no necesariamente han de ser MySQL, siendo más
versátil que MySQLi, que solamente funcionará con bases de datos MySQL.
Además, PDO es más extensible y abierto de cara al futuro, haciendo que las
aplicaciones sean más fáciles de mantener.
<?php
return [
'db' => [
'host' => 'localhost',
'user' => 'root',
'pass' => 'root',
'name' => 'tutorial_crud',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]
]
];
Lo que hemos hecho ha sido definir un array de configuración que será devuelto
por el archivo. En el array db hemos definido los parámetros y opciones que
usaremos para conectarnos a la base de datos.
Ahora que ya hemos creado la conexión, vamos a asignar nuestra consulta SQL
a una variable usando el método file_get_contents y, seguidamente,
usaremos el método exec para ejecutar la consulta:
$sql = file_get_contents('data/migracion.sql');
$conexion->exec($sql);
A continuación puedes ver el contenido final del archivo instalar.php, en el
que también hemos agregado un bloque try/catch para que se muestre algún
error en caso de haberlo:
<?php
$config = include 'config.php';
try {
$conexion = new PDO('mysql:host=' . $config['db']['host'],
$config['db']['user'], $config['db']['pass'], $config['db']
['options']);
$sql = file_get_contents("data/migracion.sql");
$conexion->exec($sql);
echo "La base de datos y la tabla de alumnos se han creado con
éxito.";
} catch(PDOException $error) {
echo $error->getMessage();
}
Tal y como ves, la sentencia catch del bloque try/catch recibirá una
excepción de tipo PDOException como parámetro.
4.3 Ejecuta el script de instalación
Tenemos que crear una página que nos permita crear un alumno, otra que nos
permita listarlos y otra que nos permita actualizarlos. Además, también
necesitaremos un script que sea capaz de eliminar usuarios. Veamos cada uno
de estos apartados de la aplicación CRUD por separado.
<div class="container">
<div class="row">
<div class="col-md-12">
<a href="crear.php" class="btn btn-primary mt-4">Crear
alumno</a>
<hr>
</div>
</div>
</div>
Formulario HTML
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-4">Crea un alumno</h2>
<hr>
<form method="post">
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" name="nombre" id="nombre"
class="form-control">
</div>
<div class="form-group">
<label for="apellido">Apellido</label>
<input type="text" name="apellido" id="apellido"
class="form-control">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" id="email"
class="form-control">
</div>
<div class="form-group">
<label for="edad">Edad</label>
<input type="text" name="edad" id="edad" class="form-
control">
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-
primary" value="Enviar">
<a class="btn btn-primary" href="index.php">Regresar
al inicio</a>
</div>
</form>
</div>
</div>
</div>
Hemos agregado también una etiqueta <label> para cada campo, que se
relacionará con su correspondiente campo gracias al atributo for. El valor del
atributo for es el mismo que el del atributo id del campo con el que se
relaciona. El uso de etiquetas label permite que las páginas sean más
accesibles.
Código PHP
if (isset($_POST['submit'])) {
// Acciones a realizar
}
Para insertar un usuario también debemos conectarnos a MySQL, pero ahora
deberemos especificar también el nombre de la base de datos en el parámetros
DSN.
<?php
if (isset($_POST['submit'])) {
$resultado = [
'error' => false,
'mensaje' => 'Usuario agregado con éxito'
];
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'],
$config['db']['pass'], $config['db']['options']);
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
}
El array $resultado almacenará algún posible error, de haberlo. Luego hemos
incluido el array de configuración del archivo config.php y nos hemos
conectado a la base de datos. Esta vez hemos definido el nombre de la base de
datos a la que nos conectamos.
$alumno = [
"nombre" => $_POST['nombre'],
"apellido" => $_POST['apellido'],
"email" => $_POST['email'],
"edad" => $_POST['edad'],
];
En teoría deberíamos sanitizar los datos de entrada. Sin embargo, dado que
usaremos sentencias preparadas de PHP, no es necesario. Usaremos una
sentencia INSERT MySQL:
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute($alumno);
Vamos a agregar también un mensaje de confirmación justo después del lugar
en el que incluimos el archivo header.php, en donde mostraremos un error, de
haberlo, o un mensaje de éxito si el alumno se ha insertado correctamente:
<?php
if (isset($resultado)) {
?>
<div class="container mt-3">
<div class="row">
<div class="col-md-12">
<div class="alert alert-<?= $resultado['error'] ?
'danger' : 'success' ?>" role="alert">
<?= $resultado['mensaje'] ?>
</div>
</div>
</div>
</div>
<?php
}
?>
Este sería el código PHP completo que usamos para crear el usuario:
<?php
if (isset($_POST['submit'])) {
$resultado = [
'error' => false,
'mensaje' => 'El alumno ' . $_POST['nombre'] . ' ha sido
agregado con éxito'
];
$config = include 'config.php';
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'],
$config['db']['pass'], $config['db']['options']);
$alumno = array(
"nombre" => $_POST['nombre'],
"apellido" => $_POST['apellido'],
"email" => $_POST['email'],
"edad" => $_POST['edad'],
);
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute($alumno);
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
}
?>
<?php
if (isset($resultado)) {
?>
<div class="container mt-3">
<div class="row">
<div class="col-md-12">
<div class="alert alert-<?= $resultado['error'] ?
'danger' : 'success' ?>" role="alert">
<?= $resultado['mensaje'] ?>
</div>
</div>
</div>
</div>
<?php
}
?>
Ahora ya podrías enviar el formulario. Deberías ver el siguiente mensaje una vez
lo envíes:
Ataques XSS
Para evitar ataques XSS vamos a codificar los caracteres especiales en sus
respectivas versiones HTML. Para simplificar el proceso, crearemos una función
reutilizable.
Crea el archivo funciones.php en el directorio raíz del proyecto y agrega esta
función:
function escapar($html) {
return htmlspecialchars($html, ENT_QUOTES | ENT_SUBSTITUTE,
"UTF-8");
}
Lo que hace la función es codificar cualquier caracter en su versión HTML.
Luego, incluye el archivo funciones.php en la parte superior del
archivo create.php:
include 'funciones.php';
Seguidamente, usa la función escapar con el elemento $_POST['nombre'] en
el array $resultado:
$resultado = [
'error' => false,
'mensaje' => 'El alumno ' . escapar($_POST['nombre']) . ' ha
sido agregado con éxito'
];
Este sería el código final completo del archivo crear.php:
<?php
include 'funciones.php';
if (isset($_POST['submit'])) {
$resultado = [
'error' => false,
'mensaje' => 'El alumno ' . escapar($_POST['nombre']) . ' ha
sido agregado con éxito'
];
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'],
$config['db']['pass'], $config['db']['options']);
$alumno = array(
"nombre" => $_POST['nombre'],
"apellido" => $_POST['apellido'],
"email" => $_POST['email'],
"edad" => $_POST['edad'],
);
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute($alumno);
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
}
?>
<?php
if (isset($resultado)) {
?>
<div class="container mt-3">
<div class="row">
<div class="col-md-12">
<div class="alert alert-<?= $resultado['error'] ?
'danger' : 'success' ?>" role="alert">
<?= $resultado['mensaje'] ?>
</div>
</div>
</div>
</div>
<?php
}
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-4">Crea un alumno</h2>
<hr>
<form method="post">
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" name="nombre" id="nombre"
class="form-control">
</div>
<div class="form-group">
<label for="apellido">Apellido</label>
<input type="text" name="apellido" id="apellido"
class="form-control">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" id="email"
class="form-control">
</div>
<div class="form-group">
<label for="edad">Edad</label>
<input type="text" name="edad" id="edad" class="form-
control">
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-
primary" value="Enviar">
<a class="btn btn-primary" href="index.php">Regresar
al inicio</a>
</div>
</form>
</div>
</div>
</div>
Vamos a crear la página usada para mostrar los datos de los alumnos. Para ello
usaremos el archivo index.php, en donde incluiremos tanto el
archivo header.php como el archivo footer.php.
Código PHP
Después del botón que nos permite acceder a la página crear.php vamos a
agregar una tabla con la lista de alumnos existentes. Sin embargo, primero
necesitamos obtener la lista de alumnos desde la base de datos. Por ello, debes
agregar este código al principio del archivo index.php:
<?php
include 'funciones.php';
$error = false;
$config = include 'config.php';
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
Luego almacenamos el resultado en la variable $alumnos:
$alumnos = $sentencia->fetchAll();
En caso de que se produzca algún error debes mostrarlo. Para ello, agrega el
siguiente código justo después del lugar en donde incluimos el
archivo header.php:
<?php
if ($error) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger" role="alert">
<?= $error ?>
</div>
</div>
</div>
</div>
<?php
}
?>
Este sería el código PHP del archivo index.php con lo que hemos hecho hasta
ahora.
<?php
include 'funciones.php';
$error = false;
$config = include 'config.php';
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
$alumnos = $sentencia->fetchAll();
} catch(PDOException $error) {
$error= $error->getMessage();
}
?>
<?php
if ($error) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger" role="alert">
<?= $error ?>
</div>
</div>
</div>
</div>
<?php
}
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<a href="crear.php" class="btn btn-primary mt-4">Crear
alumno</a>
<hr>
</div>
</div>
</div>
Tabla HTML
Vamos a mostrar la lista de alumnos en una tabla HTML. Sin embargo, primero
agregaremos un mensaje que se ejecute en caso de que se haya producido
algún error al obtener la lista de alumnos.
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-3">Lista de alumnos</h2>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Email</th>
<th>Edad</th>
</tr>
</thead>
<tbody>
<?php
if ($alumnos && $sentencia->rowCount() > 0) {
foreach ($alumnos as $fila) {
?>
<tr>
<td><?php echo escapar($fila["id"]); ?></td>
<td><?php echo escapar($fila["nombre"]); ?></td>
<td><?php echo escapar($fila["apellido"]); ?
></td>
<td><?php echo escapar($fila["email"]); ?></td>
<td><?php echo escapar($fila["edad"]); ?></td>
</tr>
<?php
}
}
?>
<tbody>
</table>
</div>
</div>
</div>
Lo que hacemos es comprobar que existen alumnos mediante el
método rowCount y recorrer la lista de alumnos, agregando una fila a la tabla
por cada uno de los alumnos.
Este sería el código del archivo index.php con lo que hemos hecho hasta
ahora:
<?php
include 'funciones.php';
$error = false;
$config = include 'config.php';
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
$alumnos = $sentencia->fetchAll();
} catch(PDOException $error) {
$error= $error->getMessage();
}
?>
<?php
if ($error) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger" role="alert">
<?= $error ?>
</div>
</div>
</div>
</div>
<?php
}
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<a href="crear.php" class="btn btn-primary mt-4">Crear
alumno</a>
<hr>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-3">Lista de alumnos</h2>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Email</th>
<th>Edad</th>
</tr>
</thead>
<tbody>
<?php
if ($alumnos && $sentencia->rowCount() > 0) {
foreach ($alumnos as $fila) {
?>
<tr>
<td><?php echo escapar($fila["id"]); ?></td>
<td><?php echo escapar($fila["nombre"]); ?></td>
<td><?php echo escapar($fila["apellido"]); ?
></td>
<td><?php echo escapar($fila["email"]); ?></td>
<td><?php echo escapar($fila["edad"]); ?></td>
</tr>
<?php
}
}
?>
<tbody>
</table>
</div>
</div>
</div>
Búsqueda
Estaría bien agregar un campo de búsqueda que nos permita buscar usuarios
por apellido. Para ello crearemos el siguiente formulario debajo de la línea de
separación que hemos agregado, debajo del enlace hacia la página crear.php:
<div class="container">
<div class="row">
<div class="col-md-12">
<a href="crear.php" class="btn btn-primary mt-4">Crear
alumno</a>
<hr>
<form method="post" class="form-inline">
<div class="form-group mr-3">
<input type="text" id="apellido" name="apellido"
placeholder="Buscar por apellido" class="form-control">
</div>
<button type="submit" name="submit" class="btn btn-
primary">Ver resultados</button>
</form>
</div>
</div>
</div>
Hemos usado el atributo placeholder en el campo nombre del formulario para
mostrar un texto por defecto, que desaparecerá cuando introduzcamos algo en
él.
if (isset($_POST['apellido'])) {
$consultaSQL = "SELECT * FROM alumnos WHERE apellido LIKE '%"
. $_POST['apellido'] . "%'";
} else {
$consultaSQL = "SELECT * FROM alumnos";
}
El operador MySQL LIKE buscará los alumnos cuyo apellido contenga la
subadena que introduzcamos en el campo apellido. El símbolo % sirve para
especificar que puede haber texto a la izquierda o a la derecha de la cadena.
Por ahora hemos visto cómo conectarnos a la base de datos mediante PDO,
cómo crear un script de instalación y cómo listar y agregar registros. En una
aplicación real también tendríamos que agregar gestión de usuarios, una página
de login o validaciones JavaScript entre otras cosas, aunque es algo que sale
del alcance de este tutorial.
Acciones
Antes de continuar, vamos a agregar una columna más a nuestra tabla que
contenga dos enlaces para cada fila. Los enlaces enlazarán al
archivo editar.php y al archivo borrar.php respectivamente. Para ello
agregamos una cabecera adicional a la tabla:
<thead>
<tr>
<!-- ... -->
<th>Acciones</th>
</tr>
</thead>
También agregaremos una columna más con las acciones al cuerpo de la tabla:
<td>
>">Editar</a>
</td>
Tal y como ves, enviamos el id del usuario que queremos borrar o que
queremos actualizar a las páginas borrar.php y editar.php respectivamente.
Estas páginas todavía nos las hemos creado.
<?php
include 'funciones.php';
$error = false;
$config = include 'config.php';
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
if (isset($_POST['apellido'])) {
$consultaSQL = "SELECT * FROM alumnos WHERE apellido LIKE
'%" . $_POST['apellido'] . "%'";
} else {
$consultaSQL = "SELECT * FROM alumnos";
}
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
$resultados = $sentencia->fetchAll();
} catch(PDOException $error) {
$error= $error->getMessage();
}
<?php
if ($error) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger" role="alert">
<?= $error ?>
</div>
</div>
</div>
</div>
<?php
}
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<a href="crear.php" class="btn btn-primary mt-4">Crear
alumno</a>
<hr>
<form method="post" class="form-inline">
<div class="form-group mr-3">
<input type="text" id="apellido" name="apellido"
placeholder="Buscar por apellido" class="form-control">
</div>
<button type="submit" name="submit" class="btn btn-
primary">Ver resultados</button>
</form>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-3"><?= $titulo ?></h2>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Email</th>
<th>Edad</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php
if ($alumnos && $sentencia->rowCount() > 0) {
foreach ($alumnos as $fila) {
?>
<tr>
<td><?php echo escapar($fila["id"]); ?></td>
<td><?php echo escapar($fila["nombre"]); ?></td>
<td><?php echo escapar($fila["apellido"]); ?
></td>
<td><?php echo escapar($fila["email"]); ?></td>
<td><?php echo escapar($fila["edad"]); ?></td>
<td>
<a href="<?= 'borrar.php?id=' .
escapar($fila["id"]) ?>">Borrar</a>
<a href="<?= 'editar.php?id=' .
Vamos a agregar una página que nos permita editar un usuario. Para ello crea el
archivo editar.php en la carpeta raíz del proyecto con este contenido:
Este es el código PHP que usamos para obtener el alumno que estamos
editando, que va al principio del archivo editar.php:
<?php
include 'funciones.php';
$resultado = [
'error' => false,
'mensaje' => ''
];
if (!isset($_GET['id'])) {
$resultado['error'] = true;
$resultado['mensaje'] = 'El alumno no existe';
}
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$id = $_GET['id'];
$consultaSQL = "SELECT * FROM alumnos WHERE id =" . $id;
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
$alumno = $sentencia->fetch(PDO::FETCH_ASSOC);
if (!$alumno) {
$resultado['error'] = true;
$resultado['mensaje'] = 'No se ha encontrado el alumno';
}
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
?>
Tal y como ves, en caso de no pasar ningún id a la página o de que ocurra
algún error, almacenamos el mensaje en el elemento $resultado['mensaje'].
Formulario HTML
Sin embargo, primero debemos mostrar algún error en caso de que haya
ocurrido alguno. Para ello usa el siguiente código después de la línea en la que
incluimos el archivo header.php:
<?php
if ($resultado['error']) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger" role="alert">
<?= $resultado['mensaje'] ?>
</div>
</div>
</div>
</div>
<?php
}
?>
En caso de que se haya enviado el formulario, tendremos que mostrar también
un mensaje de confirmación siempre y cuando no haya habido errores:
<?php
if (isset($_POST['submit']) && !$resultado['error']) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-success" role="alert">
El alumno ha sido actualizado correctamente
</div>
</div>
</div>
</div>
<?php
}
?>
Seguidamente, tras los mensajes anteriores, agrega el código del formulario:
<?php
if (isset($alumno) && $alumno) {
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-4">Editando el alumno <?=
escapar($alumno['nombre']) . ' ' . escapar($alumno['apellido'])
?></h2>
<hr>
<form method="post">
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" name="nombre" id="nombre"
value="<?= escapar($alumno['nombre']) ?>" class="form-control">
</div>
<div class="form-group">
<label for="apellido">Apellido</label>
<input type="text" name="apellido" id="apellido"
value="<?= escapar($alumno['apellido']) ?>" class="form-
control">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" id="email"
value="<?= escapar($alumno['email']) ?>" class="form-control">
</div>
<div class="form-group">
<label for="edad">Edad</label>
<input type="text" name="edad" id="edad" value="<?=
escapar($alumno['edad']) ?>" class="form-control">
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-
primary" value="Actualizar">
<a class="btn btn-primary" href="index.php">Regresar
al inicio</a>
</div>
</form>
</div>
</div>
</div>
<?php
}
?>
Tal y como ves, solamente mostramos el formulario en caso de que se haya
obtenido un alumno. Hemos usado el atributo value de los
campos input HTML para definir el valor que tendrá cada campo.
if (isset($_POST['submit'])) {
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'],
$config['db']['pass'], $config['db']['options']);
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
}
Ahora usaremos una sentencia SQL UPDATE para actualizar los valores del
alumno cuyo id se corresponde con el que estamos editando:
UPDATE alumnos
SET nombre = :nombre,
apellido = :apellido,
email = :email,
edad = :edad
updated_at = NOW()
WHERE id = :id
Tal y como ves, también actualizamos el campo updated_at con la fecha actual,
que obtenemos mediante la función NOW() de MySQL. Este sería el código PHP
que implementa la consulta anterior:
$alumno = [
"id" => $_GET['id'],
"nombre" => $_POST['nombre'],
"apellido" => $_POST['apellido'],
"email" => $_POST['email'],
"edad" => $_POST['edad']
];
$consulta = $conexion->prepare($consultaSQL);
$consulta->execute($alumno);
Y con esto ya habremos actualizado los datos del alumno.
<?php
include 'funciones.php';
$resultado = [
'error' => false,
'mensaje' => ''
];
if (!isset($_GET['id'])) {
$resultado['error'] = true;
$resultado['mensaje'] = 'El alumno no existe';
}
if (isset($_POST['submit'])) {
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'],
$config['db']['pass'], $config['db']['options']);
$alumno = [
"id" => $_GET['id'],
"nombre" => $_POST['nombre'],
"apellido" => $_POST['apellido'],
"email" => $_POST['email'],
"edad" => $_POST['edad']
];
$consulta = $conexion->prepare($consultaSQL);
$consulta->execute($alumno);
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
}
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$id = $_GET['id'];
$consultaSQL = "SELECT * FROM alumnos WHERE id =" . $id;
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
$alumno = $sentencia->fetch(PDO::FETCH_ASSOC);
if (!$alumno) {
$resultado['error'] = true;
$resultado['mensaje'] = 'No se ha encontrado el alumno';
}
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
?>
<?php
if ($resultado['error']) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger" role="alert">
<?= $resultado['mensaje'] ?>
</div>
</div>
</div>
</div>
<?php
}
?>
<?php
if (isset($_POST['submit']) && !$resultado['error']) {
?>
<div class="container mt-2">
<div class="row">
<div class="col-md-12">
<div class="alert alert-success" role="alert">
El alumno ha sido actualizado correctamente
</div>
</div>
</div>
</div>
<?php
}
?>
<?php
if (isset($alumno) && $alumno) {
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="mt-4">Editando el alumno <?=
escapar($alumno['nombre']) . ' ' . escapar($alumno['apellido'])
?></h2>
<hr>
<form method="post">
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" name="nombre" id="nombre"
value="<?= escapar($alumno['nombre']) ?>" class="form-control">
</div>
<div class="form-group">
<label for="apellido">Apellido</label>
<input type="text" name="apellido" id="apellido"
value="<?= escapar($alumno['apellido']) ?>" class="form-
control">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" id="email"
value="<?= escapar($alumno['email']) ?>" class="form-control">
</div>
<div class="form-group">
<label for="edad">Edad</label>
<input type="text" name="edad" id="edad" value="<?=
escapar($alumno['edad']) ?>" class="form-control">
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-
primary" value="Actualizar">
<a class="btn btn-primary" href="index.php">Regresar
al inicio</a>
</div>
</form>
</div>
</div>
</div>
<?php
}
?>
Vamos a agregar una página que nos permita borrar un alumno de la base de
datos. Para ello crea el archivo borrar.php en la carpeta raíz del proyecto con
este contenido:
Código PHP
<?php
include 'funciones.php';
$resultado = [
'error' => false,
'mensaje' => ''
];
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$id = $_GET['id'];
$consultaSQL = "DELETE FROM alumnos WHERE id =" . $id;
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
header('Location: /index.php');
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
?>
Código HTML
<?php
include 'funciones.php';
$resultado = [
'error' => false,
'mensaje' => ''
];
try {
$dsn = 'mysql:host=' . $config['db']['host'] . ';dbname=' .
$config['db']['name'];
$conexion = new PDO($dsn, $config['db']['user'], $config['db']
['pass'], $config['db']['options']);
$id = $_GET['id'];
$consultaSQL = "DELETE FROM alumnos WHERE id =" . $id;
$sentencia = $conexion->prepare($consultaSQL);
$sentencia->execute();
header('Location: /index.php');
} catch(PDOException $error) {
$resultado['error'] = true;
$resultado['mensaje'] = $error->getMessage();
}
?>
Protección CSRF
function csrf() {
session_start();
if (empty($_SESSION['csrf'])) {
if (function_exists('random_bytes')) {
$_SESSION['csrf'] = bin2hex(random_bytes(32));
} else if (function_exists('mcrypt_create_iv')) {
$_SESSION['csrf'] = bin2hex(mcrypt_create_iv(32,
MCRYPT_DEV_URANDOM));
} else {
$_SESSION['csrf'] =
bin2hex(openssl_random_pseudo_bytes(32));
}
}
}
Puede que no estén disponibles ciertas funciones en tu sistema, por lo que
intentamos generar el token de sesión con varias de las funciones más
habituales.
Luego, agrega este código tras incluir el archivo funciones.php en todas las
páginas de la aplicación.
include 'funciones.php';
csrf();
if (isset($_POST['submit']) && !hash_equals($_SESSION['csrf'],
$_POST['csrf'])) {
die();
}
Lo que hemos hecho es comprobar que el token CSRF de sesión sea igual que
el que agregaremos en el formulario. Si no es igual, finalizamos la ejecución de
la aplicación.
Conclusión
Esta aplicación todavía necesitaría más elementos para ser segura y poder ser
usada en producción, pero es una introducción que te resultará muy útil.