Validação de Formulários PHP
A validação de formulários é essencial no desenvolvimento web, garantindo que os dados inseridos pelos utilizadores sejam precisos e completos antes de serem processados com PHP.
A validação de formulários é o processo de verificar se os dados enviados por um utilizador através de um formulário HTML estão presentes, corretamente formatados e seguros para uso antes de o script processá-los. Em PHP, a validação é executada no servidor após o envio do formulário, por isso não pode ser contornada desativando JavaScript ou enviando uma solicitação diretamente.
Este capítulo aborda o fluxo completo de validação: por que a validação no lado do servidor é importante, a diferença entre sanitizar e validar, as funções PHP que serão utilizadas, e um exemplo completo e seguro que pode ser adaptado. Se você é novo no recebimento de dados de formulários, leia primeiro Tratamento de Formulários PHP.
Por que a Validação no Lado do Servidor É Importante
A validação no lado do cliente (HTML5 required, type="email", JavaScript) melhora a experiência do utilizador ao capturar erros instantaneamente — mas é apenas uma conveniência. Um utilizador determinado ou malicioso pode desativar o JavaScript ou enviar uma solicitação HTTP elaborada que ignora completamente o navegador. O servidor é o único lugar onde a validação pode ser confiável. A validação PHP no lado do servidor permite:
- Garantir que os campos obrigatórios estejam realmente presentes e não vazios.
- Confirmar que os valores correspondem ao formato esperado (um e-mail real, um número dentro do intervalo).
- Neutralizar entradas perigosas antes que cheguem a um banco de dados ou a uma página HTML, prevenindo SQL injection e cross-site scripting (XSS).
Trate cada valor em $_POST, $_GET e $_REQUEST como não confiável até que tenha sido verificado. Esses arrays vêm das superglobais do PHP.
Sanitizar vs. Validar
Esses dois termos são frequentemente confundidos, mas desempenham funções diferentes:
- Sanitizar limpa um valor — remove ou escapa caracteres indesejados.
trim()remove espaços em branco ao redor;htmlspecialchars()converte<,>,&e aspas em entidades HTML para que sejam renderizados como texto em vez de serem executados. - Validar verifica um valor contra uma regra e informa aprovação ou reprovação — não altera o valor.
filter_var($email, FILTER_VALIDATE_EMAIL)retorna o e-mail se parecer válido, oufalsecaso contrário.
Um fluxo típico é: sanitizar primeiro (remover espaços em branco), depois validar, e por fim escapar na saída (ao ecoar de volta para HTML). Para uma cobertura mais aprofundada do sistema de filtragem do PHP, veja Filtros PHP e filter_var().
Etapas de Validação
Uma rotina de validação no lado do servidor geralmente segue as mesmas quatro etapas:
- Construir o formulário HTML e apontar seu
actionpara o script PHP. - Detectar um envio
POSTcom$_SERVER["REQUEST_METHOD"]. - Para cada campo: ler o valor, sanitizá-lo, depois validá-lo — coletando mensagens de erro.
- Se todos os campos passarem, processar os dados; caso contrário, renderizar novamente o formulário com as mensagens de erro e os valores que o utilizador já digitou.
Funções PHP de Validação Úteis
| Função | Finalidade |
|---|---|
trim() | Remove espaços em branco do início e do fim de uma string. |
empty() | Verifica se um valor está ausente ou é uma string vazia. |
filter_var() | Valida ou sanitiza usando um filtro embutido (ex.: FILTER_VALIDATE_EMAIL, FILTER_VALIDATE_INT). |
is_numeric() | Retorna true se o valor for um número ou string numérica. |
htmlspecialchars() | Escapa caracteres especiais HTML para prevenir XSS na saída. |
preg_match() | Valida contra um padrão de expressão regular personalizado. |
Um Exemplo Mínimo
Antes do exemplo completo com banco de dados abaixo, aqui está a validação mais simples que captura o padrão principal — sanitizar, depois validar, depois coletar erros:
<?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"];
}
?>Se $_POST["email"] for " [email protected] ", os espaços ao redor são removidos, o valor é validado e o script exibe Valid email: [email protected]. Uma entrada como "not-an-email" produz Please enter a valid email address.
Exemplo Completo: Validando e Armazenando um Formulário
O exemplo abaixo valida um nome, e-mail, gênero e comentário, e depois insere a linha usando uma prepared statement — a abordagem de prepared statement (com mysqli) é o que protege contra SQL injection, pois a entrada do utilizador é enviada separadamente do texto SQL e nunca é interpretada como código.
Atualize as credenciais do banco de dados e certifique-se de que seu banco de dados contenha uma tabela users com colunas name, email, gender e comment antes de executar este exemplo.
<?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>Exibindo Erros e Mantendo a Entrada do Utilizador
Observe três detalhes no exemplo que proporcionam uma boa UX para formulários:
- Cada variável de erro (
$name_err,$email_err, …) é exibida em um<span class="error">ao lado do seu campo, para que o utilizador saiba exatamente qual entrada corrigir. - O
actiondo formulário echoahtmlspecialchars($_SERVER["PHP_SELF"]). Sem o escape,PHP_SELFpode ser explorado para injetar scripts através da URL, portanto escapá-lo é uma medida de segurança, não apenas de formatação. - Cada valor re-exibido no formulário é passado por
htmlspecialchars(). Isso tanto previne XSS quanto permite que o utilizador mantenha o que já digitou, em vez de reinserir tudo depois de um campo inválido.
Problemas Comuns
empty()trata"0"como vazio. Um campo cujo valor é a string"0"falhará em uma verificação comempty(). Para campos onde0é válido, compare explicitamente:if ($value === "").- Valide antes de confiar no tipo. Os valores de
$_POSTsão sempre strings. Usefilter_var($n, FILTER_VALIDATE_INT)ouis_numeric()em vez de assumir que um número chegou. - Escape na saída, não no armazenamento. Armazene o valor bruto (validado) no banco de dados e aplique
htmlspecialchars()apenas ao ecoar em HTML. Escapar antes do armazenamento corrompe os dados para usos não-HTML. - Use o operador null-coalescing.
$_POST["x"] ?? ""evita avisos de "Undefined array key" quando um campo está ausente.
Validando Outros Tipos de Campo
O mesmo padrão se aplica a qualquer campo — apenas a regra de validação muda:
<?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 regras específicas de URL e e-mail, veja URL e E-mail em Formulários PHP; para marcar campos como obrigatórios, veja Campos Obrigatórios em Formulários PHP; e para ver todas as peças reunidas, veja Formulário Completo PHP.
Conclusão
A validação no lado do servidor em PHP é o que torna um formulário confiável: confirma que os dados estão presentes e corretamente formatados, e — combinada com htmlspecialchars() na saída e prepared statements no armazenamento — bloqueia XSS e SQL injection. A receita básica é sempre a mesma: sanitizar, validar, coletar erros e renderizar novamente o formulário com mensagens úteis quando algo estiver errado. Domine esse ciclo e poderá validar qualquer campo simplesmente trocando a regra de validação.