UT3 · Boletín de prácticas: formularios, estructuras de control, arrays y funciones

Este boletín reúne las prácticas de la UT3 · Sintaxis Avanzada de PHP. Están ordenadas de menor a mayor dificultad en tres niveles. Hazlas en orden: cada práctica usa lo que has aprendido en las anteriores.

Para resolverlo usa la Guía de resolución.

Nivel Prácticas Qué trabajas
🟢 Básico P01 – P04 Envío y recogida de formularios, condicionales y funciones sencillas
🟡 Intermedio P05 – P09 Bucles (también anidados), arrays asociativos, formularios que conservan los datos y expresiones regulares
🔴 Avanzado P10 – P12 Funciones propias, filtrado de arrays, require_once y formularios generados desde datos

Resultados de aprendizaje: RA2 (sentencias integradas en HTML) y RA3 (estructuras de programación y formularios).

Requisitos comunes a todas las prácticas

  • Entorno: Herd (Windows/macOS) o Lerd (Xubuntu) con PHP 8.4.
  • Estilos: Bulma 1.x y Font Awesome por CDN. No hace falta JavaScript.
  • Seguridad mínima: todo lo que muestres y venga del usuario pasa por htmlspecialchars(). Los números se validan con filter_input() o filter_var().
  • Código comentado (RA3 – CE g): explica qué hace cada bloque.
  • Nombres de fichero: ut03p01.php, ut03p02.php… En las prácticas de dos páginas usa ut03p01.html (formulario) y ut03p01-res.php (resultado).
  • Git: un commit por práctica terminada, con un mensaje del tipo P03: calculadora letra DNI.

Plantillas para empezar

Descarga plantillas-ut03.zip. Tiene un fichero por práctica con el HTML y los estilos ya hechos, y comentarios TODO donde tienes que escribir el código PHP. Incluye también datos.php para la P11.

Descomprímelo en la carpeta de tu servidor local (Herd o Lerd) y renombra cada fichero a tu gusto si lo necesitas, pero mantén los atributos name de los formularios.

¿No sabes por dónde empezar?

Sigue la guía para resolver las prácticas: explica un método paso a paso, los patrones que se repiten y una ficha por práctica con la estrategia y los casos de prueba.


🟢 Nivel básico

P01 · Formulario de búsqueda de canciones

RA/CE: RA2 – CE c), e) · RA3 – CE e), f) · Duración: 1 h

Crea un formulario HTML (ut03p01.html) para buscar canciones. Debe enviar por POST a una página PHP (ut03p01-res.php) estos campos:

  • Texto a buscar (text, obligatorio).
  • Buscar en (radio): Títulos de canción, Nombres de álbum o Ambos campos (marcado por defecto).
  • Género musical (select): Todos, Acústica, Banda sonora, Blues, Electrónica, Folk, Jazz, New Age, Pop y Rock.

La página de resultados muestra lo que ha introducido el usuario y un botón Nueva búsqueda que vuelve al formulario. Si alguien abre ut03p01-res.php directamente, sin enviar el formulario, redirígelo al formulario con header('Location: …').

Pista

El radio envía un valor interno (cancion, album, ambos). Muestra al usuario un texto legible con una expresión match.


P02 · Catálogo de controles de formulario

RA/CE: RA3 – CE e), f) · Duración: 1,5 h

Crea un formulario (ut03p02.php) que tenga todos los tipos de control y una página (ut03p02-res.php) que muestre en una tabla lo que llega de cada uno:

Control Ejemplo
hidden Un token fijo, por ejemplo XYZ987654321
text Cadena a buscar, con un valor por defecto
radio Sexo: Mujer / Hombre
checkbox (varios) Extras: Garaje, Piscina, Jardín → name="extras[]"
file Un fichero cualquiera: muestra su nombre, tamaño y tipo
password Contraseña: muéstrala enmascarada (•••)
select simple Color
select multiple Idiomas → name="idiomas[]"
textarea Comentario: respeta los saltos de línea con nl2br()

Fíjate

  • Si no se marca ningún checkbox, la clave no existe en $_POST. Usa ?? [].
  • Para enviar ficheros, el formulario necesita enctype="multipart/form-data".

P03 · Calculadora de la letra del DNI

RA/CE: RA2 – CE g) · RA3 – CE a), d), f) · Duración: 1 h

Crea una página autoprocesada (el formulario se envía a sí misma) que pida el número de un DNI y muestre su letra.

  • Escribe la función calcularLetraDNI(int $numero): string. La letra es la posición numero % 23 de la cadena TRWAGMYFPDXBNJZSQVHLCKE.
  • Valida que el dato sea un entero positivo. Si no lo es, muestra un aviso de error.
  • Muestra el DNI con 8 cifras, rellenando con ceros a la izquierda (str_pad). Por ejemplo, 12345678 → 12345678Z.
  • Añade un botón Borrar que recargue la página vacía.

Cuaderno

Antes de programar, haz a mano el cálculo para tu propio DNI y anota el resto de la división y la letra que sale.


P04 · Ecuación de segundo grado

RA/CE: RA2 – CE g) · RA3 – CE a), f) · Duración: 1 h

Crea una página autoprocesada que resuelva a·x² + b·x + c = 0 a partir de los tres coeficientes.

  • Valida que los tres sean números (FILTER_VALIDATE_FLOAT) y que a ≠ 0.
  • Calcula el discriminante b² − 4ac:
    • Si es negativo, indica que no hay soluciones reales.
    • Si es cero o positivo, muestra x₁ y x₂ con dos decimales.
  • El formulario conserva los valores introducidos después de enviarlo.

Ejemplo: a = 1, b = −5, c = 6 → x₁ = 3,00 y x₂ = 2,00.


🟡 Nivel intermedio

P05 · Dibuja un triángulo

RA/CE: RA3 – CE b), f) · Duración: 1 h

Pide una altura (de 1 a 30) y un carácter (por defecto *) y dibuja un triángulo rectángulo con dos bucles anidados:

*
* *
* * *
* * * *

Muestra el resultado dentro de una etiqueta <pre>. Si la altura no es un entero positivo, muestra un error.

Cuaderno

Haz la traza de los dos bucles para una altura de 3: apunta los valores de $i y $j en cada vuelta y lo que se añade a la fila.


P06 · Tabla numerada dinámica

RA/CE: RA3 – CE b), f) · Duración: 1,5 h

Pide el número total de casillas y el número de casillas por fila, y genera una tabla HTML numerada del 1 al total.

  • Abre y cierra cada fila <tr> en el momento justo usando el operador módulo (%).
  • Si la última fila no está completa, rellénala con celdas vacías para que la tabla quede cuadrada.
  • Valida que los dos valores sean enteros mayores que cero.

Ejemplo: 12 casillas y 5 por fila → 3 filas. La última tiene 11 y 12 y tres celdas vacías.


P07 · Conversor de divisas

RA/CE: RA3 – CE c), e), f) · Duración: 1,5 h

Crea un conversor entre euros (€), dólares ($) y yenes (¥). El formulario tiene una cantidad y dos select (De y A).

  • Guarda las tasas en un array asociativo tomando el euro como base:
$tasas = ['EUR' => 1.0, 'USD' => 1.0850, 'JPY' => 160.0];
  • Para convertir, pasa primero la cantidad a euros y luego a la divisa de destino.
  • El formulario es persistente: después de enviarlo, cada select conserva la opción elegida (atributo selected).
  • Muestra el resultado con sprintf(), por ejemplo: 340.00 EUR = 368.90 USD.
  • Comprueba que las divisas recibidas existen en $tasas antes de usarlas.

P08 · La quiniela

RA/CE: RA3 – CE b), c), e), f) · Duración: 2 h

Crea una quiniela de 10 partidos con dos ficheros.

Formulario (ut03p08.php):

  • Genera las 10 filas con un bucle for, no a mano.
  • Cada partido es un grupo de tres radio (1, X, 2) llamado partido[1], partido[2]…, para que lleguen al servidor como un array.

Resultados (ut03p08-res.php):

  • Simula el resultado real de cada partido con rand().
  • Muestra una tabla con cuatro columnas: Partido, Tu resultado (o SIN MARCAR), Ha salido y ¿Has acertado?.
  • Muestra el total de aciertos y un botón Volver a jugar.

Seguridad

Un usuario puede modificar el formulario y enviar cualquier valor en partido[…]. Acepta solo 1, X o 2 (comprueba con in_array()) y escapa todo lo que muestres.


P09 · Formulario de alta validado con expresiones regulares

RA/CE: RA2 – CE g) · RA3 – CE a), d), e), f), g) · Duración: 2 h

Crea un formulario de alta autoprocesado (ut03p09.php) que valide cada campo con preg_match(). Antes de validar, normaliza los datos con preg_replace(): quita espacios sobrantes, guiones y puntos, y pasa a mayúsculas lo que haga falta.

Campo Regla Válido No válido
Nombre y apellidos Letras (con tildes y ñ), espacios, apóstrofo y guion. De 2 a 60 caracteres Ana María Pérez-Ruiz Ana2
DNI o NIE 8 cifras + letra, o X/Y/Z + 7 cifras + letra. La letra debe ser la correcta 12345678Z, X1234567L 12345678A
Teléfono 9 cifras que empiezan por 6, 7, 8 o 9. Prefijo +34 o 0034 opcional +34 612 345 678 512345678
Código postal 5 cifras; las dos primeras, de 01 a 52 30530 60000
Correo electrónico Usa filter_var(), no una expresión regular ana@ejemplo.es ana@
Contraseña Al menos 8 caracteres, con minúscula, mayúscula, número y símbolo Segura#2026 abc
Matrícula (opcional) 4 cifras y 3 consonantes, sin vocales, Ñ ni Q 1234 BCD 1234 AEI

Requisitos:

  1. Muestra el error de cada campo debajo del propio campo (clase is-danger de Bulma), no todos juntos arriba.
  2. En la contraseña, di qué requisitos le faltan. Para eso, comprueba cada requisito con una expresión regular distinta.
  3. El formulario conserva lo escrito, salvo la contraseña, que nunca se vuelve a mostrar.
  4. Para el DNI/NIE, reutiliza la función de la letra de la P03. En el NIE, la X vale 0, la Y vale 1 y la Z vale 2.
  5. Si todo es correcto, muestra una tabla con los datos ya normalizados. El teléfono debe aparecer agrupado (612 345 678); usa grupos de captura y $1 $2 $3 en preg_replace().
Pista: grupos de captura

preg_match('/^(?:\+34|0034)?([6-9]\d{8})$/', $tel, $partes) guarda en $partes[1] el número sin el prefijo. (?: … ) es un grupo que no captura.

Cuaderno

Escribe a mano la expresión regular del código postal y explica qué significa cada parte: ^, ( | | ), \d{3} y $.

Para pensar

¿Por qué validamos el email con filter_var() y no con una expresión regular hecha a mano?


🔴 Nivel avanzado

P10 · Gestión de calificaciones

RA/CE: RA3 – CE c), d), f), g) · Duración: 2 h

Crea un formulario con el nombre y la nota (0–10) de 4 alumnos. Usa name="nombres[]" y name="notas[]".

  • Valida cada pareja: el nombre no puede estar vacío y la nota debe ser un número entre 0 y 10. Si alguna falla, muestra un error.
  • Guarda los datos válidos en un array asociativo nombre => nota.
  • Escribe y usa tres funciones propias:
    • calcular_media(array $alumnos): float
    • obtener_maximo(array $alumnos): array → devuelve ['nombre' => …, 'nota' => …]
    • obtener_minimo(array $alumnos): array
  • Muestra la media, la nota más alta y la más baja (con el nombre del alumno), y una tabla con todos los alumnos y su estado: Aprobado (nota ≥ 5) o Suspenso.
  • Muestra los números en formato español con number_format(), por ejemplo 7,25.
Para pensar

¿Qué ocurre si dos alumnos tienen el mismo nombre? Propón una solución y anótala en el cuaderno.


P11 · Buscador de productos con filtros

RA/CE: RA2 – CE h) · RA3 – CE c), d), e), f) · Duración: 2,5 h

Crea un buscador sobre un catálogo de productos que está en un fichero aparte, datos.php:

<?php
$categorias = ['Informática', 'Telefonía', 'Audio', 'Hogar'];

$productos = [
    ['nombre' => 'Portátil 15"',          'categoria' => 'Informática', 'precio' => 749.00, 'stock' => 5],
    ['nombre' => 'Ratón inalámbrico',     'categoria' => 'Informática', 'precio' => 19.90,  'stock' => 0],
    ['nombre' => 'Monitor 27"',           'categoria' => 'Informática', 'precio' => 229.00, 'stock' => 3],
    ['nombre' => 'Smartphone 128 GB',     'categoria' => 'Telefonía',   'precio' => 399.00, 'stock' => 8],
    ['nombre' => 'Funda de silicona',     'categoria' => 'Telefonía',   'precio' => 9.95,   'stock' => 25],
    ['nombre' => 'Auriculares Bluetooth', 'categoria' => 'Audio',       'precio' => 59.00,  'stock' => 0],
    ['nombre' => 'Altavoz portátil',      'categoria' => 'Audio',       'precio' => 45.50,  'stock' => 12],
    ['nombre' => 'Robot aspirador',       'categoria' => 'Hogar',       'precio' => 199.00, 'stock' => 2],
    ['nombre' => 'Cafetera de cápsulas',  'categoria' => 'Hogar',       'precio' => 79.99,  'stock' => 0],
];

Formulario (ut03p11.php):

  • Lo envía por GET.
  • Incluye datos.php con require_once y genera el select de categorías recorriendo $categorias, con la opción Todas las categorías.
  • Tiene dos campos de precio (mínimo y máximo) y un checkbox Solo productos con stock.

Resultados (ut03p11-res.php):

  • Filtra $productos con array_filter() y una función anónima (use). Cada filtro solo se aplica si el usuario lo ha rellenado.
  • Muestra un resumen de los filtros aplicados.
  • Muestra una tabla con los productos encontrados: precio en formato 749,00 € y stock en verde, o Sin stock en rojo. Si no hay ninguno, muéstralo con un aviso.
Pregunta

¿Por qué aquí tiene sentido usar GET y no POST? Piensa en compartir el enlace de una búsqueda o guardarlo en marcadores.


P12 · Reto: calculadora de esperanza de vida

RA/CE: RA3 – CE a), b), c), d), e), f), g) · Duración: 3 h

Crea en un único fichero una calculadora orientativa de años de vida. Parte de la esperanza de vida en España (INE, 2024) y súmale o réstale años según cinco hábitos.

Punto de partida (radio): hombre 81,4 años · mujer 86,5 años.

Ajustes (en años):

Factor Opciones y ajuste
Tabaco Nunca 0 · Lo dejé antes de los 40 −1 · Lo dejé a los 40 o después −3 · Fumo −10
Actividad física semanal < 15 min −1,8 · 15–149 min 0 · 150–449 min +1,6 · ≥ 450 min +2,7
Bebidas alcohólicas semanales 0–10 0 · 11–20 −0,5 · 21–35 −1,5 · > 35 −4,5
Alimentación Procesada −2 · Mixta 0 · Mediterránea +2,5
IMC (a partir de altura y peso) < 18,5 −2 · < 25 0 · < 30 −0,5 · < 35 −3 · < 40 −6 · ≥ 40 −9

Requisitos:

  1. Guarda las preguntas, sus opciones y sus ajustes en un array multidimensional, y genera el formulario recorriéndolo con foreach. Si añades una pregunta al array, debe aparecer en el formulario sin tocar el HTML.
  2. Valida con lista blanca: solo se aceptan claves que existan en el array (array_key_exists). La altura debe estar entre 120 y 220 cm y el peso entre 30 y 250 kg. Si algo falla, muestra todos los errores juntos y usa un valor por defecto.
  3. Calcula el IMC (peso / altura², con la altura en metros) y busca su tramo recorriendo un array de tramos.
  4. Muestra el resultado total y un desglose con cada factor, la opción elegida y su ajuste con signo (+1,6 / −3,0). Indica también qué factor resta más años.
  5. Crea funciones auxiliares: h() para escapar, fmt() para dar formato a los números y marcado() para conservar los radio elegidos.

Aviso

Es un ejercicio de programación con datos orientativos sacados de estudios publicados. No es un consejo médico. Dilo así en la propia página.


Entrega

Cómo entregar

  • Sube a Moodle (aulavirtual.murciaeduca.es) un .zip llamado ut03-apellido-nombre.zip con una carpeta por práctica (p01/, p02/…).
  • Añade en el comentario de la entrega el enlace a tu repositorio de GitHub.
  • Entrega también las fotos de las páginas del cuaderno que se piden en P03, P05, P09 y P10.
  • Mínimo para entregar: todas las prácticas de nivel básico e intermedio (P01–P09). Las de nivel avanzado suben nota.

Rúbrica

Cada práctica se puntúa sobre 10:

Criterio Peso Excelente Suficiente Insuficiente
Funcionalidad 40 % Hace todo lo que pide el enunciado, también en los casos límite Funciona en el caso normal No funciona o le faltan partes importantes
Validación y seguridad 25 % Valida todas las entradas y escapa todas las salidas Valida lo principal Muestra datos sin escapar o no valida
Calidad del código 20 % Buenos nombres, funciones bien usadas y comentarios útiles Código correcto pero con repeticiones Código desordenado y sin comentarios
Interfaz 10 % Bulma bien usado, mensajes claros y formulario que conserva los datos Interfaz correcta y básica HTML sin estilos o confuso
Git y cuaderno 5 % Un commit por práctica y cuaderno completo Pocos commits o cuaderno incompleto Sin repositorio o sin cuaderno

La nota del boletín cuenta dentro del 50 % de tareas y prácticas de RA2 y RA3.