Tabla de contenido
- ¿Qué vamos a construir?
- Configuración del entorno
- Crear la base de datos
- Conexión con PDO
- Listar tareas (Read)
- Crear una tarea (Create)
- Completar una tarea (Update)
- Eliminar una tarea (Delete)
La mejor forma de consolidar lo aprendido sobre PHP y MySQL es construir algo real. En este tutorial vamos a crear una lista de tareas (to-do list) funcional desde cero, aplicando las cuatro operaciones básicas: Crear, Leer, Actualizar y Eliminar (CRUD).
¿Qué vamos a construir?
Una aplicación web sencilla donde puedas:
- Ver todas tus tareas pendientes
- Agregar nuevas tareas
- Marcar tareas como completadas
- Eliminar tareas
No usaremos frameworks, solo PHP puro, MySQL y HTML básico, para que entiendas exactamente qué hace cada línea.
Configuración del entorno
Necesitas:
- XAMPP (Apache + MySQL + PHP) — descarga desde apachefriends.org
- Un editor de código (recomiendo VS Code)
Una vez instalado XAMPP:
- Inicia Apache y MySQL desde el panel de control
- Crea una carpeta
lista-tareasdentro dehtdocs - Abre en el navegador
http://localhost/lista-tareas
Crear la base de datos
Abre phpMyAdmin en http://localhost/phpmyadmin y ejecuta:
CREATE DATABASE lista_tareas;
USE lista_tareas;
CREATE TABLE tareas (
id INT AUTO_INCREMENT PRIMARY KEY,
titulo VARCHAR(200) NOT NULL,
completada TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insertar algunas tareas de ejemplo
INSERT INTO tareas (titulo) VALUES
('Aprender PHP'),
('Practicar MySQL'),
('Crear un CRUD completo');
Conexión con PDO
Crea el archivo db.php:
<?php
$host = 'localhost';
$db = 'lista_tareas';
$user = 'root';
$pass = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
die("Error de conexión: " . $e->getMessage());
}
?>
Listar tareas (Read)
Crea index.php:
<?php
require 'db.php';
// Obtener todas las tareas ordenadas por fecha
$stmt = $pdo->query("SELECT * FROM tareas ORDER BY created_at DESC");
$tareas = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Lista de Tareas</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
.tarea { display: flex; align-items: center; gap: 10px; padding: 10px; border-bottom: 1px solid #eee; }
.completada span { text-decoration: line-through; color: #999; }
input[type="text"] { flex: 1; padding: 8px; font-size: 1rem; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 8px 16px; cursor: pointer; border: none; border-radius: 4px; }
.btn-agregar { background: #4CAF50; color: white; }
.btn-completar { background: #2196F3; color: white; font-size: 12px; }
.btn-eliminar { background: #f44336; color: white; font-size: 12px; }
</style>
</head>
<body>
<h1>Mi Lista de Tareas</h1>
<!-- Formulario para agregar tarea -->
<form method="POST" action="crear.php" style="display:flex; gap:10px; margin-bottom:20px;">
<input type="text" name="titulo" placeholder="Nueva tarea..." required>
<button type="submit" class="btn-agregar">Agregar</button>
</form>
<!-- Lista de tareas -->
<?php if (empty($tareas)): ?>
<p>No tienes tareas pendientes. ¡Añade una!</p>
<?php else: ?>
<?php foreach ($tareas as $tarea): ?>
<div class="tarea <?= $tarea['completada'] ? 'completada' : '' ?>">
<span><?= htmlspecialchars($tarea['titulo']) ?></span>
<div style="margin-left:auto; display:flex; gap:5px;">
<?php if (!$tarea['completada']): ?>
<form method="POST" action="completar.php">
<input type="hidden" name="id" value="<?= $tarea['id'] ?>">
<button type="submit" class="btn-completar">✓ Completar</button>
</form>
<?php endif; ?>
<form method="POST" action="eliminar.php">
<input type="hidden" name="id" value="<?= $tarea['id'] ?>">
<button type="submit" class="btn-eliminar">✗ Eliminar</button>
</form>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</body>
</html>
Crear una tarea (Create)
Crea crear.php:
<?php
require 'db.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['titulo'])) {
$titulo = trim($_POST['titulo']);
$stmt = $pdo->prepare("INSERT INTO tareas (titulo) VALUES (:titulo)");
$stmt->execute([':titulo' => $titulo]);
}
header("Location: index.php");
exit;
?>
Completar una tarea (Update)
Crea completar.php:
<?php
require 'db.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['id'])) {
$id = (int) $_POST['id'];
$stmt = $pdo->prepare("UPDATE tareas SET completada = 1 WHERE id = :id");
$stmt->execute([':id' => $id]);
}
header("Location: index.php");
exit;
?>
Eliminar una tarea (Delete)
Crea eliminar.php:
<?php
require 'db.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['id'])) {
$id = (int) $_POST['id'];
$stmt = $pdo->prepare("DELETE FROM tareas WHERE id = :id");
$stmt->execute([':id' => $id]);
}
header("Location: index.php");
exit;
?>
Con estos 5 archivos (db.php, index.php, crear.php, completar.php, eliminar.php) tienes una aplicación CRUD completamente funcional. Presta atención a estos puntos de seguridad:
- Usamos sentencias preparadas con
prepare()yexecute()para prevenir SQL Injection - Usamos
htmlspecialchars()al mostrar datos del usuario para prevenir XSS - Convertimos el ID a entero con
(int)antes de usarlo en queries
Esta es la base de cualquier aplicación web con PHP. A partir de aquí puedes agregar autenticación, validaciones más robustas, CSS con Bootstrap, o migrar a un framework como Laravel.