En la Unidad 1 el navegador ya validaba: required, type="email", min y max.
Esa validación es para el usuario: le avisa rápido que se equivocó. Pero no
protege al servidor, porque cualquiera puede saltársela. La validación que cuenta es
la que hace PHP.
Por qué no basta el navegador
Incorrecto: confiar en required
Abre F12, busca el <input required>, borra el atributo y envía el formulario
vacío. Llega vacío al servidor. Lo mismo se puede hacer sin navegador:
curl -X POST -d "nombre=&correo=noesuncorreo" http://localhost:8000/contacto.php
Todo lo que está en el navegador lo controla el usuario.
Correcto: validar en los dos lados
Validación
Para qué
¿Se puede saltar?
Navegador (required, type, min)
Avisar rápido, sin recargar
Sí
Servidor (PHP)
Asegurar que el dato sirve antes de usarlo
No
Se dejan los atributos del HTML y se valida en PHP.
El patrón
Toda validación en el curso sigue los mismos cuatro pasos.
Validar con un arreglo de errores
flowchart TD
A["POST recibido"] --> B["1. Leer cada campo<br/>con trim y ??"]
B --> C["2. Revisar cada campo<br/>y anotar el error en $errores"]
C --> D{"3. ¿$errores<br/>está vacío?"}
D -->|"sí"| E["4a. Usar los datos<br/>y confirmar"]
D -->|"no"| F["4b. Volver a mostrar el formulario<br/>con los errores y lo escrito"]
<?php$errores = [];$nombre = "";$correo = "";if ($_SERVER["REQUEST_METHOD"] === "POST") { // 1. Leer $nombre = trim($_POST["nombre"] ?? ""); $correo = trim($_POST["correo"] ?? ""); // 2. Revisar if ($nombre === "") { $errores["nombre"] = "Escribe tu nombre."; } if ($correo === "") { $errores["correo"] = "Escribe tu correo."; } elseif (filter_var($correo, FILTER_VALIDATE_EMAIL) === false) { $errores["correo"] = "El correo no tiene un formato válido."; } // 3. ¿Hay errores? if (count($errores) === 0) { // 4a. Todo bien }}
$errores es un arreglo asociativo: la clave es el name del campo y el valor
es el mensaje. Así, junto a cada campo se puede preguntar si tiene un error.
Un error por campo
Para el correo se usa elseif: si está vacío, no tiene sentido decir además que
el formato es inválido. Cada campo muestra su primer problema.
empty() da true para "", pero también para "0". Si alguien escribe 0
hijos, el campo se rechaza como vacío. Es la trampa de los
valores que cuentan como falso.
Que el <select> tenga tres opciones no impide que llegue otra: con F12 se
puede cambiar el value de una opción. Si el servidor no lo revisa con
in_array(), acepta cualquier cosa.
Un formulario completo
contacto.php entero: muestra el formulario, lo procesa, marca los errores en cada
campo y conserva lo que se escribió.
isset($errores["campo"]) muestra el mensaje debajo del campo
novalidate en el <form>
Apaga la validación del navegador solo para probar la de PHP. Quítalo al terminar
Incorrecto: perder lo que escribió el usuario
Si el formulario vuelve vacío por un solo error, el usuario tiene que escribir
todo de nuevo. Es la razón número uno por la que la gente abandona un formulario.
Correcto: el error dice qué hacer, no solo qué está mal
“Correo inválido” obliga a adivinar. “El correo no tiene un formato válido” o
“Escribe tu correo” explica qué corregir. Y el error va en texto junto al
campo, no solo en el color del borde
(Interfaces de usuario).
Pruébalo
Arma el formulario completo y envíalo vacío: cada campo muestra su error
Llena solo el nombre y envía: el nombre se conserva, el resto marca error
Escribe 0 en un campo y compara empty() con === ""
Con F12, cambia el value de una opción del <select> y comprueba que PHP lo rechaza
Error provocado: cambia la clave de un error ($errores["Nombre"]) y comprueba que el mensaje ya no aparece
Errores comunes
Síntoma
Causa
Solución
Un 0 se rechaza como campo vacío
Se usó empty()
trim() y comparar con === ""
El formulario vuelve vacío tras un error
Los value no imprimen las variables
value="<?= htmlspecialchars($campo) ?>"
Los errores no aparecen aunque el campo está mal
La clave en $errores no coincide con la del isset
Usa el name del campo como clave en los dos lugares
Checkpoint
Intenta responder antes de desplegar cada pregunta.
Si el campo ya tiene required, ¿por qué validarlo también en PHP?
Porque required vive en el navegador y el usuario lo puede quitar con F12, o
enviar la solicitud sin navegador. PHP es lo único que el usuario no controla.
¿Por qué $errores es un arreglo asociativo y no una lista?
Porque la clave dice a qué campo pertenece cada error. Así se puede mostrar cada
mensaje debajo de su campo con isset($errores["correo"]).
¿Cómo conservas lo que escribió el usuario cuando hay un error?
Imprimiendo cada variable en el value del campo (con htmlspecialchars), y
selected en la opción elegida de cada <select>.
¿Por qué empty() no sirve para revisar si un campo vino?
Porque también da true con "0": alguien que escribe 0 en un campo quedaría
rechazado como si lo hubiera dejado vacío. Se usa trim() y se compara con === "".