Ejercicio: Sistema de Diario Personal
Implementa un sistema completo de diario personal con PHP y MySQL
Objetivos de Aprendizaje
Conexión a Base de Datos
Aprender a conectar PHP con MySQL usando MySQLi
CRUD Completo
Implementar Create, Read, Update, Delete de registros
Manipulación de Archivos
Generar archivos PHP dinámicamente
Sistema de Búsqueda
Implementar búsqueda en contenido y metadatos
Requisitos Previos
Estado Actual de la Entrada de Demo
Archivo: diario_ejercicio.php EXISTE
Tamaño: 36636 bytes
Última modificación: 2026-09-10 16:12:04
Contenido actual:
<?php
// Incluir configuración
include_once '../database/config.php';
// Procesar el formulario - DEMO EDUCATIVA
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$opcion = $_POST['opcion'] ?? null;
$mensaje = $_POST['mensaje'] ?? '';
$nombre_archivo = $_POST['nombre_archivo'] ?? 'diario_ejercicio.php';
switch ($opcion) {
case 'crear':
$contenido = "<?php\n// Mi Diario Personal - Entrada de ejemplo\n\$fecha = date('Y-m-d H:i:s');\n\$nombre = 'Usuario Demo';\n?>\n<html>\n<head>\n <title><?php echo t('Ejercicio Diario de Programación'); ?> | ProgramandoWeb</title>\n</head>\n<body>\n <h1>Mi Diario Personal</h1>\n <p><strong>Fecha:</strong> <?php echo \$fecha; ?></p>\n <p><strong>Nombre:</strong> <?php echo \$nombre; ?></p>\n <div>\n <h2>Mis pensamientos de hoy:</h2>\n <p>Esta es una entrada de ejemplo en mi diario personal.</p>\n </div>\n</body>\n</html>";
file_put_contents($nombre_archivo, $contenido);
$resultado = t("✅ Archivo de diario creado correctamente");
break;
case 'editar':
$contenido_actual = file_exists($nombre_archivo) ? file_get_contents($nombre_archivo) : '';
$nuevo_contenido = preg_replace('/<p>Esta es una entrada.*?<\/p>/', "<p>$mensaje</p>", $contenido_actual);
file_put_contents($nombre_archivo, $nuevo_contenido);
$resultado = t("✅ Entrada del diario actualizada");
break;
case 'eliminar':
if (file_exists($nombre_archivo)) {
unlink($nombre_archivo);
$resultado = t("✅ Entrada del diario eliminada");
} else {
$resultado = t("⚠️ La entrada no existe");
}
break;
case 'leer':
if (file_exists($nombre_archivo)) {
$contenido = file_get_contents($nombre_archivo);
// Extraer solo el contenido visible
preg_match('/<p>([^<]*)<\/p>/', $contenido, $matches);
$resultado = $matches[1] ?? t("Contenido no encontrado");
} else {
$resultado = t("⚠️ La entrada no existe");
}
break;
}
}
// Verificar estado actual del archivo de demo
$archivo_existe = file_exists('diario_ejercicio.php');
$contenido_actual = $archivo_existe ? file_get_contents('diario_ejercicio.php') : '';
$userInfo = getUserInfo();
?>
<!DOCTYPE html>
<html lang="<?php echo currentLang(); ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="<?php echo t('Ejercicio práctico para crear un diario de programación. Pon en práctica tus habilidades de PHP, bases de datos y desarrollo web.'); ?>">
<meta name="keywords" content="ejercicio PHP, practica PHP, proyecto PHP, diario ejercicio programación">
<meta name="author" content="ProgramandoWeb - xlRaiko">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://programandoweb.site/ejemplos/diario_ejercicio">
<meta property="og:type" content="article">
<meta property="og:title" content="Ejercicio Diario de Programación | ProgramandoWeb">
<meta property="og:description" content="Ejercicio práctico para crear un diario de programación. Pon en práctica tus habilidades de PHP, bases de datos y desarrollo web.">
<meta property="og:url" content="https://programandoweb.site/ejemplos/diario_ejercicio">
<meta property="og:image" content="https://programandoweb.site/assets/images/bannerProgramandoWeb.png">
<meta property="og:site_name" content="ProgramandoWeb">
<meta property="og:locale" content="<?php echo currentLang() === 'en' ? 'en_US' : 'es_ES'; ?>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@programando_web">
<meta name="twitter:title" content="Ejercicio Diario de Programación | ProgramandoWeb">
<meta name="twitter:description" content="Ejercicio práctico para crear un diario de programación. Pon en práctica tus habilidades de PHP, bases de datos y desarrollo web.">
<meta name="twitter:image" content="https://programandoweb.site/assets/images/bannerProgramandoWeb.png">
<title><?php echo t('Ejercicio: Sistema de Diario Personal - Recursos de Programación'); ?></title>
<link rel="stylesheet" href="../template/css/header.css">
<link rel="stylesheet" href="../template/css/darktheme.css"> <!-- FOUC-FIX-DARKTHEME-CSS-LINK -->
<link rel="stylesheet" href="template/css/diario_ejercicio.css">
<link rel="icon" href="/favicon.ico">
</head>
<body>
<header class="header">
<div class="header-container">
<a href="../" class="logo-link">
<img src="../assets/images/logo.png" alt="Logo Programación" class="logo">
</a>
</div>
</header>
<?php include '../nav-bar.php'; ?>
<main class="main-content" id="main-content">
<div class="container">
<article class="tutorial-article">
<header class="article-header">
<h1 class="article-title">Ejercicio: Sistema de Diario Personal</h1>
<p class="article-subtitle">Implementa un sistema completo de diario personal con PHP y MySQL</p>
<div class="exercise-info">
<div class="difficulty">
<span class="badge intermediate"><?php echo t('Nivel Intermedio'); ?></span>
<span class="badge time-estimate">⏱️ 2-3 <?php echo t('horas'); ?></span>
</div>
</div>
</br>
<div>
<a href="descargas/Diario/diarioejercicio.zip" download="diarioejercicio.zip" class="download-btn">
<i class="fas fa-download"></i> <?php echo t('Descargar Código Ejemplo'); ?>
</a>
</div>
</header>
<!-- Objetivos del ejercicio -->
<section class="content-section">
<h2><i class="fas fa-bullseye"></i> <?php echo t('Objetivos de Aprendizaje'); ?></h2>
<div class="learning-objectives">
<div class="objective">
<i class="fas fa-database"></i>
<h3><?php echo t('Conexión a Base de Datos'); ?></h3>
<p><?php echo t('Aprender a conectar PHP con MySQL usando MySQLi'); ?></p>
</div>
<div class="objective">
<i class="fas fa-code"></i>
<h3><?php echo t('CRUD Completo'); ?></h3>
<p><?php echo t('Implementar Create, Read, Update, Delete de registros'); ?></p>
</div>
<div class="objective">
<i class="fas fa-file-code"></i>
<h3><?php echo t('Manipulación de Archivos'); ?></h3>
<p><?php echo t('Generar archivos PHP dinámicamente'); ?></p>
</div>
<div class="objective">
<i class="fas fa-search"></i>
<h3><?php echo t('Sistema de Búsqueda'); ?></h3>
<p><?php echo t('Implementar búsqueda en contenido y metadatos'); ?></p>
</div>
</div>
</section>
<!-- Requisitos previos -->
<section class="content-section">
<h2><i class="fas fa-clipboard-check"></i> <?php echo t('Requisitos Previos'); ?></h2>
<div class="prerequisites">
<div class="prerequisite-item">
<i class="fas fa-check-circle"></i>
<span><?php echo t('Conocimientos básicos de PHP'); ?></span>
</div>
<div class="prerequisite-item">
<i class="fas fa-check-circle"></i>
<span><?php echo t('Conceptos básicos de MySQL'); ?></span>
</div>
<div class="prerequisite-item">
<i class="fas fa-check-circle"></i>
<span><?php echo t('Entender HTML y CSS'); ?></span>
</div>
<div class="prerequisite-item">
<i class="fas fa-check-circle"></i>
<span><?php echo t('Servidor local (XAMPP, WAMP, etc.)'); ?></span>
</div>
</div>
</section>
<!-- Estado actual del archivo de demo -->
<section class="content-section">
<h2><i class="fas fa-info-circle"></i> <?php echo t('Estado Actual de la Entrada de Demo'); ?></h2>
<div class="estado-archivo">
<div class="archivo-info">
<p><strong><?php echo t('Archivo:'); ?></strong>
<span class="badge <?php echo $archivo_existe ? 'existe' : 'no-existe'; ?>">
<i class="fas <?php echo $archivo_existe ? 'fa-check-circle' : 'fa-times-circle'; ?>"></i>
diario_ejercicio.php <?php echo $archivo_existe ? t('EXISTE') : t('NO EXISTE'); ?>
</span>
</p>
<?php if ($archivo_existe): ?>
<p><strong><?php echo t('Tamaño:'); ?></strong> <?php echo filesize('diario_ejercicio.php'); ?> bytes</p>
<p><strong><?php echo t('Última modificación:'); ?></strong> <?php echo date('Y-m-d H:i:s', filemtime('diario_ejercicio.php')); ?></p>
<?php if (!empty($contenido_actual)): ?>
<p><strong><?php echo t('Contenido actual:'); ?></strong></p>
<div class="contenido-archivo">
<pre><?php echo htmlspecialchars($contenido_actual); ?></pre>
</div>
<?php else: ?>
<p><strong><?php echo t('Contenido actual:'); ?></strong> <em><?php echo t('El archivo está vacío'); ?></em></p>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</section>
<!-- Resultado de la última acción -->
<?php if (isset($resultado)): ?>
<section class="content-section">
<h2><i class="fas fa-bell"></i> <?php echo t('Resultado de la Última Acción'); ?></h2>
<div class="resultado-accion">
<div class="mensaje-resultado">
<i class="fas fa-info-circle"></i>
<?php echo $resultado; ?>
</div>
</div>
</section>
<?php endif; ?>
<!-- Demo interactivo -->
<section class="content-section">
<h2><i class="fas fa-play-circle"></i> <?php echo t('Prueba el Sistema de Diario'); ?></h2>
<p><?php echo t('Usa los siguientes controles para probar las funciones del diario personal en tiempo real:'); ?></p>
<div class="live-example">
<div class="form-container">
<h3><?php echo t('Panel de Control del Diario'); ?></h3>
<form method="POST" class="form-diario">
<?php echo csrf_field(); ?>
<?php echo honeypot_field(); ?>
<div class="botones-accion">
<button type="submit" name="opcion" value="crear" class="btn btn-crear">
<i class="fas fa-file"></i> <?php echo t('Crear Entrada'); ?>
</button>
<button type="submit" name="opcion" value="leer" class="btn btn-leer">
<i class="fas fa-eye"></i> <?php echo t('Leer Entrada'); ?>
</button>
<button type="submit" name="opcion" value="eliminar" class="btn btn-eliminar">
<i class="fas fa-trash"></i> <?php echo t('Eliminar Entrada'); ?>
</button>
</div>
<div class="form-group">
<label for="mensaje">
<i class="fas fa-edit"></i> <?php echo t('Modificar contenido del diario:'); ?>
</label>
<textarea id="mensaje" name="mensaje" rows="4"
placeholder="<?php echo t('Escribe el nuevo contenido para tu entrada de diario...'); ?>"><?php echo t('Hoy fue un día increíble. Aprendí mucho sobre PHP y la manipulación de archivos.'); ?></textarea>
<button type="submit" name="opcion" value="editar" class="submit-btn">
<i class="fas fa-pencil-alt"></i> <?php echo t('Actualizar Entrada'); ?>
</button>
</div>
<div class="form-group">
<label for="nombre_archivo">
<i class="fas fa-file-signature"></i> <?php echo t('Nombre del archivo:'); ?>
</label>
<input type="text" id="nombre_archivo" name="nombre_archivo" value="diario_ejercicio.php"
placeholder="<?php echo t('Nombre del archivo de diario'); ?>">
</div>
</form>
</div>
</div>
</section>
<!-- Explicación del código principal -->
<section class="content-section">
<h2><i class="fas fa-code"></i> <?php echo t('Código del Sistema Explicado'); ?></h2>
<div class="code-explanation">
<div class="code-section">
<h3>1. <?php echo t('Configuración de la Base de Datos'); ?></h3>
<div class="code-example">
<pre><code><?php
// config.php - <?php echo t('Configuración de conexión a MySQL'); ?>
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'diario');
function conectarDB() {
$conexion = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($conexion->connect_error) {
die("Error de conexión: " . $conexion->connect_error);
}
$conexion->set_charset("utf8mb4");
return $conexion;
}
?></code></pre>
</div>
<div class="explanation">
<p><strong>MySQLi:</strong> <?php echo t('Extensión mejorada para trabajar con MySQL'); ?></p>
<p><strong>utf8mb4:</strong> <?php echo t('Soporte completo para caracteres Unicode'); ?></p>
<p><strong><?php echo t('Validación de errores:'); ?></strong> <?php echo t('Manejo de errores de conexión'); ?></p>
</div>
</div>
<div class="code-section">
<h3>2. <?php echo t('Función para Crear Entradas'); ?></h3>
<div class="code-example">
<pre><code><?php
function crearArchivoDia($numero_dia, $nombre, $apellido, $observaciones, $fecha) {
$contenido_archivo = '<html>
<head>
<title>Día '.$numero_dia.'</title>
<link rel="stylesheet" href="../template/css/estilos.css">
</head>
<body>
<div class="diario-container">
<div class="diario-pagina">
<header class="encabezado-diario">
<h1 class="titulo-diario">Día '.$numero_dia.'</h1>
<p class="subtitulo-diario">'.date("d \\d\\e F, Y", strtotime($fecha)).'</p>
<a href="../menu.php" class="boton-volver">← Volver al Menú</a>
</header>
<main class="contenido-diario">
<section class="entrada-completa">
<div class="info-entrada">
<div class="campo-info">
<label>Nombre:</label>
<span>'.$nombre.' '.$apellido.'</span>
</div>
<div class="campo-info">
<label>Fecha:</label>
<span>'.date('d/m/Y H:i:s', strtotime($fecha)).'</span>
</div>
</div>
<div class="contenido-entrada">
<h3>Reflexiones del día</h3>
<div class="texto-entrada">
'.nl2br($observaciones).'
</div>
</div>
</section>
</main>
</div>
</div>
</body>
</html>';
$carpeta_registros = "registros";
if (!file_exists($carpeta_registros)) {
mkdir($carpeta_registros, 0777, true);
}
$nombre_archivo = "$carpeta_registros/Dia $numero_dia.php";
file_put_contents($nombre_archivo, $contenido_archivo);
}
?></code></pre>
</div>
<div class="explanation">
<p><strong>file_put_contents():</strong> <?php echo t('Crea el archivo automáticamente si no existe'); ?></p>
<p><strong>nl2br():</strong> <?php echo t('Convierte saltos de línea en etiquetas <br> para HTML'); ?></p>
<p><strong>mkdir():</strong> <?php echo t('Crea directorios recursivamente si no existen'); ?></p>
</div>
</div>
<div class="code-section">
<h3>3. <?php echo t('Procesamiento del Formulario'); ?></h3>
<div class="code-example">
<pre><code><?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// <?php echo t('Sanitizar entradas para prevenir XSS'); ?>
$nombre = htmlspecialchars($_POST['nombre']);
$apellido = htmlspecialchars($_POST['apellido']);
$observaciones = htmlspecialchars($_POST['observaciones']);
$fecha = date('Y-m-d H:i:s');
// <?php echo t('Obtener próximo número de día desde la base de datos'); ?>
$numero_dia = obtenerProximoDia();
// <?php echo t('Guardar en base de datos'); ?>
if (guardarEntradaDB($numero_dia, $nombre, $apellido, $observaciones, $fecha)) {
// <?php echo t('Crear archivo físico'); ?>
crearArchivoDia($numero_dia, $nombre, $apellido, $observaciones, $fecha);
// <?php echo t('Redirigir al menú con confirmación'); ?>
header("Location: menu.php?creado=$numero_dia");
exit();
} else {
\$error = t("Error al guardar la entrada en la base de datos");
}
}
?></code></pre>
</div>
<div class="explanation">
<p><strong>htmlspecialchars():</strong> <?php echo t('Previene ataques XSS escapando caracteres especiales'); ?></p>
<p><strong>header():</strong> <?php echo t('Redirige al usuario después de procesar el formulario'); ?></p>
<p><strong><?php echo t('Validación:'); ?></strong> <?php echo t('Verifica que el guardado en BD fue exitoso'); ?></p>
</div>
</div>
<div class="code-section">
<h3>4. <?php echo t('Sistema de Búsqueda Avanzado'); ?></h3>
<div class="code-example">
<pre><code><?php
function buscarEntradas($termino) {
$conexion = conectarDB();
// <?php echo t('Extraer número si se busca "Día X"'); ?>
$numero_dia = null;
if (preg_match('/(\d+)/', $termino, $matches)) {
$numero_dia = intval($matches[1]);
}
$termino_limpio = trim(preg_replace('/día\s*/i', '', $termino));
$termino_like = "%" . $termino_limpio . "%";
if ($numero_dia !== null) {
// <?php echo t('Búsqueda incluyendo número de día'); ?>
$stmt = $conexion->prepare("SELECT numero_dia, fecha_creacion, nombre, apellido, observaciones
FROM registros
WHERE nombre LIKE ?
OR apellido LIKE ?
OR observaciones LIKE ?
OR numero_dia = ?
ORDER BY numero_dia DESC");
$stmt->bind_param("sssi", $termino_like, $termino_like, $termino_like, $numero_dia);
} else {
// <?php echo t('Búsqueda solo por texto'); ?>
$stmt = $conexion->prepare("SELECT numero_dia, fecha_creacion, nombre, apellido, observaciones
FROM registros
WHERE nombre LIKE ?
OR apellido LIKE ?
OR observaciones LIKE ?
ORDER BY numero_dia DESC");
$stmt->bind_param("sss", $termino_like, $termino_like, $termino_like);
}
$stmt->execute();
return $stmt->get_result();
}
?></code></pre>
</div>
<div class="explanation">
<p><strong>Prepared Statements:</strong> <?php echo t('Previene inyecciones SQL'); ?></p>
<p><strong><?php echo t('Búsqueda flexible:'); ?></strong> <?php echo t('Busca en múltiples campos'); ?></p>
<p><strong><?php echo t('Expresiones regulares:'); ?></strong> <?php echo t('Detecta búsquedas por número de día'); ?></p>
</div>
</div>
</div>
</section>
<!-- Estructura de la base de datos -->
<section class="content-section">
<h2><i class="fas fa-database"></i> <?php echo t('Estructura de la Base de Datos'); ?></h2>
<div class="database-structure">
<div class="table-schema">
<h3><?php echo t('Tabla:'); ?> registros</h3>
<table class="schema-table">
<thead>
<tr>
<th><?php echo t('Campo'); ?></th>
<th><?php echo t('Tipo'); ?></th>
<th><?php echo t('Descripción'); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>INT AUTO_INCREMENT</td>
<td><?php echo t('Clave primaria'); ?></td>
</tr>
<tr>
<td>numero_dia</td>
<td>INT</td>
<td><?php echo t('Número consecutivo del día'); ?></td>
</tr>
<tr>
<td>nombre</td>
<td>VARCHAR(100)</td>
<td><?php echo t('Nombre del usuario'); ?></td>
</tr>
<tr>
<td>apellido</td>
<td>VARCHAR(100)</td>
<td><?php echo t('Apellido del usuario'); ?></td>
</tr>
<tr>
<td>observaciones</td>
<td>TEXT</td>
<td><?php echo t('Contenido de la entrada'); ?></td>
</tr>
<tr>
<td>fecha_creacion</td>
<td>DATETIME</td>
<td><?php echo t('Fecha y hora de creación'); ?></td>
</tr>
</tbody>
</table>
</div>
<div class="sql-code">
<h4><?php echo t('Script SQL para crear la tabla:'); ?></h4>
<pre><code>CREATE TABLE registros (
id INT AUTO_INCREMENT PRIMARY KEY,
numero_dia INT NOT NULL,
nombre VARCHAR(100) NOT NULL,
apellido VARCHAR(100) NOT NULL,
observaciones TEXT NOT NULL,
fecha_creacion DATETIME NOT NULL,
UNIQUE KEY unique_numero_dia (numero_dia)
);</code></pre>
</div>
</div>
</section>
<!-- Ejercicios prácticos -->
<section class="content-section">
<h2><i class="fas fa-tasks"></i> <?php echo t('Ejercicios para Practicar'); ?></h2>
<div class="steps">
<div class="step">
<h3><?php echo t('Ejercicio'); ?> 1: <?php echo t('Añadir Categorías'); ?></h3>
<p><?php echo t('Modifica el sistema para que cada entrada pueda tener una categoría (Trabajo, Personal, Estudio, etc.)'); ?></p>
<div class="exercise-hint">
<h5><?php echo t('Pistas:'); ?></h5>
<ul>
<li><?php echo t('Añade un campo "categoria" en la tabla registros'); ?></li>
<li><?php echo t('Modifica el formulario para incluir un select de categorías'); ?></li>
<li><?php echo t('Actualiza la función crearArchivoDia() para mostrar la categoría'); ?></li>
</ul>
</div>
</div>
<div class="step">
<h3><?php echo t('Ejercicio'); ?> 2: <?php echo t('Sistema de Etiquetas'); ?></h3>
<p><?php echo t('Implementa un sistema de etiquetas donde cada entrada pueda tener múltiples etiquetas'); ?></p>
<div class="exercise-hint">
<h5>Pistas:</h5>
<ul>
<li><?php echo t('Crea una tabla "etiquetas" y una tabla intermedia "registro_etiquetas"'); ?></li>
<li><?php echo t('Usa checkboxes en el formulario para seleccionar etiquetas'); ?></li>
<li><?php echo t('Implementa una función para guardar las relaciones'); ?></li>
</ul>
</div>
</div>
<div class="step">
<h3><?php echo t('Ejercicio'); ?> 3: <?php echo t('Backup Automático'); ?></h3>
<p><?php echo t('Crea una función para hacer backup de todas las entradas en un archivo ZIP'); ?></p>
<div class="exercise-hint">
<h5>Pistas:</h5>
<ul>
<li><?php echo t('Investiga la clase ZipArchive de PHP'); ?></li>
<li><?php echo t('Crea un script que recorra todos los archivos de la carpeta registros'); ?></li>
<li><?php echo t('Añade un botón en el menú para descargar el backup'); ?></li>
</ul>
</div>
</div>
</div>
</section>
<!-- Flujo de trabajo completo -->
<section class="content-section">
<h2><i class="fas fa-project-diagram"></i> <?php echo t('Flujo de Trabajo Completo'); ?></h2>
<div class="workflow">
<div class="workflow-step">
<div class="step-number">1</div>
<h3><?php echo t('Usuario completa formulario'); ?></h3>
<p><?php echo t('El usuario ingresa nombre, apellido y observaciones del día'); ?></p>
</div>
<div class="workflow-step">
<div class="step-number">2</div>
<h3>PHP <?php echo t('procesa los datos'); ?></h3>
<p><?php echo t('El servidor sanitiza los datos y determina el próximo número de día'); ?></p>
</div>
<div class="workflow-step">
<div class="step-number">3</div>
<h3><?php echo t('Guardado en Base de Datos'); ?></h3>
<p><?php echo t('Los datos se almacenan en la tabla registros usando MySQLi'); ?></p>
</div>
<div class="workflow-step">
<div class="step-number">4</div>
<h3><?php echo t('Generación de Archivo'); ?></h3>
<p><?php echo t('Se crea un archivo PHP con la entrada formateada en HTML'); ?></p>
</div>
<div class="workflow-step">
<div class="step-number">5</div>
<h3><?php echo t('Redirección al menú'); ?></h3>
<p><?php echo t('El usuario es redirigido al menú principal con confirmación'); ?></p>
</div>
</div>
</section>
<!-- Evaluación -->
<section class="content-section">
<h2><i class="fas fa-graduation-cap"></i> <?php echo t('Criterios de Evaluación'); ?></h2>
<div class="evaluation-criteria">
<div class="criterion">
<h3>✅ <?php echo t('Funcionalidad Básica (40%)'); ?></h3>
<ul>
<li><?php echo t('Crear nuevas entradas correctamente'); ?></li>
<li><?php echo t('Listar todas las entradas en el menú'); ?></li>
<li><?php echo t('Editar entradas existentes'); ?></li>
<li><?php echo t('Eliminar entradas con confirmación'); ?></li>
</ul>
</div>
<div class="criterion">
<h3>✅ <?php echo t('Base de Datos (30%)'); ?></h3>
<ul>
<li><?php echo t('Conexión correcta a MySQL'); ?></li>
<li><?php echo t('Uso de prepared statements'); ?></li>
<li><?php echo t('Manejo de errores de conexión'); ?></li>
<li><?php echo t('Estructura de tabla adecuada'); ?></li>
</ul>
</div>
<div class="criterion">
<h3>✅ <?php echo t('Seguridad (20%)'); ?></h3>
<ul>
<li><?php echo t('Sanitización de entradas (htmlspecialchars)'); ?></li>
<li><?php echo t('Prevención de SQL injection'); ?></li>
<li><?php echo t('Validación de datos del formulario'); ?></li>
</ul>
</div>
<div class="criterion">
<h3>✅ UX/UI (10%)</h3>
<ul>
<li><?php echo t('Interfaz intuitiva y responsive'); ?></li>
<li><?php echo t('Mensajes de confirmación y error'); ?></li>
<li><?php echo t('Navegación clara entre secciones'); ?></li>
</ul>
</div>
</div>
</section>
<!-- Recursos adicionales -->
<section class="content-section">
<h2><i class="fas fa-book"></i> <?php echo t('Recursos Adicionales'); ?></h2>
<div class="resources">
<a href="https://www.php.net/manual/es/book.mysqli.php" class="resource-link" target="_blank">
<i class="fas fa-external-link-alt"></i>
<span><?php echo t('Documentación Oficial de MySQLi'); ?></span>
</a>
<a href="https://www.php.net/manual/es/function.file-put-contents.php" class="resource-link" target="_blank">
<i class="fas fa-external-link-alt"></i>
<span><?php echo t('Función'); ?> file_put_contents()</span>
</a>
<a href="https://www.w3schools.com/php/php_form_validation.asp" class="resource-link" target="_blank">
<i class="fas fa-external-link-alt"></i>
<span><?php echo t('Validación de Formularios PHP'); ?></span>
</a>
</div>
</section>
</article>
</div>
</main>
<?php include '../footer.php'; ?>
<script src="../template/js/header.js"></script>
<script src="template/js/diario_ejercicio.js"></script>
</body>
</html>
Prueba el Sistema de Diario
Usa los siguientes controles para probar las funciones del diario personal en tiempo real:
Panel de Control del Diario
Código del Sistema Explicado
1. Configuración de la Base de Datos
<?php
// config.php - Configuración de conexión a MySQLdefine('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'diario');
function conectarDB() {
$conexion = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($conexion->connect_error) {
die("Error de conexión: " . $conexion->connect_error);
}
$conexion->set_charset("utf8mb4");
return $conexion;
}
?>
MySQLi: Extensión mejorada para trabajar con MySQL
utf8mb4: Soporte completo para caracteres Unicode
Validación de errores: Manejo de errores de conexión
2. Función para Crear Entradas
<?php
function crearArchivoDia($numero_dia, $nombre, $apellido, $observaciones, $fecha) {
$contenido_archivo = '<html>
<head>
<title>Día '.$numero_dia.'</title>
<link rel="stylesheet" href="../template/css/estilos.css">
</head>
<body>
<div class="diario-container">
<div class="diario-pagina">
<header class="encabezado-diario">
<h1 class="titulo-diario">Día '.$numero_dia.'</h1>
<p class="subtitulo-diario">'.date("d \\d\\e F, Y", strtotime($fecha)).'</p>
<a href="../menu.php" class="boton-volver">← Volver al Menú</a>
</header>
<main class="contenido-diario">
<section class="entrada-completa">
<div class="info-entrada">
<div class="campo-info">
<label>Nombre:</label>
<span>'.$nombre.' '.$apellido.'</span>
</div>
<div class="campo-info">
<label>Fecha:</label>
<span>'.date('d/m/Y H:i:s', strtotime($fecha)).'</span>
</div>
</div>
<div class="contenido-entrada">
<h3>Reflexiones del día</h3>
<div class="texto-entrada">
'.nl2br($observaciones).'
</div>
</div>
</section>
</main>
</div>
</div>
</body>
</html>';
$carpeta_registros = "registros";
if (!file_exists($carpeta_registros)) {
mkdir($carpeta_registros, 0777, true);
}
$nombre_archivo = "$carpeta_registros/Dia $numero_dia.php";
file_put_contents($nombre_archivo, $contenido_archivo);
}
?>
file_put_contents(): Crea el archivo automáticamente si no existe
nl2br(): Convierte saltos de línea en etiquetas <br> para HTML
mkdir(): Crea directorios recursivamente si no existen
3. Procesamiento del Formulario
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// Sanitizar entradas para prevenir XSS $nombre = htmlspecialchars($_POST['nombre']);
$apellido = htmlspecialchars($_POST['apellido']);
$observaciones = htmlspecialchars($_POST['observaciones']);
$fecha = date('Y-m-d H:i:s');
// Obtener próximo número de día desde la base de datos $numero_dia = obtenerProximoDia();
// Guardar en base de datos if (guardarEntradaDB($numero_dia, $nombre, $apellido, $observaciones, $fecha)) {
// Crear archivo físico crearArchivoDia($numero_dia, $nombre, $apellido, $observaciones, $fecha);
// Redirigir al menú con confirmación header("Location: menu.php?creado=$numero_dia");
exit();
} else {
\$error = t("Error al guardar la entrada en la base de datos");
}
}
?>
htmlspecialchars(): Previene ataques XSS escapando caracteres especiales
header(): Redirige al usuario después de procesar el formulario
Validación: Verifica que el guardado en BD fue exitoso
4. Sistema de Búsqueda Avanzado
<?php
function buscarEntradas($termino) {
$conexion = conectarDB();
// Extraer número si se busca "Día X" $numero_dia = null;
if (preg_match('/(\d+)/', $termino, $matches)) {
$numero_dia = intval($matches[1]);
}
$termino_limpio = trim(preg_replace('/día\s*/i', '', $termino));
$termino_like = "%" . $termino_limpio . "%";
if ($numero_dia !== null) {
// Búsqueda incluyendo número de día $stmt = $conexion->prepare("SELECT numero_dia, fecha_creacion, nombre, apellido, observaciones
FROM registros
WHERE nombre LIKE ?
OR apellido LIKE ?
OR observaciones LIKE ?
OR numero_dia = ?
ORDER BY numero_dia DESC");
$stmt->bind_param("sssi", $termino_like, $termino_like, $termino_like, $numero_dia);
} else {
// Búsqueda solo por texto $stmt = $conexion->prepare("SELECT numero_dia, fecha_creacion, nombre, apellido, observaciones
FROM registros
WHERE nombre LIKE ?
OR apellido LIKE ?
OR observaciones LIKE ?
ORDER BY numero_dia DESC");
$stmt->bind_param("sss", $termino_like, $termino_like, $termino_like);
}
$stmt->execute();
return $stmt->get_result();
}
?>
Prepared Statements: Previene inyecciones SQL
Búsqueda flexible: Busca en múltiples campos
Expresiones regulares: Detecta búsquedas por número de día
Estructura de la Base de Datos
Tabla: registros
| Campo | Tipo | Descripción |
|---|---|---|
| id | INT AUTO_INCREMENT | Clave primaria |
| numero_dia | INT | Número consecutivo del día |
| nombre | VARCHAR(100) | Nombre del usuario |
| apellido | VARCHAR(100) | Apellido del usuario |
| observaciones | TEXT | Contenido de la entrada |
| fecha_creacion | DATETIME | Fecha y hora de creación |
Script SQL para crear la tabla:
CREATE TABLE registros (
id INT AUTO_INCREMENT PRIMARY KEY,
numero_dia INT NOT NULL,
nombre VARCHAR(100) NOT NULL,
apellido VARCHAR(100) NOT NULL,
observaciones TEXT NOT NULL,
fecha_creacion DATETIME NOT NULL,
UNIQUE KEY unique_numero_dia (numero_dia)
);
Ejercicios para Practicar
Ejercicio 1: Añadir Categorías
Modifica el sistema para que cada entrada pueda tener una categoría (Trabajo, Personal, Estudio, etc.)
Pistas:
- Añade un campo "categoria" en la tabla registros
- Modifica el formulario para incluir un select de categorías
- Actualiza la función crearArchivoDia() para mostrar la categoría
Ejercicio 2: Sistema de Etiquetas
Implementa un sistema de etiquetas donde cada entrada pueda tener múltiples etiquetas
Pistas:
- Crea una tabla "etiquetas" y una tabla intermedia "registro_etiquetas"
- Usa checkboxes en el formulario para seleccionar etiquetas
- Implementa una función para guardar las relaciones
Ejercicio 3: Backup Automático
Crea una función para hacer backup de todas las entradas en un archivo ZIP
Pistas:
- Investiga la clase ZipArchive de PHP
- Crea un script que recorra todos los archivos de la carpeta registros
- Añade un botón en el menú para descargar el backup
Flujo de Trabajo Completo
Usuario completa formulario
El usuario ingresa nombre, apellido y observaciones del día
PHP procesa los datos
El servidor sanitiza los datos y determina el próximo número de día
Guardado en Base de Datos
Los datos se almacenan en la tabla registros usando MySQLi
Generación de Archivo
Se crea un archivo PHP con la entrada formateada en HTML
Redirección al menú
El usuario es redirigido al menú principal con confirmación
Criterios de Evaluación
✅ Funcionalidad Básica (40%)
- Crear nuevas entradas correctamente
- Listar todas las entradas en el menú
- Editar entradas existentes
- Eliminar entradas con confirmación
✅ Base de Datos (30%)
- Conexión correcta a MySQL
- Uso de prepared statements
- Manejo de errores de conexión
- Estructura de tabla adecuada
✅ Seguridad (20%)
- Sanitización de entradas (htmlspecialchars)
- Prevención de SQL injection
- Validación de datos del formulario
✅ UX/UI (10%)
- Interfaz intuitiva y responsive
- Mensajes de confirmación y error
- Navegación clara entre secciones