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 confilter_input()ofilter_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 usaut03p01.html(formulario) yut03p01-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ónnumero % 23de la cadenaTRWAGMYFPDXBNJZSQVHLCKE. - 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
selectconserva la opción elegida (atributoselected). - Muestra el resultado con
sprintf(), por ejemplo:340.00 EUR = 368.90 USD. - Comprueba que las divisas recibidas existen en
$tasasantes 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:
- Muestra el error de cada campo debajo del propio campo (clase
is-dangerde Bulma), no todos juntos arriba. - En la contraseña, di qué requisitos le faltan. Para eso, comprueba cada requisito con una expresión regular distinta.
- El formulario conserva lo escrito, salvo la contraseña, que nunca se vuelve a mostrar.
- 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.
- 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 $3enpreg_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): floatobtener_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 ejemplo7,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.phpconrequire_oncey genera elselectde 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
$productosconarray_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:
- 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. - 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. - Calcula el IMC (peso / altura², con la altura en metros) y busca su tramo recorriendo un array de tramos.
- 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. - Crea funciones auxiliares:
h()para escapar,fmt()para dar formato a los números ymarcado()para conservar losradioelegidos.
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
.zipllamadout03-apellido-nombre.zipcon 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.