Ejercicio: Sistema de Diario Personal
Implementa un sistema completo de diario personal con PHP y MySQL
Learning Objectives
Database Connection
Learn to connect PHP to MySQL using MySQLi
Complete CRUD
Implement Create, Read, Update, Delete for records
File Manipulation
Dynamically generate PHP files
Search System
Implement search in content and metadata
Prerequisites
Current Status of the Demo Entry
File: diario_ejercicio.php EXISTS
Size: 36636 bytes
Last modified: 2026-09-10 16:12:04
Current content:
<?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>
Try the Diary System
Use the following controls to try the personal diary functions in real time:
Diary Control Panel
System Code Explained
1. Database Configuration
<?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: Improved extension for working with MySQL
utf8mb4: Full support for Unicode characters
Error Validation: Connection error handling
2. Function to Create Entries
<?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(): Automatically creates the file if it doesn't exist
nl2br(): Converts line breaks into <br> tags for HTML
mkdir(): Recursively creates directories if they don't exist
3. Form Processing
<?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(): Prevents XSS attacks by escaping special characters
header(): Redirects the user after processing the form
Validation: Verifies that the DB save was successful
4. Advanced Search System
<?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: Prevents SQL injections
Flexible Search: Searches across multiple fields
Regular Expressions: Detects searches by day number
Database Structure
Table: registros
| Field | Type | Description |
|---|---|---|
| id | INT AUTO_INCREMENT | Primary key |
| numero_dia | INT | Day's consecutive number |
| nombre | VARCHAR(100) | User's name |
| apellido | VARCHAR(100) | User's last name |
| observaciones | TEXT | Entry content |
| fecha_creacion | DATETIME | Creation date and time |
SQL script to create the table:
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)
);
Exercises to Practice
Exercise 1: Add Categories
Modify the system so each entry can have a category (Work, Personal, Study, etc.)
Hints:
- Add a "categoria" field in the registros table
- Modify the form to include a category select
- Update the crearArchivoDia() function to show the category
Exercise 2: Tagging System
Implement a tagging system where each entry can have multiple tags
Pistas:
- Create an "etiquetas" table and an intermediate "registro_etiquetas" table
- Use checkboxes in the form to select tags
- Implement a function to save the relationships
Exercise 3: Automatic Backup
Create a function to back up all entries into a ZIP file
Pistas:
- Research PHP's ZipArchive class
- Create a script that goes through all the files in the registros folder
- Add a button in the menu to download the backup
Complete Workflow
User fills out the form
The user enters name, last name and remarks for the day
PHP processes the data
The server sanitizes the data and determines the next day number
Saving to the Database
The data is stored in the registros table using MySQLi
File Generation
A PHP file is created with the entry formatted in HTML
Redirection to the menu
The user is redirected to the main menu with confirmation
Evaluation Criteria
✅ Basic Functionality (40%)
- Correctly create new entries
- List all entries in the menu
- Edit existing entries
- Delete entries with confirmation
✅ Database (30%)
- Correct connection to MySQL
- Use of prepared statements
- Connection error handling
- Appropriate table structure
✅ Security (20%)
- Input sanitization (htmlspecialchars)
- SQL injection prevention
- Form data validation
✅ UX/UI (10%)
- Intuitive and responsive interface
- Confirmation and error messages
- Clear navigation between sections