Validación y Sanitización de Datos en PHP
Vamos a ver como procesar entradas de usuarios (por ejemplo, de formularios HTML) para garantizar que sean
seguras y válidas. Cubriremos funciones como filter_input()
, filter_var()
, técnicas de
sanitización (htmlspecialchars()
, strip_tags()
), y el uso de expresiones regulares para
validación.
¿Qué son Validación y Sanitización?
- Validación: Verifica que los datos cumplen reglas específicas (por ejemplo, un correo válido o un número positivo).
- Sanitización: Limpia los datos para eliminar contenido peligroso.
Valida primero, luego sanitiza si es necesario. Nunca confíes en datos de usuarios sin procesarlos.
filter_input() y filter_var()
PHP ofrece funciones específicas para validar datos de entrada de forma segura:
filter_input(tipo, nombre, filtro, opciones)
: Extrae y valida directamente una variable externa (por ejemplo, desde$_GET
,$_POST
, etc.).filter_var(variable, filtro, opciones)
: Aplica un filtro a una variable ya obtenida.
PHP incluye una serie de filtros predefinidos para validar o sanear datos. Estos filtros se identifican mediante constantes como FILTER_VALIDATE_EMAIL
o FILTER_VALIDATE_INT
.
FILTER_VALIDATE_EMAIL
: Comprueba si el valor es un correo válido.FILTER_VALIDATE_INT
: Comprueba si es un número entero válido (se puede limitar con un rango).FILTER_SANITIZE_*
: Existen también filtros para limpiar entradas (por ejemplo, eliminar etiquetas HTML o caracteres no válidos).
Estos filtros están disponibles como constantes definidas por PHP en el núcleo (no hay que importarlas ni definirlas). Puedes ver la lista completa en la documentación oficial: php.net.
Ejemplo: Validar un correo electrónico enviado por POST
<?php
declare(strict_types=1);
// Obtiene y valida un correo desde $_POST["email"]
$email = filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL) ?? "";
if ($email !== "") {
echo "Correo válido: <b>$email</b>";
} else {
echo "Correo inválido";
}
?>
Ejemplo: Validar un número entero entre 18 y 120
<?php
declare(strict_types=1);
// Valida que "edad" sea un número entero dentro del rango permitido
$edad = filter_input(INPUT_POST, "edad", FILTER_VALIDATE_INT, [
"options" => ["min_range" => 18, "max_range" => 120]
]) ?? 0;
if ($edad !== 0) {
echo "Edad válida: <b>$edad</b>";
} else {
echo "Edad inválida";
}
?>
También puedes usar filter_var()
si ya tienes la variable en una forma tradicional, como $email = $_POST["email"];
<?php
$email = $_POST["email"] ?? "";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "Correo válido";
} else {
echo "Correo inválido";
}
?>
Sanear datos con FILTER_SANITIZE_*
Además de validar, PHP permite sanear (limpiar) entradas eliminando caracteres no válidos o peligrosos. Esto se hace con filtros como:
FILTER_SANITIZE_EMAIL
: Elimina caracteres no permitidos en correos.FILTER_SANITIZE_STRING
: Elimina etiquetas HTML y caracteres especiales (obsoleto, mejorhtmlspecialchars
,strip_tags
o expresiones regularesFILTER_SANITIZE_NUMBER_INT
: Deja solo dígitos y signos +/-.
<?php
// Elimina caracteres inválidos de un correo
$email = filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL);
// Limpia una cadena eliminando etiquetas
$comentario = filter_var($_POST["comentario"] ?? "", FILTER_SANITIZE_STRING);
?>
Sanitización con htmlspecialchars() y strip_tags()
htmlspecialchars()
: Convierte caracteres especiales en entidades HTML para prevenir XSS.strip_tags()
: Elimina etiquetas HTML y PHP.
Ejemplo: Sanitizar un comentario:
<?php
declare(strict_types=1);
$comentario = filter_input(INPUT_POST, "comentario", FILTER_SANITIZE_STRING) ?? "";
$comentario = htmlspecialchars($comentario, ENT_QUOTES, "UTF-8");
// Coincide: Texto limpio (por ejemplo, "<script>" se convierte en "<script>").
// No coincide: Código ejecutable o etiquetas HTML.
echo "Comentario seguro: <b>$comentario</b>\n";
?>
Ejemplo: Eliminar etiquetas:
<?php
declare(strict_types=1);
$texto = filter_input(INPUT_POST, "texto", FILTER_SANITIZE_STRING) ?? "";
$texto = strip_tags($texto);
// Coincide: Texto sin etiquetas HTML (por ejemplo, "<p>Hola</p>" se convierte en "Hola").
// No coincide: Texto con etiquetas HTML intactas.
echo "Texto limpio: <b>$texto</b>\n";
?>
Validación con Expresiones Regulares
Las regex son útiles para validar formatos específicos. Usa el Manual de Expresiones Regulares para más detalles.
Ejemplo: Validar un nombre:
<?php
declare(strict_types=1);
$nombre = filter_input(INPUT_POST, "nombre", FILTER_SANITIZE_STRING) ?? "";
$patron = "/^[A-Za-z\s]{2,50}$/";
// Coincide: Nombres con letras y espacios, 2-50 caracteres (por ejemplo, "Ana García").
// No coincide: "A1", "", "Ana@García".
preg_match($patron, $nombre);
?>
Formulario Seguro
Combina validación y sanitización en un formulario:
<?php
declare(strict_types=1);
$nombre = filter_input(INPUT_POST, "nombre", FILTER_SANITIZE_STRING) ?? "";
$email = filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL) ?? "";
$edad = filter_input(INPUT_POST, "edad", FILTER_VALIDATE_INT, [
"options" => ["min_range" => 18, "max_range" => 120]
]) ?? 0;
$patron_nombre = "/^[A-Za-z\s]{2,50}$/";
// Coincide: Nombres válidos.
// No coincide: Nombres con números o caracteres especiales.
if (preg_match($patron_nombre, $nombre) && $email !== "" && $edad !== 0) {
$nombre = htmlspecialchars($nombre, ENT_QUOTES, "UTF-8");
echo "Datos válidos: <b>$nombre</b>, <b>$email</b>, <b>$edad</b>\n";
} else {
echo "Datos inválidos\n";
}
?>
Seguridad adicional
- Límite de longitud: Restringe el tamaño de las entradas:
<?php
if (strlen($nombre) > 50) {
exit("Nombre demasiado largo");
}
?>
- Evita inyecciones: Nunca uses datos sin validar en consultas SQL o patrones regex:
<?php
$patron = "/" . preg_quote($nombre, "/") . "/";
// Coincide: Nombre sanitizado como literal.
// No coincide: Entradas maliciosas.
?>
- Usa filtros estrictos: Prefiere
FILTER_VALIDATE_*
sobreFILTER_SANITIZE_*
para validación.