UT3 · Guía para resolver las prácticas paso a paso
Esta guía no trae el código de las prácticas. Te enseña cómo pensar cada una: por dónde empezar, en qué trozos dividirla, qué preguntarte y cómo comprobar que funciona. El código lo escribes tú.
Úsala así:
- Lee primero la parte 1 (el método) y la parte 2 (los patrones). Sirven para todas las prácticas.
- Cuando vayas a hacer una práctica, abre su ficha en la parte 3 y síguela con el cuaderno al lado.
- Si te atascas, vuelve al patrón que se cita en la ficha.
Si te bloqueas
Atascarse es normal: es parte de aprender a programar. Lo que no funciona es quedarse mirando la pantalla. Si llevas más de 15 minutos sin avanzar, vuelve al cuaderno, escribe en una frase qué intentas hacer y qué ocurre, y pregunta con esa frase.
1. El método: seis pasos para cualquier ejercicio
Casi todos los bloqueos vienen de empezar a escribir código demasiado pronto. Antes de abrir VS Code, haz los pasos 1 a 4 en el cuaderno.
Paso 1. Lee y subraya
Lee el enunciado dos veces. En la segunda, subraya:
- los datos que da el usuario (normalmente, los campos del formulario);
- lo que hay que mostrar;
- las condiciones: «obligatorio», «entre 1 y 30», «solo si…», «si no…».
Mira también la plantilla: los atributos name del formulario te dicen cómo se llaman los datos que te llegan.
Paso 2. Haz la tabla Entrada – Proceso – Salida
Dibuja en el cuaderno una tabla de tres columnas:
| Entrada (¿qué tengo?) | Proceso (¿qué hago?) | Salida (¿qué muestro?) |
|---|---|---|
Los campos del formulario y sus name |
Validar, calcular, buscar, recorrer… | Mensajes, resultados, tablas… |
Si no sabes rellenar alguna columna, todavía no has entendido el problema. Vuelve a leer el enunciado antes de seguir.
Paso 3. Divide el problema en trozos pequeños
Un problema grande da miedo; cinco problemas pequeños, no. Casi todas las prácticas de esta unidad se dividen en los mismos trozos:
- Saber si el formulario se ha enviado.
- Recoger los datos.
- Validarlos y apuntar los errores.
- Si no hay errores, calcular el resultado.
- Mostrar el formulario (con lo que escribió el usuario), los errores y el resultado.
Escribe la lista en el cuaderno y ve tachando cada trozo cuando funcione.
Paso 4. Escribe el pseudocódigo
El pseudocódigo es el programa escrito en castellano, con la estructura de un programa: SI … ENTONCES, PARA CADA …, MIENTRAS …. No tiene que compilar; tiene que ser claro.
SI se ha enviado el formulario ENTONCES
recoger número
SI número no es entero positivo ENTONCES
apuntar error
SI NO
calcular letra
FIN SI
Después, haz una traza: elige unos datos de prueba y sigue el pseudocódigo a mano, línea a línea, apuntando el valor de cada variable. Si la traza da el resultado correcto, el algoritmo está bien y solo queda traducirlo a PHP.
Paso 5. Programa poco a poco y comprueba cada trozo
No escribas todo de golpe. Escribe un trozo, guarda, recarga el navegador y comprueba que hace lo que esperas. Para ver qué contiene una variable, usa:
echo '<pre>';
var_dump($_POST); // o la variable que quieras inspeccionar
echo '</pre>';
Cuando el trozo funcione, borra la línea de depuración y pasa al siguiente.
Lee los mensajes de error
Un mensaje como Warning: Undefined array key "altura" in … on line 12 te dice qué pasa (esa clave no existe en el array) y dónde (línea 12). Léelo entero antes de cambiar nada.
Paso 6. Prueba con casos pensados y haz commit
Prueba siempre tres tipos de casos:
| Tipo de caso | Ejemplo | Qué compruebas |
|---|---|---|
| Normal | Un dato correcto y típico | Que el cálculo es correcto |
| Límite | El valor más pequeño y el más grande permitidos, una lista vacía… | Que no fallas «por uno» |
| Erróneo | Letras donde van números, campo vacío, valor fuera de rango, formulario manipulado | Que la validación lo detecta |
Cada ficha de la parte 3 trae una tabla de casos de prueba. Cuando todos pasen, haz el commit (P05: dibuja triángulo).
2. Patrones que se repiten
Un patrón es una forma de resolver un tipo de problema que aparece una y otra vez. Si reconoces el patrón, ya tienes media práctica hecha. En cada ficha se indica cuáles usar.
Patrón A · Estructura de una página PHP
Separa la página en dos zonas:
┌──────────────────────────────────────────┐
│ ZONA DE LÓGICA (PHP, antes del DOCTYPE) │
│ · inicializar variables │
│ · ¿se ha enviado? → recoger, validar, │
│ calcular │
├──────────────────────────────────────────┤
│ ZONA DE PRESENTACIÓN (HTML) │
│ · solo muestra variables ya calculadas │
│ · if / foreach con sintaxis alternativa │
└──────────────────────────────────────────┘
Regla de oro: en la zona de HTML no se calcula nada; solo se muestra. Si te ves haciendo cuentas en mitad de una <table>, sube ese cálculo a la zona de lógica y guarda el resultado en una variable.
Inicializa al principio todas las variables que usará el HTML ($errores = [], $resultado = null, los valores de los campos a ''). Así la página funciona igual la primera vez que se abre, cuando todavía no se ha enviado nada.
Patrón B · ¿Se ha enviado el formulario?
En una página autoprocesada hay dos momentos: la primera visita (formulario vacío) y el envío. Distínguelos preguntando por el método de la petición ($_SERVER['REQUEST_METHOD']), como en la teoría (apartado 4).
En una página de resultados separada (…-res.php), si no se ha llegado por POST, redirige al formulario con header('Location: …') seguido de exit. Recuerda que header() tiene que ir antes de cualquier salida HTML, incluso antes de un espacio en blanco.
Patrón C · Validar y acumular errores
No muestres el primer error y te pares. Revisa todos los campos y apunta cada error en un array:
errores ← lista vacía
SI campo1 no es válido ENTONCES errores['campo1'] ← "mensaje"
SI campo2 no es válido ENTONCES errores['campo2'] ← "mensaje"
…
SI errores está vacío ENTONCES
calcular y preparar el resultado
FIN SI
Usar el nombre del campo como clave te permite, después, mostrar cada error debajo de su campo (P09) o todos juntos (P12).
Para validar números, usa filter_input() o filter_var() con FILTER_VALIDATE_INT o FILTER_VALIDATE_FLOAT. Devuelven false si el dato no es válido, y admiten la opción min_range / max_range para los rangos. Compara siempre con === false, porque el número 0 también se evalúa como falso.
Patrón D · Formulario persistente
Después de enviar, el formulario debe mostrar lo que escribió el usuario:
| Control | Qué haces |
|---|---|
text, number |
Pon en value el dato recibido, escapado con htmlspecialchars() |
radio, checkbox |
Escribe checked solo en la opción cuyo value coincide con lo recibido |
select |
Escribe selected solo en la <option> cuyo value coincide con lo recibido |
password |
Nunca se vuelve a mostrar |
Cuando haya muchas opciones, no compares una a una: genera las opciones con un bucle a partir de un array y compara dentro del bucle. Si lo haces en varias prácticas, crea una pequeña función que devuelva 'checked' o ''.
Patrón E · Escapar todo lo que se muestra
Todo dato que venga del usuario y vaya a aparecer en la página pasa por htmlspecialchars(). Si lo escribes muchas veces, crea una función corta h() que lo haga (la pide la P12, pero puedes usarla desde la P01).
Patrón F · Tabla de consulta en lugar de muchos if
Si tienes que traducir un valor a otro (un código a un texto, una divisa a su tasa, una opción a su ajuste), no encadenes if. Usa:
- un array asociativo
clave => valor, si los datos se usan en varios sitios (P07, P11, P12); - una expresión
match, si solo es una traducción puntual (P01).
Ventaja: para añadir una opción nueva solo cambias el array, no la lógica.
Patrón G · Lista blanca
No te fíes de lo que llega del formulario: el usuario puede modificar el HTML desde el navegador y enviar cualquier cosa. Comprueba que el valor recibido está entre los permitidos antes de usarlo:
in_array($valor, $permitidos)si tienes una lista de valores (P08);array_key_exists($valor, $array)oisset($array[$valor])si los valores son claves de un array (P07, P11, P12).
Patrón H · Acumulador, contador, máximo y mínimo
Cuatro cosas que se calculan recorriendo una lista:
suma ← 0 contador ← 0
PARA CADA x EN lista PARA CADA x EN lista
suma ← suma + x SI x cumple la condición ENTONCES
FIN PARA contador ← contador + 1
FIN SI
FIN PARA
máximo ← primer elemento
PARA CADA x EN lista
SI x > máximo ENTONCES máximo ← x
FIN PARA
Fíjate en el valor inicial: la suma y el contador empiezan en 0; el máximo y el mínimo empiezan en el primer elemento de la lista (no en 0: si todas las notas fueran negativas, o todas fueran mayores que 0 al buscar el mínimo, fallaría).
Patrón I · Bucles anidados
Cuando el resultado tiene filas y columnas, piensa en dos bucles:
- el exterior recorre las filas;
- el interior recorre los elementos de cada fila.
La clave es descubrir de qué depende el número de vueltas del bucle interior. A veces es fijo; a veces depende de la fila en que estás (como en el triángulo de la P05).
Patrón J · «Cada N elementos» con el módulo
El operador % da el resto de una división. Sirve para hacer algo cada N elementos: si numeras desde 1, i % N == 0 es cierto en el elemento N, 2N, 3N…, y (i - 1) % N == 0 es cierto en el elemento 1, N+1, 2N+1… Úsalo en la P06 para saber cuándo abrir y cuándo cerrar una fila.
3. Fichas de las prácticas
Cada ficha tiene la misma estructura: qué tienes y qué quieres, estrategia (los trozos en orden), preguntas para el cuaderno, casos de prueba y errores típicos.
P01 · Formulario de búsqueda de canciones
Patrones: B, E, F · Plantillas: ut03p01.html (ya hecho) y ut03p01-res.php
| Entrada | Proceso | Salida |
|---|---|---|
texto, buscar_en, genero por POST |
Traducir buscar_en a un texto legible |
Lista con los tres datos y botón Nueva búsqueda |
Estrategia
- En
ut03p01-res.php, antes delDOCTYPE, comprueba si se ha llegado por POST. Si no, redirige al formulario (patrón B). Pruébalo abriendout03p01-res.phpdirectamente. - Recoge los tres campos. Usa el operador
??para dar un valor por defecto si alguno no llega. - Traduce el valor interno de
buscar_en(cancion,album,ambos) a un texto conmatch(patrón F). Piensa qué hacematchsi llega un valor que no está en la lista: añade un casodefault. - Sustituye los textos de ejemplo de la plantilla por tus variables, escapadas (patrón E).
Casos de prueba
| Caso | Resultado esperado |
|---|---|
rock and roll, Ambos, Rock |
Se muestran los tres datos |
Escribe <b>hola</b> en el texto |
Se ve literalmente <b>hola</b>, no «hola» en negrita |
Abre ut03p01-res.php en una pestaña nueva |
Vuelves al formulario |
Errores típicos
- «Cannot modify header information – headers already sent»: hay algo (HTML, un espacio, una línea en blanco) antes de
header(). Pon el bloque PHP en la primera línea del fichero. - Olvidar
exitdespués deheader(): el resto de la página se sigue ejecutando.
P02 · Catálogo de controles de formulario
Patrones: B, E · Plantillas: ut03p02.php (ya hecho) y ut03p02-res.php
| Entrada | Proceso | Salida |
|---|---|---|
9 controles distintos, uno de ellos file |
Recoger cada uno según su tipo | Tabla con lo que llega de cada control |
Estrategia
- Antes de programar nada, envía el formulario con
var_dump($_POST)yvar_dump($_FILES)en la página de resultados. Mira cómo llega cada control: ¿es una cadena?, ¿un array?, ¿no aparece? - Apunta en el cuaderno, para cada control, si llega como cadena o como array, y qué pasa si no lo rellenas.
- Recoge uno a uno. Los que llegan como array (
extras[],idiomas[]) se recogen con?? []y se muestran unidos conimplode(). - Para el fichero, todo está en
$_FILES['fichero']: busca en la teoría (apartado 4.3.1) qué claves tiene (name,size,type,error…). Comprueba antes si se ha subido algo. - La contraseña no se muestra: genera tantos
•como caracteres tenga (str_repeat()ystrlen()), o un número fijo. - El comentario se escapa primero y después se pasa por
nl2br(). Piensa por qué el orden importa.
Casos de prueba
| Caso | Resultado esperado |
|---|---|
| Rellenar todo | Cada fila muestra su valor |
| No marcar ningún checkbox ni idioma | Aparece un texto como «Ninguno», sin warnings |
| No elegir fichero | «No se ha enviado ningún fichero», sin warnings |
| Comentario de tres líneas | Se ven tres líneas |
Errores típicos
Undefined array key "extras": si no se marca ningún checkbox, la clave no existe. Usa?? [].$_FILESvacío: faltaenctype="multipart/form-data"en el<form>.- Si haces
nl2br()antes dehtmlspecialchars(), los<br>se escapan y se ven como texto.
P03 · Calculadora de la letra del DNI
Patrones: A, B, C, D, E · Plantilla: ut03p03.php (autoprocesada)
| Entrada | Proceso | Salida |
|---|---|---|
numero por POST |
Validar entero positivo; calcular el resto entre 23; buscar la letra | DNI de 8 cifras con su letra, o un error |
Estrategia
- Cuaderno primero: haz el cálculo con tu DNI (lo pide el enunciado). Divide entre 23, apunta el resto y busca esa posición en la cadena
TRWAGMYFPDXBNJZSQVHLCKE. Ojo: la primera letra es la posición 0. - Escribe la función
calcularLetraDNI()y pruébala sola, sin formulario, con unechoy un número fijo. Cuando déZpara12345678, sigue. - Monta la zona de lógica (patrón A): inicializa
$error,$numeroy$resultado. - Si se ha enviado (patrón B), valida con
FILTER_VALIDATE_INTymin_range(patrón C). - Si es válido, llama a tu función y construye el DNI completo rellenando con ceros (
str_pad(), conSTR_PAD_LEFT). - En el HTML, muestra el error solo si existe y el resultado solo si existe. Haz el campo persistente (patrón D).
- Botón Borrar: piensa por qué un enlace a la propia página la deja vacía (es una petición GET).
Pregunta para el cuaderno
Un DNI tiene como máximo 8 cifras. ¿Deberías aceptar 123456789? Decide qué haces y añade la regla a la validación.
Casos de prueba
| Entrada | Resultado esperado |
|---|---|
12345678 |
12345678Z |
1 |
00000001R |
87654321 |
87654321X |
0, -5, abc, 12.5, vacío |
Mensaje de error |
Errores típicos
- Coger la letra con
resto + 1oresto - 1: las cadenas empiezan en la posición 0. if (!$numero)para detectar errores: falla con el número 0. Usa=== false.
P04 · Ecuación de segundo grado
Patrones: A, B, C, D · Plantilla: ut03p04.php
| Entrada | Proceso | Salida |
|---|---|---|
a, b, c |
Validar; calcular discriminante; decidir el caso | Dos soluciones con 2 decimales, o «no hay soluciones reales» |
Estrategia
- Cuaderno: escribe la fórmula x = (−b ± √(b² − 4ac)) / 2a y resuelve a mano el ejemplo del enunciado.
- Valida los tres coeficientes con
FILTER_VALIDATE_FLOAT(patrón C). Después, comprueba aparte queano es 0. ¿Por qué? Piensa qué pasa en la fórmula siavale 0. - Calcula el discriminante en una variable.
- Decide con un
if: negativo → aviso; cero o positivo → dos soluciones (sqrt()). - Formatea con
number_format()(2 decimales, coma decimal). - Haz persistentes los tres campos.
SI discriminante < 0 ENTONCES
resultado ← "sin soluciones reales"
SI NO
x1 ← (−b + raíz(discriminante)) / (2·a)
x2 ← (−b − raíz(discriminante)) / (2·a)
FIN SI
Casos de prueba
| a | b | c | Resultado esperado |
|---|---|---|---|
| 1 | −5 | 6 | x₁ = 3,00 · x₂ = 2,00 |
| 2 | −7 | 3 | x₁ = 3,00 · x₂ = 0,50 |
| 1 | 2 | 1 | x₁ = −1,00 · x₂ = −1,00 (discriminante 0) |
| 1 | 0 | 1 | No hay soluciones reales |
| 0 | 3 | 2 | Error: a no puede ser 0 |
hola |
1 | 1 | Error: no es un número |
Errores típicos
- Escribir
-b + sqrt($d) / 2 * $a: sin paréntesis, PHP divide antes de sumar y multiplica poraen vez de dividir. Pon paréntesis en el numerador y en el denominador. - Con
FILTER_VALIDATE_FLOAT, un0es válido pero se evalúa como falso. Compara con=== false.
P05 · Dibuja un triángulo
Patrones: A, C, D, I · Plantilla: ut03p05.php
| Entrada | Proceso | Salida |
|---|---|---|
altura (1–30), caracter |
Dos bucles anidados que construyen las filas | El triángulo dentro de <pre> |
Estrategia
- Cuaderno: dibuja el triángulo de altura 4 y numera las filas. Responde: en la fila 1, ¿cuántos caracteres hay?, ¿y en la 2?, ¿y en la fila i? Ahí tienes el límite del bucle interior.
- Haz la traza que pide el enunciado para altura 3.
- Valida la altura con
FILTER_VALIDATE_INT,min_range1 ymax_range30. Si el carácter llega vacío, usa*. - Construye todo el dibujo en una variable (en la zona de lógica), concatenando, y muéstrala en el
<pre>al final (patrón A).
dibujo ← ""
PARA fila DESDE 1 HASTA altura
PARA columna DESDE 1 HASTA ¿…? ← lo has deducido en el cuaderno
añadir carácter y un espacio a dibujo
FIN PARA
añadir salto de línea a dibujo
FIN PARA
Para ir más allá
Cuando funcione, intenta el triángulo invertido (la fila 1 es la más larga) o una pirámide centrada. Solo cambian los límites de los bucles… y en la pirámide aparece un tercer bucle para los espacios.
Casos de prueba
| Entrada | Resultado esperado |
|---|---|
Altura 4, * |
El triángulo del enunciado |
| Altura 1 | Un solo carácter |
| Altura 30 | 30 filas, la última con 30 caracteres |
Altura 0, 31, abc |
Error |
Carácter < |
Se dibuja < (escápalo) |
Errores típicos
- Las filas salen todas iguales: el bucle interior no depende de la fila.
- Sale todo en una sola línea: falta el salto de línea
"\n"al terminar cada fila, o no estás dentro de<pre>. - El salto de línea sale como
\nliteral: lo has escrito entre comillas simples.
P06 · Tabla numerada dinámica
Patrones: A, C, D, J · Plantilla: ut03p06.php
| Entrada | Proceso | Salida |
|---|---|---|
num_casillas, casillas_por_fila |
Un bucle de 1 a total; abrir y cerrar filas con %; rellenar la última |
Tabla HTML |
Estrategia
- Cuaderno: dibuja la tabla para 12 casillas y 5 por fila. Rodea con un círculo los números donde empieza cada fila (1, 6, 11) y los números donde acaba (5, 10). ¿Qué tienen en común respecto al 5? (patrón J).
- Escribe primero un bucle que genere todas las celdas sin filas. Comprueba que salen los 12 números.
- Añade la apertura de
<tr>: ¿en qué números se abre una fila? - Añade el cierre de
</tr>: ¿en qué números se cierra? - Al terminar el bucle, mira si la última fila quedó abierta. Si es así, calcula cuántas celdas vacías faltan, añádelas y cierra la fila.
Pregunta para el cuaderno
Con 12 casillas y 5 por fila faltan 3 celdas. Con 10 casillas y 5 por fila no falta ninguna. Escribe una expresión con % que dé el número de celdas que faltan y comprueba que funciona en los dos casos.
Casos de prueba
| Total | Por fila | Resultado esperado |
|---|---|---|
| 12 | 5 | 3 filas; la última: 11, 12 y tres vacías |
| 10 | 5 | 2 filas completas, sin celdas vacías |
| 3 | 5 | 1 fila: 1, 2, 3 y dos vacías |
| 7 | 1 | 7 filas de una celda |
0, −2, abc |
— | Error |
Errores típicos
- Una fila vacía de más al final: cierras la fila y luego, al rellenar, la vuelves a cerrar. Rellena solo si la última fila quedó incompleta.
- Abre el inspector del navegador (F12) y mira el HTML generado: es la forma más rápida de ver si los
<tr>cuadran.
P07 · Conversor de divisas
Patrones: C, D, F, G · Plantilla: ut03p07.php
| Entrada | Proceso | Salida |
|---|---|---|
cantidad, de, a |
Pasar a euros y de euros a destino, usando $tasas |
340.00 EUR = 368.90 USD |
Estrategia
- Cuaderno: las tasas dicen «cuántas unidades de esa divisa vale 1 euro». Resuelve a mano: ¿cuántos euros son 100 USD?, ¿y cuántos yenes son esos euros? Deduce la regla: para pasar a euros, ¿multiplicas o divides?
- Crea el array
$tasas(patrón F). - Valida la cantidad (número no negativo) y comprueba que
deyason claves de$tasas(patrón G). - Calcula en dos pasos, con una variable intermedia para los euros. Así cada paso se entiende y se puede comprobar.
- Formatea con
sprintf()y%.2f. - Genera las
<option>de losselectcon unforeachsobre$tasasy añadeselecteda la elegida (patrón D). Así no repites el código en los dosselect.
euros ← cantidad / tasa[de]
resultado ← euros · tasa[a]
Casos de prueba
| Entrada | Resultado esperado |
|---|---|
| 340 EUR → USD | 340.00 EUR = 368.90 USD |
| 100 USD → JPY | 100.00 USD = 14746.54 JPY |
| 1000 JPY → EUR | 1000.00 JPY = 6.25 EUR |
| 50 EUR → EUR | 50.00 EUR = 50.00 EUR |
Cantidad abc |
Error |
Cambia con F12 el value de una opción a GBP |
Error de divisa no válida, sin warnings |
P08 · La quiniela
Patrones: B, E, G, H · Plantillas: ut03p08.php y ut03p08-res.php
| Entrada | Proceso | Salida |
|---|---|---|
Array partido[1..10] con 1, X o 2 |
Simular cada partido, comparar, contar aciertos | Tabla de 10 filas y total de aciertos |
Estrategia
Formulario
- Coge la fila modelo de la plantilla y métela en un
forde 1 a 10. Sustituye el número fijo por la variable del bucle en todos los sitios donde aparece (texto,name,id,for). - Comprueba con F12 que los
namequedan comopartido[1],partido[2]… y que losidno se repiten.
Resultados
- Redirige si no se llega por POST (patrón B).
- Recoge el array
partidocon?? []y hazvar_dump()para ver su forma. - Prepara un array con los tres signos válidos. Te sirve para dos cosas: validar (patrón G) y simular el resultado eligiendo una posición al azar con
rand(). - Recorre de 1 a 10. En cada vuelta: tu apuesta (o «SIN MARCAR» si no existe o no es válida), el resultado simulado y si coinciden. Si coinciden, suma un acierto (patrón H).
- Guarda cada fila en un array en la zona de lógica y, en el HTML, recórrelo con
foreachpara pintar la tabla (patrón A).
Casos de prueba
| Caso | Resultado esperado |
|---|---|
| Marcar los 10 | 10 filas; aciertos entre 0 y 10 |
| No marcar ninguno | 10 filas «SIN MARCAR», 0 aciertos, sin warnings |
Cambiar con F12 un value a 3 |
Esa fila cuenta como no válida |
| Recargar la página de resultados | Cambian los resultados simulados (es normal) |
P09 · Formulario de alta validado con expresiones regulares
Patrones: A, C, D, E · Plantilla: ut03p09.php
Es la práctica más larga del nivel intermedio. No la abordes entera: hazla campo a campo.
| Entrada | Proceso | Salida |
|---|---|---|
nombre, documento, telefono, cp, email, clave, matricula |
Normalizar → validar → apuntar errores por campo | Errores debajo de cada campo, o tabla de datos normalizados |
Estrategia general
- Monta primero el esqueleto con un solo campo (el código postal, que es el más sencillo): recoger, normalizar, validar, mostrar el error debajo del campo y hacerlo persistente. Cuando funcione, copia la mecánica a los demás.
- Usa el array de errores con el nombre del campo como clave (patrón C). En el HTML, cada campo pregunta si existe su clave en
$errorespara añadiris-dangery el mensaje. - Para cada campo sigue siempre el mismo orden: normalizar → validar → guardar el valor normalizado.
Cómo construir una expresión regular sin perderte
- Escribe en castellano la regla, trozo a trozo, de izquierda a derecha: «empieza por…, luego vienen…, y termina».
- Traduce cada trozo por separado: «una cifra» →
\d; «exactamente 5» →{5}; «uno de estos caracteres» →[…]; «esto o esto otro» →( | ); «opcional» →?. - Ancla siempre con
^al principio y$al final. Sin anclas,12345también «encaja» dentro deabc12345xyz. - Prueba la expresión aislada en una web como regex101.com (elige el modo PCRE, que es el de PHP) con los ejemplos válidos y no válidos de la tabla del enunciado, antes de ponerla en el código.
Pistas por campo
| Campo | Piensa en esto |
|---|---|
| Código postal | Las dos primeras cifras van de 01 a 52. Divide ese rango en tramos que se puedan escribir con clases: ¿qué pasa si la primera cifra es 0?, ¿y si es 1, 2, 3 o 4?, ¿y si es 5? Cada tramo es una alternativa del grupo. |
| Teléfono | Normaliza primero (quita espacios, guiones y puntos). Después, la expresión tiene un prefijo opcional y el número. Usa el grupo de captura de la pista del enunciado para quedarte solo con las 9 cifras. |
| DNI / NIE | Normaliza (mayúsculas, sin guiones ni espacios). Una expresión comprueba el formato. Si encaja, calcula la letra con tu función de la P03 y compárala. Para el NIE, sustituye la X, Y o Z inicial por 0, 1 o 2 antes de calcular. |
| Nombre | Las letras con tilde y la ñ no entran en [a-z]. Añádelas a la clase o usa \p{L} con el modificador u (UTF-8). |
| Correo | filter_var() con FILTER_VALIDATE_EMAIL. Nada de expresiones regulares aquí. |
| Contraseña | Cinco comprobaciones separadas (longitud, minúscula, mayúscula, número, símbolo). Cada una que falle añade su texto a una lista de requisitos pendientes. Al final, si la lista no está vacía, el error es esa lista unida con implode(). |
| Matrícula | Es opcional: si llega vacía, no hay error. Si no, normaliza y escribe la clase de consonantes enumerando las letras permitidas: el alfabeto sin A, E, I, O, U, Ñ ni Q. |
Casos de prueba: usa directamente las columnas Válido y No válido de la tabla del enunciado, más estos:
| Campo | Entrada | Resultado esperado |
|---|---|---|
| DNI | 12.345.678-z |
Válido, se guarda 12345678Z |
| NIE | X1234567L |
Válido |
| NIE | X1234567A |
Error: letra incorrecta |
| Teléfono | 0034-612.345.678 |
Válido, se muestra 612 345 678 |
| CP | 00123, 53000 |
Error |
| Contraseña | abcdefgh |
Error que dice que faltan mayúscula, número y símbolo |
| Todo correcto | — | Tabla de datos; la contraseña no aparece |
Errores típicos
- Validar antes de normalizar:
+34 612 345 678falla porque tiene espacios. - Olvidar las anclas
^y$. - Mostrar la contraseña en el
valuedel campo después de enviar. - Las tildes no funcionan: falta el modificador
ual final de la expresión (/…/u).
P10 · Gestión de calificaciones
Patrones: C, D, H · Plantilla: ut03p10.php
| Entrada | Proceso | Salida |
|---|---|---|
Arrays nombres[] y notas[] (4 cada uno) |
Validar parejas; crear nombre => nota; media, máximo, mínimo |
Resumen y tabla con Aprobado / Suspenso |
Estrategia
- Envía el formulario con
var_dump($_POST)y observa: llegan dos arrays paralelos. El alumno de la posición 0 denombrestiene su nota en la posición 0 denotas. - Recorre las posiciones de 0 a 3. En cada una, valida el nombre (no vacío tras
trim()) y la nota (FILTER_VALIDATE_FLOATcon rango 0–10). Si falla, apunta el error indicando qué fila falla (patrón C). Si es correcta, añádela al array asociativo$alumnos. - Escribe las tres funciones antes de usarlas y pruébalas con un array fijo escrito a mano, sin formulario.
calcular_media(): acumulador (patrón H), oarray_sum()ycount().obtener_maximo()/obtener_minimo(): patrón H, pero recuerda también el nombre, no solo la nota. Recorre conforeach ($alumnos as $nombre => $nota).
- Solo si no hay errores, llama a las funciones y prepara los datos para el HTML.
- En la tabla, decide el estado y la clase de color con un
ifo con el operador ternario.
mejor_nombre ← primer nombre; mejor_nota ← primera nota
PARA CADA (nombre, nota) EN alumnos
SI nota > mejor_nota ENTONCES
mejor_nota ← nota
mejor_nombre ← nombre
FIN SI
FIN PARA
devolver [nombre ← mejor_nombre, nota ← mejor_nota]
Casos de prueba
| Datos | Resultado esperado |
|---|---|
| Ana 7 · Luis 4,5 · Eva 9 · Pepe 6,5 | Media 6,75 · Máx. Eva (9,00) · Mín. Luis (4,50) · Luis suspenso |
Una nota 11 o -1 |
Error en esa fila |
| Un nombre vacío | Error en esa fila |
Nota 5 |
Aprobado (el límite es ≥ 5) |
Errores típicos
- Empezar el mínimo en 0: nunca encuentra una nota menor que 0. Empieza por el primer alumno (
array_key_first()te da su nombre). - Escribir la nota con coma (
7,5):FILTER_VALIDATE_FLOATla rechaza. Decide si avisas al usuario o si cambias la coma por un punto antes de validar. - Para el caso de dos alumnos con el mismo nombre, mira la pregunta Para pensar del enunciado: ¿qué le pasa a un array asociativo si repites una clave?
P11 · Buscador de productos con filtros
Patrones: D, F, G · Plantillas: ut03p11.php, ut03p11-res.php y datos.php
| Entrada | Proceso | Salida |
|---|---|---|
categoria, precio_min, precio_max, solo_stock por GET |
Filtrar $productos con array_filter() |
Resumen de filtros y tabla de productos, o aviso |
Estrategia
Formulario
- Incluye
datos.phpconrequire_oncey comprueba convar_dump($categorias)que llega. - Genera las
<option>con unforeachsobre$categorias, después de la opción Todas.
Resultados
- Recoge los filtros de
$_GET. Para cada uno, decide qué significa «no rellenado»: categoría vacía o Todas; precio vacío; checkbox sin marcar (no existe en$_GET). - Valida la categoría con lista blanca contra
$categorias(patrón G) y los precios como números. -
Antes de usar
array_filter(), escribe la condición en pseudocódigo para un solo producto. Una buena estrategia es empezar suponiendo que el producto pasa y descartarlo si falla algún filtro activo:FUNCIÓN pasa_los_filtros(producto) SI hay filtro de categoría Y la categoría del producto es distinta ENTONCES devolver falso SI hay precio mínimo Y el precio del producto es menor ENTONCES devolver falso SI ¿… precio máximo …? SI ¿… solo con stock …? devolver verdadero FIN FUNCIÓN -
Convierte ese pseudocódigo en una función anónima y pásala a
array_filter(). La función recibe un producto, pero los filtros están fuera de ella: por eso necesitasuse (…)para «meterlos» dentro. - Prepara los textos del resumen (por ejemplo, «Todas», «Sin límite»).
- En el HTML: si el array filtrado está vacío, aviso; si no, tabla con
foreach. Precio connumber_format()y€; stock en verde o Sin stock en rojo.
Casos de prueba
| Filtros | Productos esperados |
|---|---|
| Ninguno | Los 9 |
| Audio | Auriculares Bluetooth y Altavoz portátil |
| Máximo 50 + solo stock | Funda de silicona y Altavoz portátil |
| Informática + mínimo 200 | Portátil 15" y Monitor 27" |
| Hogar + solo stock | Robot aspirador |
| Mínimo 800 | Ninguno: aviso |
Categoría Juguetes escrita en la URL |
Error o se ignora el filtro, sin warnings |
Errores típicos
Undefined variable $categoriadentro de la función anónima: faltause ($categoria, …).- Un precio mínimo de
0desactiva el filtro sin querer: distingue «campo vacío» de «el número 0». - Las claves de
array_filter()se conservan (pueden quedar 1, 3, 6…). Para recorrer conforeachno importa.
P12 · Reto: calculadora de esperanza de vida
Patrones: todos · Plantilla: ut03p12.php
Es el reto final: junta todo lo de la unidad. La clave está en diseñar bien el array antes de escribir una sola línea.
| Entrada | Proceso | Salida |
|---|---|---|
sexo, 4 preguntas de opción, altura, peso |
Validar con lista blanca; sumar ajustes; calcular IMC y buscar su tramo | Total, desglose con signo y factor que más resta |
Estrategia
-
Diseña el array en el cuaderno. Dibuja su forma como un árbol antes de escribirlo en PHP. Por ejemplo:
$preguntas ├── 'tabaco' │ ├── 'titulo' → "¿Fumas o has fumado?" │ ├── 'ayuda' → "Cuenta cigarrillos, puros y pipa." │ └── 'opciones' │ ├── 'nunca' → [ 'texto' → "Nunca he fumado", 'ajuste' → 0 ] │ ├── 'ex_antes' → [ 'texto' → "Lo dejé antes…", 'ajuste' → -1 ] │ └── … ├── 'actividad' │ └── … └── …Las claves de primer nivel serán los
namede losradio; las claves deopciones, susvalue. Respeta las que ya usa la plantilla (tabaco,nunca,ex_antes…). Haz lo mismo para la esperanza de vida base (hombre,mujer) y para los tramos del IMC (una lista ordenada de pares límite – ajuste). -
Escribe las funciones auxiliares
h(),fmt()ymarcado()y pruébalas aisladas.fmt()debe poner el signo+delante de los positivos. - Genera el formulario desde el array: un
foreachexterior para las preguntas (unfieldsetcada una) y unforeachinterior para las opciones (patrón I). Comprueba que, si añades una pregunta al array, aparece sin tocar el HTML. - Valida con lista blanca: para cada pregunta, la opción recibida debe ser una clave de sus
opciones(patrón G). Altura y peso, con rango. Acumula todos los errores (patrón C) y, si algo falla, usa un valor por defecto. - Calcula:
- Parte de la esperanza base según el sexo.
- Recorre las preguntas: busca el ajuste de la opción elegida, súmalo al total y guarda una entrada en un array
$desglose(factor, opción elegida, ajuste). - IMC: convierte la altura a metros. Recorre los tramos en orden y quédate con el primero cuyo límite sea mayor que el IMC. Añade su ajuste al total y al desglose.
- Factor que más resta: recorre
$desglosebuscando el ajuste mínimo (patrón H).
- Muestra el resultado y el desglose con
foreach, eligiendo la clase de color según el signo del ajuste.
Pregunta para el cuaderno
¿Qué pasa si ningún factor resta (todos los ajustes son 0 o positivos)? Decide qué mensaje muestras en ese caso.
Casos de prueba
| Datos | Resultado esperado |
|---|---|
| Mujer · nunca · 150–449 min · 0–10 · mediterránea · 172 cm, 70 kg (IMC 23,7) | 86,5 + 1,6 + 2,5 = 90,6 años · no resta nada |
| Hombre · fuma · < 15 min · 21–35 · procesada · 175 cm, 95 kg (IMC 31,0) | 81,4 − 10 − 1,8 − 1,5 − 2 − 3 = 63,1 años · lo que más resta: tabaco (−10,0) |
| Altura 100 y peso 300 | Dos errores mostrados juntos |
Cambiar con F12 un value a mucho |
Error de opción no válida |
Errores típicos
- Tramos del IMC desordenados: el primero que cumpla la condición no es el correcto. Ordénalos de menor a mayor límite.
- El último tramo (IMC ≥ 40) no tiene límite superior: usa un límite muy grande, por ejemplo
INF. - El formulario no recuerda lo elegido:
marcado()compara con el valor recibido, pero en la primera visita no hay nada recibido. Decide qué opción va marcada por defecto.
4. Lista de comprobación antes de entregar
Repasa esta lista con cada práctica antes de hacer el commit final:
- He hecho en el cuaderno la tabla E-P-S y el pseudocódigo (y la traza, si se pide).
- La página funciona la primera vez que se abre, sin warnings.
- He probado los casos normales, límite y erróneos de la ficha.
- Todo lo que viene del usuario se muestra con
htmlspecialchars(). - Los números se validan con
filter_input()ofilter_var(). - Los valores de
radio,selectycheckboxse comprueban con lista blanca. - El formulario conserva los datos (salvo la contraseña).
- No hay cálculos en mitad del HTML: la lógica está arriba.
- El código tiene comentarios que explican qué hace cada bloque.
- He borrado los
var_dump()de depuración. - He hecho el commit con un mensaje claro.