W3docs

Validación de Formularios PHP

La validación de formularios en PHP garantiza que los datos enviados por los usuarios sean correctos y seguros antes de procesarlos en el servidor.

La validación de formularios es el proceso de verificar que los datos enviados por un usuario a través de un formulario HTML estén presentes, con el formato correcto y sean seguros de usar antes de que el script actúe sobre ellos. En PHP, la validación se ejecuta en el servidor después de que se envía el formulario, por lo que no puede evitarse deshabilitando JavaScript ni enviando una solicitud directamente.

Este capítulo cubre el flujo de trabajo completo de validación: por qué importa la validación del lado del servidor, la diferencia entre sanear y validar, las funciones PHP que usarás, y un ejemplo completo y seguro que puedes adaptar. Si eres nuevo en el manejo de entradas de formularios, lee primero Manejo de Formularios PHP.

Por Qué Importa la Validación del Lado del Servidor

La validación del lado del cliente (HTML5 required, type="email", JavaScript) mejora la experiencia del usuario al detectar errores al instante, pero es solo una comodidad. Un usuario determinado o malicioso puede deshabilitar JavaScript o enviar una solicitud HTTP manipulada que omita el navegador por completo. El servidor es el único lugar donde se puede confiar en la validación. La validación PHP del lado del servidor te permite:

  • Garantizar que los campos obligatorios estén realmente presentes y no vacíos.
  • Confirmar que los valores coincidan con el formato esperado (un correo electrónico real, un número en rango).
  • Neutralizar entradas peligrosas antes de que lleguen a una base de datos o a una página HTML, previniendo la inyección SQL y el cross-site scripting (XSS).

Trata cada valor en $_POST, $_GET y $_REQUEST como no confiable hasta que lo hayas verificado. Estos arrays provienen de las superglobales de PHP.

Saneamiento vs. Validación

Estos dos términos suelen confundirse, pero hacen trabajos diferentes:

  • Sanear limpia un valor: elimina o escapa los caracteres no deseados. trim() elimina los espacios en blanco circundantes; htmlspecialchars() convierte <, >, & y las comillas en entidades HTML para que se rendericen como texto en lugar de ejecutarse.
  • Validar verifica un valor contra una regla y devuelve aprobado o fallido; no cambia el valor. filter_var($email, FILTER_VALIDATE_EMAIL) devuelve el correo electrónico si parece válido, o false si no.

El flujo típico es: sanear primero (recortar espacios en blanco), luego validar y finalmente escapar en la salida (al mostrar en HTML). Para una cobertura más profunda del sistema de filtrado de PHP, consulta Filtros PHP y filter_var().

Pasos de Validación

Una rutina de validación del lado del servidor suele seguir los mismos cuatro pasos:

  1. Construir el formulario HTML y apuntar su action al script PHP.
  2. Detectar un envío POST con $_SERVER["REQUEST_METHOD"].
  3. Para cada campo: leer el valor, sanearlo y luego validarlo, recopilando cualquier mensaje de error.
  4. Si todos los campos pasaron, procesar los datos; de lo contrario, volver a renderizar el formulario con los mensajes de error y los valores que el usuario ya escribió.

Funciones PHP de Validación Útiles

FunciónPropósito
trim()Elimina los espacios en blanco del inicio y el final de una cadena.
empty()Verifica si un valor falta o es una cadena vacía.
filter_var()Valida o sanea usando un filtro integrado (p. ej., FILTER_VALIDATE_EMAIL, FILTER_VALIDATE_INT).
is_numeric()Devuelve true si el valor es un número o una cadena numérica.
htmlspecialchars()Escapa los caracteres especiales HTML para prevenir XSS en la salida.
preg_match()Valida contra un patrón de expresión regular personalizado.

Un Ejemplo Mínimo

Antes del ejemplo completo con base de datos que aparece a continuación, aquí está la validación más pequeña que captura el patrón básico: sanear, luego validar, luego recopilar errores:

<?php
$email = trim($_POST["email"] ?? "");
$errors = [];

if ($email === "") {
    $errors["email"] = "Please enter your email.";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors["email"] = "Please enter a valid email address.";
}

if (empty($errors)) {
    echo "Valid email: " . htmlspecialchars($email);
} else {
    echo $errors["email"];
}
?>

Si $_POST["email"] es " [email protected] ", los espacios circundantes se recortan, el valor se valida y el script imprime Valid email: [email protected]. Una entrada como "not-an-email" produce Please enter a valid email address.

Ejemplo Completo: Validar y Almacenar un Formulario

El ejemplo a continuación valida un nombre, correo electrónico, género y comentario, y luego inserta la fila usando una sentencia preparada. El enfoque de sentencias preparadas (con mysqli) es lo que te protege de la inyección SQL, porque la entrada del usuario se envía por separado del texto SQL y nunca se interpreta como código.

Actualiza las credenciales de la base de datos y asegúrate de que tu base de datos contenga una tabla users con las columnas name, email, gender y comment antes de ejecutar este ejemplo.

<?php
// Database connection setup
$link = mysqli_connect("localhost", "username", "password", "database");
if (!$link) {
    die("Connection failed: " . mysqli_connect_error());
}

// Define variables and initialize with empty values
$name = $email = $gender = $comment = $website = "";
$name_err = $email_err = $gender_err = $comment_err = "";
 
// Processing form data when form is submitted
if($_SERVER["REQUEST_METHOD"] == "POST"){
    // Validate name
    if(empty(trim($_POST["name"] ?? ""))){
        $name_err = "Please enter your name.";
    } else{
        $name = trim($_POST["name"]);
    }
    
    // Validate email
    if(empty(trim($_POST["email"] ?? ""))){
        $email_err = "Please enter your email.";
    } elseif(!filter_var(trim($_POST["email"] ?? ""), FILTER_VALIDATE_EMAIL)) {
        $email_err = "Please enter a valid email address.";
    } else{
        $email = trim($_POST["email"]);
    }
    
    // Validate gender
    if(!isset($_POST["gender"]) || empty($_POST["gender"])){
        $gender_err = "Please select your gender.";
    } else{
        $gender = $_POST["gender"];
    }
    
    // Validate comment
    if(empty(trim($_POST["comment"] ?? ""))){
        $comment_err = "Please enter your comment.";
    } else{
        $comment = trim($_POST["comment"]);
    }
    
    // Check input errors before inserting in database
    if(empty($name_err) && empty($email_err) && empty($gender_err) && empty($comment_err)){
        // Prepare an insert statement
        $sql = "INSERT INTO users (name, email, gender, comment) VALUES (?, ?, ?, ?)";
         
        if($stmt = mysqli_prepare($link, $sql)){
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "ssss", $param_name, $param_email, $param_gender, $param_comment);
            
            // Set parameters
            $param_name = $name;
            $param_email = $email;
            $param_gender = $gender;
            $param_comment = $comment;
            
            // Attempt to execute the prepared statement
            if(mysqli_stmt_execute($stmt)){
                // Records created successfully. Redirect to landing page
                header("location: index.php");
                exit();
            } else{
                echo "Something went wrong. Please try again later.";
            }
        }
         
        // Close statement
        mysqli_stmt_close($stmt);
    }
}

// Close connection
mysqli_close($link);
?>
<!DOCTYPE html>
<html>
<head><title>PHP Form Validation</title></head>
<body>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
    Name: <input type="text" name="name" value="<?php echo htmlspecialchars($name); ?>">
    <span class="error"><?php echo $name_err; ?></span><br><br>
    Email: <input type="text" name="email" value="<?php echo htmlspecialchars($email); ?>">
    <span class="error"><?php echo $email_err; ?></span><br><br>
    Gender:
    <input type="radio" name="gender" value="female"> Female
    <input type="radio" name="gender" value="male"> Male
    <span class="error"><?php echo $gender_err; ?></span><br><br>
    Comment: <textarea name="comment"><?php echo htmlspecialchars($comment); ?></textarea>
    <span class="error"><?php echo $comment_err; ?></span><br><br>
    <input type="submit" value="Submit">
</form>
</body>
</html>

Mostrar Errores y Conservar la Entrada del Usuario

Observa tres detalles en el ejemplo que hacen una buena UX de formularios:

  • Cada variable de error ($name_err, $email_err, …) se imprime en un <span class="error"> junto a su campo, para que el usuario sepa exactamente qué entrada corregir.
  • El action del formulario muestra htmlspecialchars($_SERVER["PHP_SELF"]). Sin el escape, PHP_SELF puede explotarse para inyectar scripts a través de la URL, por lo que escaparlo es una medida de seguridad, no solo de formato.
  • Cada valor que se vuelve a mostrar en el formulario pasa por htmlspecialchars(). Esto tanto previene el XSS como permite que el usuario conserve lo que ya escribió en lugar de tener que volver a introducir todo después de un campo inválido.

Errores Comunes

  • empty() trata "0" como vacío. Un campo cuyo valor es la cadena "0" fallará una verificación con empty(). Para campos donde 0 es válido, compara explícitamente: if ($value === "").
  • Valida antes de confiar en el tipo. Los valores de $_POST siempre son cadenas. Usa filter_var($n, FILTER_VALIDATE_INT) o is_numeric() en lugar de asumir que llegó un número.
  • Escapa en la salida, no en el almacenamiento. Guarda el valor sin procesar (validado) en la base de datos y aplica htmlspecialchars() solo al mostrar en HTML. Escapar antes del almacenamiento corrompe los datos para usos que no sean HTML.
  • Usa el operador de fusión nula. $_POST["x"] ?? "" evita las advertencias de "Undefined array key" cuando falta un campo.

Validar Otros Tipos de Campos

El mismo patrón se extiende a cualquier campo; solo cambia la regla de validación:

<?php
// Age: an integer between 18 and 120
$age = filter_var($_POST["age"] ?? "", FILTER_VALIDATE_INT, [
    "options" => ["min_range" => 18, "max_range" => 120],
]);
if ($age === false) {
    echo "Please enter an age between 18 and 120.";
}

// Username: 3-16 letters, digits, or underscores
$username = trim($_POST["username"] ?? "");
if (!preg_match('/^[A-Za-z0-9_]{3,16}$/', $username)) {
    echo "Username must be 3-16 letters, digits, or underscores.";
}
?>

Para reglas específicas de URL y correo electrónico, consulta URL y Correo Electrónico en Formularios PHP; para marcar campos como obligatorios, consulta Campos Obligatorios en Formularios PHP; y para ver todas las piezas ensambladas, consulta Formulario Completo PHP.

Conclusión

La validación del lado del servidor en PHP es lo que hace que un formulario sea confiable: confirma que los datos están presentes y tienen el formato correcto y, combinada con htmlspecialchars() en la salida y sentencias preparadas en el almacenamiento, cierra la puerta al XSS y a la inyección SQL. La receta básica es siempre la misma: sanear, validar, recopilar errores y volver a renderizar el formulario con mensajes útiles cuando algo está mal. Domina ese ciclo y podrás validar cualquier campo simplemente cambiando la regla.

Práctica

Práctica
¿Cuáles son algunos elementos clave en la validación de formularios PHP?
¿Cuáles son algunos elementos clave en la validación de formularios PHP?
Was this page helpful?