Saltar a contenido

Lab 04 — Condicionales en PHP

Campo Valor
Módulo Implantación de Aplicaciones Web (IMW)
Ciclo Administración de Sistemas Informáticos en Red (ASIR)
Unidad UT4 — PHP en servidor
Criterios de evaluación (CE) d (estructuras de control: if/elseif/else)
Requisitos Labs 01, 02 y 03 completados
Agrupación Individual
Herramientas Navegador + editor de texto + terminal
Apuntes https://ichigar.codeberg.page/imw/recursos/ut4_php_04_control_de_flujo/
Tiempo estimado 60–90 minutos

Antes de empezar

Entorno de trabajo

Este lab usa el proyecto ~/gestor/ que creaste en el Lab 01. La estructura es:

gestor/
├── public/        <-- accesible desde el navegador
├── src/
├── templates/
└── data/

Apache está configurado con un VirtualHost cuyo DocumentRoot apunta a ~/gestor/public. Por eso, un fichero public/estado.php se ve desde el navegador en http://gestor.local/estado.php.

Si http://gestor.local no responde, revisa el Lab 01 Paso 3 antes de continuar.

Qué vamos a construir

A lo largo del lab iremos completando un único fichero: ~/gestor/public/estado.php. Empieza mostrando el estado de una incidencia y acaba con un selector que filtra una lista de incidencias por estado mediante la URL.

Cada paso amplía el fichero del paso anterior. Al final habrás integrado las cuatro herramientas del lab: if/elseif/else, lectura de parámetros de la URL con ??, filtrado dentro de foreach, y comprobación de listas vacías con empty().


Cómo se entrega este lab

Al terminar, empaqueta tu trabajo en un ZIP con esta estructura exacta:

apellido_nombre_lab04/
├── gestor/
│   └── public/
│       └── estado.php
├── capturas/
│   ├── paso1_boton_abierta.png
│   ├── paso2_prioridad_alta.png
│   ├── paso3_url_resuelta.png
│   ├── paso4_lista_filtrada.png
│   └── paso5_filtro_resueltas.png
└── RESPUESTAS.md

Nombres prescritos

Los nombres de los ficheros y carpetas son obligatorios y exactos. No uses mayúsculas, espacios ni acentos donde no los haya. El script de corrección busca estos nombres concretos: si los cambias, tu entrega aparecerá como incompleta.

Cómo preparar la entrega (independientemente del sistema operativo):

  1. Crea una carpeta en tu equipo llamada apellido_nombre_lab04 (sustituye por tu apellido y nombre reales, en minúsculas y sin espacios ni acentos).
  2. Dentro, reproduce la estructura de arriba:
    • Una subcarpeta gestor/public/ con tu fichero estado.php. Lo construirás en el servidor durante los pasos del lab; cópialo a tu carpeta de entrega antes de hacer el ZIP.
    • Una subcarpeta capturas/ con los 5 PNG, ya renombrados exactamente como se indica en cada paso.
    • Un fichero RESPUESTAS.md en la raíz de la carpeta, con una sección ## Paso N por cada pregunta del lab (la plantilla está en el anexo al final de este documento).
  3. Comprime esa carpeta completa en un archivo .zip:
    • Windows: clic derecho sobre la carpeta → Enviar aCarpeta comprimida (en zip). El archivo resultante debe llamarse apellido_nombre_lab04.zip.
    • Linux/macOS: desde la terminal, zip -r apellido_nombre_lab04.zip apellido_nombre_lab04/.
  4. Abre el ZIP para comprobar que al descomprimirlo aparece una sola carpeta raíz llamada apellido_nombre_lab04/, y que dentro están todos los ficheros esperados.

Comprueba la estructura del ZIP antes de subirlo

Un error habitual en Windows es seleccionar los ficheros de dentro de la carpeta en lugar de la carpeta completa, y comprimirlos. Eso genera un ZIP que al abrirse no tiene carpeta raíz, y el script de corrección lo rechaza. Comprime la carpeta apellido_nombre_lab04/, no su contenido.


Paso 1 — if / else: mostrar u ocultar contenido

Conceptos

  • if comprueba una condición y ejecuta un bloque solo si es verdadera.
  • Paralelismo con bash: if [ "$estado" = "abierta" ]; then ... fi en PHP se escribe if ($estado === 'abierta') { ... }.
  • Operadores de comparación en PHP: === (igual estricto), !== (distinto estricto), <, >, <=, >=. Usa siempre ===, nunca ==. Razón: == hace conversiones automáticas de tipo (lo que se llama type juggling) y produce sorpresas como 0 == 'texto' que devuelve true. Con === no ocurre: 0 === 'texto' es false porque PHP no convierte nada antes de comparar.
  • Cuando mezclamos PHP dentro de HTML, la sintaxis alternativa if (...): ... endif; es más legible que usar llaves.

Objetivo. Crear public/estado.php que muestre el estado de una incidencia y, según el valor, un botón activo o deshabilitado.

Tarea. Crea el fichero ~/gestor/public/estado.php con este contenido:

<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

$estado = 'abierta';   // prueba también: 'resuelta'
?>
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <title>Estado de la incidencia</title>
</head>
<body>
  <h1>Incidencia #1</h1>
  <p>Estado actual: <?= htmlspecialchars($estado) ?></p>

  <?php if ($estado === 'abierta'): ?>
    <button>Marcar como resuelta</button>
  <?php else: ?>
    <button disabled>Ya resuelta</button>
  <?php endif ?>
</body>
</html>

Guarda el fichero y accede desde el navegador a http://gestor.local/estado.php.

Pista si el navegador muestra código PHP en lugar de la página

Si ves texto como <?php if ... en el navegador, Apache no está interpretando PHP. Revisa que el módulo PHP esté habilitado: sudo a2enmod php8.3 (o la versión que tengas instalada) y después sudo systemctl reload apache2. Si el navegador da 404, comprueba que el fichero está en ~/gestor/public/ y no en otra ruta.

Responde en RESPUESTAS.md, sección ## Paso 1.

Cambia $estado a 'resuelta' y recarga. ¿Qué diferencias ves en la página? ¿Por qué el botón cambia solo al modificar esa variable?

Captura requerida. Guarda en capturas/paso1_boton_abierta.png una captura del navegador con $estado = 'abierta'. Debe verse:

  • La URL http://gestor.local/estado.php en la barra de direcciones.
  • El texto "Estado actual: abierta".
  • El botón "Marcar como resuelta" activo (no deshabilitado).

Antes de pasar al Paso 2

Deja finalmente $estado = 'abierta'; en el fichero. Los pasos siguientes asumen ese valor inicial.

Verificación antes de pasar al Paso 2.

  • ~/gestor/public/estado.php existe y se abre en http://gestor.local/estado.php.
  • Con $estado = 'abierta' aparece el botón activo.
  • Con $estado = 'resuelta' aparece el botón deshabilitado.
  • He guardado capturas/paso1_boton_abierta.png.
  • El fichero queda con $estado = 'abierta';.

Paso 2 — if / elseif / else: varios casos

Conceptos

  • elseif encadena condiciones. PHP evalúa las condiciones en orden y ejecuta solo el primer bloque cuya condición sea verdadera.
  • Equivale al elif de bash. El else final es el caso "ninguna de las anteriores".
  • Si ninguna condición es verdadera y no hay else, simplemente no se ejecuta nada.

Objetivo. Mostrar una etiqueta distinta según la prioridad de la incidencia.

Tarea 1 — Añadir $prioridad al bloque PHP. En el bloque PHP inicial de estado.php, justo después de la línea $estado = 'abierta'; y antes del ?>, añade:

$prioridad = 'alta';   // prueba también: 'media', 'baja', 'desconocida'

Tarea 2 — Añadir el bloque de condicionales en el HTML. En el HTML, justo antes de la etiqueta </body> (es decir, al final del <body>, después del <?php endif ?> del botón del Paso 1), añade este bloque:

<p>Prioridad:
<?php if ($prioridad === 'alta'): ?>
  <strong>URGENTE — atender cuanto antes</strong>
<?php elseif ($prioridad === 'media'): ?>
  Prioridad media — planificar para esta semana
<?php elseif ($prioridad === 'baja'): ?>
  Prioridad baja — cuando haya tiempo
<?php else: ?>
  (prioridad no reconocida)
<?php endif ?>
</p>

Guarda y recarga la página probando los 4 valores de $prioridad.

Pista

Si al añadir el bloque la página se rompe, mira si has cerrado todos los endif. Cada if / elseif / else necesita un endif al final del bloque.

Si la página sale completamente en blanco o con HTTP ERROR 500 y no ves ningún mensaje que te indique qué línea revisar, es que display_errors está apagado en php.ini. Vuelve al Paso 5 del lab A1 — Depuración: ver los errores de PHP — y actívalo: en lugar de la pantalla en blanco aparecerá el "Parse error" con la línea exacta. Una vez hecho, no tendrás que volver a tocarlo en los próximos labs.

Responde en RESPUESTAS.md, sección ## Paso 2.

¿Qué ocurre cuando pones $prioridad = 'desconocida'? ¿Por qué aparece ese mensaje concreto y no otro?

Captura requerida. Guarda en capturas/paso2_prioridad_alta.png una captura con $prioridad = 'alta'. La página tiene también lo del Paso 1 (botón de estado) porque hemos ido ampliando el mismo fichero; la captura puede mostrar la página entera. Lo que debe verse sí o sí:

  • La URL http://gestor.local/estado.php.
  • El texto "URGENTE — atender cuanto antes" en negrita.

Verificación.

  • Con $prioridad = 'alta' aparece "URGENTE".
  • Con $prioridad = 'media' aparece el texto de media.
  • Con $prioridad = 'baja' aparece el texto de baja.
  • Con $prioridad = 'desconocida' aparece "(prioridad no reconocida)".
  • He guardado capturas/paso2_prioridad_alta.png.

Paso 3 — ??: leer un parámetro de la URL con valor por defecto

Conceptos

  • Cliente → servidor: cuando escribes ?estado=resuelta en la URL del navegador, ese texto viaja al servidor. Apache recibe la URL completa, ejecuta estado.php y le pasa los parámetros a PHP. Tu navegador no procesa esa información: solo la envía.
  • $_GET es un array asociativo donde PHP coloca automáticamente los parámetros que vienen tras el ? de la URL para que tú los leas. Por ejemplo, en estado.php?estado=resuelta, $_GET['estado'] vale 'resuelta'.
  • Si la URL no trae ese parámetro, $_GET['estado'] no existe y acceder a él da un aviso.
  • El operador ?? (null coalescing) devuelve el valor de la izquierda si existe y no es null, y si no, el de la derecha. Es perfecto para "coge esto, y si no hay nada, pon esto por defecto".
$estado = $_GET['estado'] ?? 'abierta';
// Si la URL trae ?estado=X, $estado vale X. Si no, vale 'abierta'.

Objetivo. Hacer que el estado de la incidencia venga de la URL en lugar de estar fijo en el código.

Tarea. En el bloque PHP inicial, sustituye:

$estado = 'abierta';

por:

$estado = $_GET['estado'] ?? 'abierta';

Prueba las tres URLs siguientes y observa cómo cambia la página:

  • http://gestor.local/estado.php (sin parámetro → debería usar el valor por defecto).
  • http://gestor.local/estado.php?estado=resuelta (debería mostrar el botón deshabilitado).
  • http://gestor.local/estado.php?estado=abierta (debería mostrar el botón activo).
Pista

No uses comillas al escribir el parámetro en la barra de direcciones del navegador. La URL correcta es estado.php?estado=resuelta, sin comillas ni espacios.

Responde en RESPUESTAS.md, sección ## Paso 3.

En tu captura has visitado http://gestor.local/estado.php?estado=resuelta. ¿Qué valor toma $estado en ese caso? ¿Y qué valor tomaría si visitaras la misma página sin ningún ?estado=... (la URL pelada http://gestor.local/estado.php)? Explica en una frase qué hace el operador ??.

Captura requerida. Guarda en capturas/paso3_url_resuelta.png una captura visitando http://gestor.local/estado.php?estado=resuelta. Debe verse:

  • La URL completa con ?estado=resuelta en la barra de direcciones.
  • El texto "Estado actual: resuelta".
  • El botón "Ya resuelta" deshabilitado (en gris).

Verificación.

  • Sin parámetro en la URL, la página muestra el estado por defecto.
  • Con ?estado=resuelta, la página muestra ese estado y el botón deshabilitado.
  • He guardado capturas/paso3_url_resuelta.png.

Paso 4 — Filtrar dentro de un foreach y mostrar mensaje si la lista está vacía

Conceptos

  • Filtrar dentro de un bucle: si dentro del foreach (que ya viste en el Lab 03) pones un if, decides elemento por elemento si lo muestras o no. Cada vuelta del foreach ejecuta el if con la incidencia actual; si la condición se cumple, se pinta el <li>; si no, la iteración pasa a la siguiente sin imprimir nada. Paralelismo con bash: es como for x in $lista; do if [ ... ]; then echo "$x"; fi; done.
  • Comprobar si una lista está vacía con empty(): la función empty($array) devuelve true si el array está vacío o no existe, y false si tiene al menos un elemento. Combinada con if/else, te permite mostrar un mensaje alternativo cuando no hay datos en lugar de una lista vacía sin contexto.
    • $estado (del Paso 3) → viene de la URL ($_GET['estado'] ?? 'abierta') y controla el botón del Paso 1.
    • $inc['estado'] (de este paso) → es el estado de cada incidencia concreta dentro del foreach.

    Dos variables estado distintas: en este paso vas a tener dos variables parecidas en el mismo fichero, y es importante no confundirlas:

    En este paso filtramos por el literal 'abierta'. En el Paso 5 las combinarás (filtrar $inc['estado'] comparándolo con el $estado que viene de la URL).

Objetivo. Añadir al final de la página una lista solo con las incidencias 'abierta', y un mensaje alternativo si la lista de incidencias está vacía.

Ajuste previo del <h1>

Hasta ahora el <h1> del fichero dice Incidencia #1, pero a partir de aquí vamos a mostrar varias incidencias. Antes de empezar las tareas, cambia el <h1>Incidencia #1</h1> por un título más genérico:

<h1>Gestor de incidencias</h1>

La captura del Paso 3 ya está guardada con el título antiguo: no la rehagas.

Tarea 1 — Añadir el array de incidencias. Al inicio del bloque PHP de estado.php (antes de $estado = $_GET['estado'] ?? 'abierta';), añade un array con 4 incidencias de ejemplo:

1
2
3
4
5
6
$incidencias = [
    ['id' => 1, 'titulo' => 'Impresora sin tóner',    'estado' => 'abierta'],
    ['id' => 2, 'titulo' => 'Proyector sin imagen',   'estado' => 'resuelta'],
    ['id' => 3, 'titulo' => 'Wifi caído en aula 201', 'estado' => 'abierta'],
    ['id' => 4, 'titulo' => 'Teclado de recepción',   'estado' => 'resuelta'],
];

Tarea 2 — Añadir el bloque HTML con filtrado y mensaje alternativo. En el HTML, justo antes de la etiqueta </body> (al final del <body>, después del <p>Prioridad: ...</p> del Paso 2), añade este bloque:

<h2>Incidencias abiertas</h2>
<?php if (empty($incidencias)): ?>
  <p>No hay incidencias registradas.</p>
<?php else: ?>
  <ul>
  <?php foreach ($incidencias as $inc): ?>
    <?php if ($inc['estado'] === 'abierta'): ?>
      <li>#<?= $inc['id'] ?><?= htmlspecialchars($inc['titulo']) ?></li>
    <?php endif ?>
  <?php endforeach ?>
  </ul>
<?php endif ?>

Fíjate en la estructura: el if (empty(...)) / else exterior decide entre mensaje o lista, y el foreach + if interior recorre y filtra.

Guarda y recarga. Deben aparecer solo 2 elementos en la lista (los de estado abierta).

Tarea 3 — Probar el caso de lista vacía. Cambia temporalmente la línea del array a:

$incidencias = [];

Recarga la página: ahora debes ver el mensaje "No hay incidencias registradas." en lugar del <ul>. Vuelve a poner las 4 incidencias originales antes de hacer la captura.

Pista

Cada foreach necesita su endforeach al final, igual que cada if necesita su endif. Presta atención a cerrar los bloques en el orden correcto: primero el if interior del filtrado, después el foreach, y al final el endif del if (empty(...)) exterior.

Responde en RESPUESTAS.md, sección ## Paso 4.

  1. Si quisieras mostrar todas las incidencias (no solo las abiertas), ¿qué única línea tendrías que cambiar en el bloque HTML? ¿Y para mostrar solo las resueltas?
  2. Cuando dejaste temporalmente $incidencias = [], ¿qué mostró la página? Explica con tus palabras qué hace empty($incidencias) cuando el array tiene 4 elementos y cuando no tiene ninguno.

Captura requerida. Con las 4 incidencias originales en el array, guarda en capturas/paso4_lista_filtrada.png una captura con la lista visible. Debe verse:

  • La URL en la barra de direcciones.
  • El encabezado "Incidencias abiertas".
  • Exactamente 2 elementos en la lista: "#1 — Impresora sin tóner" y "#3 — Wifi caído en aula 201".

Verificación.

  • El array $incidencias está definido al inicio del fichero, con las 4 incidencias originales.
  • El bloque HTML envuelve el <ul> con if (empty($incidencias)) / else.
  • Con el array lleno, la lista muestra solo las 2 incidencias 'abierta'.
  • Con $incidencias = [], la página muestra "No hay incidencias registradas." y no hay <ul>.
  • He guardado capturas/paso4_lista_filtrada.png con el array lleno.

Paso 5 — Aplica lo aprendido: filtrado interactivo con enlaces

Qué es este paso

Los cuatro pasos anteriores han sido guiados: te he dado el código y tú lo has tecleado, probado y respondido. En este quinto paso no hay código de referencia. Lo que hay son requisitos, y tú aplicas lo aprendido para cumplirlos.

Vas a unir las cuatro herramientas vistas: $_GET con ?? para leer un parámetro, if/elseif/else para decidir, foreach con if para filtrar, y empty() con if/else para mostrar mensaje alternativo. La página tendrá tres enlaces que cambian la URL al pulsarse, y según el enlace que se pulse la lista mostrará todas las incidencias, solo las abiertas o solo las resueltas.

Objetivo. Ampliar estado.php con tres enlaces que filtren la lista por estado mediante la URL.

Tarea. Modifica ~/gestor/public/estado.php cumpliendo los requisitos siguientes.

Requisitos obligatorios de contenido:

  1. Renombra el <h2>Incidencias abiertas</h2> del Paso 4 a <h2>Incidencias filtradas</h2> (la lista ya no es solo de abiertas).
  2. Añade tres enlaces justo encima de ese <h2>, dentro de un <p>. Cada enlace apunta a la misma página estado.php pero con un valor distinto del parámetro estado en la URL:
    • "Todas" → ?estado=todos
    • "Abiertas" → ?estado=abierta
    • "Resueltas" → ?estado=resuelta
  3. Cambia el if del filtrado del Paso 4 para usar el $estado que viene de la URL en lugar del literal 'abierta'. La regla es:
    • Si $estado === 'todos', muestra todas las incidencias.
    • Si $estado === 'abierta' o 'resuelta', muestra solo las que coinciden.
  4. Mantén el if (empty($incidencias)) exterior del Paso 4 con su mensaje alternativo. La estructura general (mensaje o lista) no cambia.
  5. Cambia el valor por defecto de $estado: ahora será 'todos' en lugar de 'abierta', para que al entrar sin parámetro se vean todas.

Requisitos de presentación HTML:

  • Los tres enlaces aparecen visiblemente sobre la lista, separados por algún carácter (|, · o similar) o como una lista <ul>.
  • Cada enlace lleva al usuario a la misma página estado.php con el filtro correspondiente.

Requisitos de calidad del código:

  • htmlspecialchars() en cualquier valor de texto dinámico que vaya al HTML.

Visita http://gestor.local/estado.php y prueba los tres enlaces. Después prueba a teclear directamente las URL: ?estado=todos, ?estado=abierta, ?estado=resuelta.

Pista sobre cómo escribir los enlaces

Tres <a href="?estado=valor">texto</a> separados, dentro de un <p>. Por ejemplo:

<p>
  <a href="?estado=todos">Todas</a> |
  <a href="?estado=abierta">Abiertas</a> |
  <a href="?estado=resuelta">Resueltas</a>
</p>

Fíjate en href="?estado=todos": la URL empieza directamente con ?, sin nombre de fichero. Eso significa "la misma página actual, con este parámetro". El navegador interpreta el href relativo a la URL en la que estás.

Pista sobre el filtrado con condición compuesta

Una forma elegante: dentro del foreach, usa una condición con || (o lógico) que diga "muestra si el filtro es 'todos' o si el estado de la incidencia coincide con el filtro":

<?php if ($estado === 'todos' || $inc['estado'] === $estado): ?>

|| significa "uno u otro": basta con que una de las dos condiciones sea verdadera para que se ejecute el bloque.

Responde en RESPUESTAS.md, sección ## Paso 5.

  1. Cuando pulsas el enlace "Abiertas", ¿qué cambia en la URL del navegador? ¿Y qué hace PHP con ese cambio? Describe el viaje del clic en una frase: del navegador a Apache a tu código PHP y de vuelta.
  2. ¿Qué ocurre si tecleas http://gestor.local/estado.php?estado=imposible (un valor que ningún elemento tiene)? ¿Sale el mensaje "No hay incidencias registradas." o sale otra cosa? Explica por qué (pista: piensa en si el array $incidencias está vacío o no en ese caso).

Captura requerida. Pulsa el enlace "Resueltas" en la página y guarda en capturas/paso5_filtro_resueltas.png la captura del resultado. Debe verse:

  • La URL con ?estado=resuelta en la barra de direcciones.
  • Los tres enlaces visibles encima del <h2>.
  • La lista filtrada mostrando solo las 2 incidencias resueltas.

Verificación.

  • estado.php tiene tres enlaces <a href="?estado=..."> con valores todos, abierta y resuelta.
  • Al pulsar cada enlace, la URL cambia y la lista filtra correctamente.
  • El filtrado usa $estado (de URL) en lugar del literal 'abierta'.
  • El if (empty($incidencias)) del Paso 4 sigue presente.
  • El valor por defecto de $estado es 'todos'.
  • He guardado capturas/paso5_filtro_resueltas.png.

Checklist final de entrega

Antes de subir el ZIP al Campus, revisa uno a uno:

  • He creado la carpeta apellido_nombre_lab04/ (con mi apellido y nombre reales).
  • Dentro hay gestor/public/estado.php con el código final del Paso 5.
  • Dentro hay capturas/ con los 5 PNG: paso1_boton_abierta.png, paso2_prioridad_alta.png, paso3_url_resuelta.png, paso4_lista_filtrada.png, paso5_filtro_resueltas.png.
  • Dentro hay RESPUESTAS.md con las 5 secciones rellenas.
  • El fichero estado.php no tiene errores de sintaxis (compruébalo con php -l ~/gestor/public/estado.php).
  • El ZIP se llama apellido_nombre_lab04.zip y al descomprimirlo solo aparece una carpeta raíz con ese nombre.
  • He subido el ZIP a la tarea correspondiente en el Campus antes de la fecha límite.

Anexo — Plantilla de RESPUESTAS.md

Crea un fichero llamado RESPUESTAS.md dentro de apellido_nombre_lab04/ con esta plantilla y rellena cada sección:

# Respuestas — Lab 04 Condicionales

**Nombre:** Apellido, Nombre
**Fecha:** YYYY-MM-DD

## Paso 1

(Tu respuesta: diferencias al cambiar `$estado` a `'resuelta'` y por qué el botón cambia.)

## Paso 2

(Tu respuesta: qué ocurre con `$prioridad = 'desconocida'` y por qué.)

## Paso 3

(Tu respuesta: valor de `$estado` con `?estado=resuelta` y sin parámetro, y qué hace `??`.)

## Paso 4

1. (Tu respuesta: qué línea cambiarías para mostrar todas las incidencias, y qué línea para mostrar solo las resueltas.)
2. (Tu respuesta: qué muestra la página con `$incidencias = []` y qué hace `empty()` con array lleno y vacío.)

## Paso 5

1. (Tu respuesta: qué cambia en la URL al pulsar "Abiertas" y describe el viaje del clic — navegador → Apache → PHP → respuesta.)
2. (Tu respuesta: qué ocurre con `?estado=imposible` y por qué.)