A validação e sanitização de dados são práticas essenciais para a segurança e integridade de qualquer aplicação web. Em PHP, a função filter_var oferece uma maneira simples e eficaz de verificar e limpar entradas do usuário, prevenindo ataques como injeção de código, XSS e outros. Nesta aula, você aprenderá a usar filter_var com diferentes filtros, entenderá a diferença entre validar e sanitizar, e compreenderá por que nunca devemos confiar em dados provenientes do cliente.

filter_var

A função filter_var é a principal ferramenta do PHP para validação e sanitização de dados. Ela recebe como parâmetros o valor a ser filtrado, o tipo de filtro (constante) e um array opcional de opções. A função retorna o valor filtrado (no caso de sanitização) ou o valor original (se a validação passar), ou false se a validação falhar.

Existem dois tipos principais de filtros: filtros de validação (constantes FILTER_VALIDATE_*) e filtros de sanitização (constantes FILTER_SANITIZE_*). Os filtros de validação verificam se o valor atende a um determinado formato (ex.: e-mail, URL, número inteiro), enquanto os filtros de sanitização removem ou codificam caracteres indesejados.

<?php
// Exemplo básico de filter_var com validação de e-mail
$email = "usuario@exemplo.com";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
    echo "E-mail válido.";
} else {
    echo "E-mail inválido.";
}

// Exemplo de sanitização: remover tags HTML
$texto = "<script>alert('XSS')</script>Olá";
$textoLimpo = filter_var($texto, FILTER_SANITIZE_STRING);
echo $textoLimpo; // Exibe: alert('XSS')Olá (tags removidas)
?>

Note que FILTER_SANITIZE_STRING está obsoleto a partir do PHP 8.1; recomenda-se usar htmlspecialchars() ou strip_tags() para remoção de tags. No entanto, a função ainda funciona em versões mais antigas.

Validando entradas

A validação de entradas consiste em verificar se os dados fornecidos pelo usuário estão no formato esperado. Isso é crucial para evitar dados malformados que possam causar erros ou vulnerabilidades. Os filtros de validação mais comuns incluem:

  • FILTER_VALIDATE_EMAIL: verifica se o valor é um endereço de e-mail válido (formato básico).
  • FILTER_VALIDATE_URL: verifica se o valor é uma URL válida (com suporte a protocolos).
  • FILTER_VALIDATE_INT: verifica se o valor é um inteiro, com opção de faixa (min_range, max_range).
  • FILTER_VALIDATE_FLOAT: verifica se o valor é um número de ponto flutuante.
  • FILTER_VALIDATE_BOOLEAN: verifica se o valor é um booleano (true, false, 1, 0, "true", "false").
  • FILTER_VALIDATE_IP: verifica se o valor é um endereço IP (IPv4 ou IPv6).
  • FILTER_VALIDATE_MAC: verifica se o valor é um endereço MAC.

Exemplo prático de validação de um campo de idade:

<?php
$idade = $_POST['idade'] ?? '';
$options = array(
    'options' => array(
        'min_range' => 0,
        'max_range' => 150
    )
);
if (filter_var($idade, FILTER_VALIDATE_INT, $options) !== false) {
    echo "Idade válida: $idade";
} else {
    echo "Idade inválida. Deve ser um número entre 0 e 150.";
}
?>

É importante lembrar que a validação deve ser feita tanto no cliente (JavaScript) quanto no servidor (PHP), mas a validação no servidor é a única confiável.

Sanitizando

A sanitização é o processo de limpar os dados, removendo ou codificando caracteres que possam ser perigosos ou indesejados. Diferente da validação, que apenas verifica, a sanitização altera o valor para torná-lo seguro. Os filtros de sanitização mais comuns incluem:

  • FILTER_SANITIZE_EMAIL: remove caracteres não permitidos em e-mails (exceto letras, dígitos e alguns símbolos).
  • FILTER_SANITIZE_URL: remove caracteres não permitidos em URLs.
  • FILTER_SANITIZE_NUMBER_INT: remove tudo que não é dígito ou sinal de menos.
  • FILTER_SANITIZE_NUMBER_FLOAT: remove tudo que não é dígito, ponto, sinal de menos ou vírgula (opções podem incluir separador decimal).
  • FILTER_SANITIZE_STRING: remove tags HTML e codifica caracteres especiais (obsoleto, use htmlspecialchars()).
  • FILTER_SANITIZE_ENCODED: codifica a string como URL (percent-encoding).
  • FILTER_SANITIZE_SPECIAL_CHARS: codifica caracteres especiais HTML (equivalente a htmlspecialchars()).

Exemplo de sanitização de um campo de nome de usuário (permitindo apenas letras e números):

<?php
$username = $_POST['username'] ?? '';
$usernameSanitizado = filter_var($username, FILTER_SANITIZE_STRING); // remove tags
// Para permitir apenas alfanuméricos, use expressão regular:
$usernameFinal = preg_replace('/[^a-zA-Z0-9]/', '', $usernameSanitizado);
echo "Nome de usuário limpo: $usernameFinal";
?>

Outra abordagem comum é usar filter_input ou filter_input_array para filtrar diretamente de superglobais como $_GET, $_POST e $_SERVER.

Por que nunca confiar no cliente

Em aplicações web, todo dado que vem do cliente (navegador) é potencialmente malicioso. O cliente pode ser um usuário mal-intencionado, ou um script automatizado que envia requisições forjadas. Mesmo que o front-end faça validação, ela pode ser facilmente contornada. Portanto, a validação e sanitização no servidor são a última linha de defesa.

Exemplos de riscos ao confiar no cliente:

  • Injeção de SQL: Se um campo de texto for usado em uma consulta SQL sem sanitização, um invasor pode inserir comandos SQL maliciosos.
  • XSS (Cross-Site Scripting): Se dados não sanitizados forem exibidos em uma página, scripts maliciosos podem ser executados no navegador de outros usuários.
  • Injeção de comandos: Se dados forem passados para funções de sistema, comandos arbitrários podem ser executados.
  • Manipulação de dados: Um usuário pode alterar campos ocultos, cookies ou cabeçalhos HTTP para burlar regras de negócio.

Para ilustrar, considere um formulário que espera um número inteiro para o campo 'quantidade'. Um invasor pode enviar uma string como "1; DROP TABLE produtos; --" se não houver validação. Com filter_var e validação de inteiro, isso é bloqueado.

<?php
// Simulação de entrada maliciosa
$quantidade = "1; DROP TABLE produtos; --";
if (filter_var($quantidade, FILTER_VALIDATE_INT) !== false) {
    // Seguro para usar em consulta (mas ainda use prepared statements)
    $quantidade = (int) $quantidade;
} else {
    die("Entrada inválida.");
}
?>

Lembre-se: a validação e sanitização são complementares ao uso de prepared statements (para SQL) e escape de saída (para HTML). Sempre combine essas técnicas para uma segurança robusta.

Boas práticas

  • Sempre valide e sanitize dados no servidor, mesmo que o cliente já tenha feito.
  • Use filter_input para acessar diretamente entradas de formulários e filtrá-las.
  • Para validação mais complexa, combine filter_var com expressões regulares.
  • Prefira filtros específicos (ex.: FILTER_VALIDATE_EMAIL) a filtros genéricos.
  • Não confie apenas na sanitização para segurança; valide o formato antes.
  • Mantenha-se atualizado sobre filtros obsoletos (ex.: FILTER_SANITIZE_STRING foi removido no PHP 8.1).

Referências

Exercícios

  1. Exercício 1: Escreva um script PHP que receba um e-mail via GET e valide se é um e-mail válido usando filter_var. Exiba "Válido" ou "Inválido".

    ✓ Resposta:
    <?php
    $email = $_GET['email'] ?? '';
    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
        echo "Válido";
    } else {
        echo "Inválido";
    }
    ?>
    
  2. Exercício 2: Usando filter_var com opções, valide se um número inteiro recebido via POST está entre 1 e 100. Use min_range e max_range.

    ✓ Resposta:
    <?php
    $numero = $_POST['numero'] ?? '';
    $options = array('options' => array('min_range' => 1, 'max_range' => 100));
    if (filter_var($numero, FILTER_VALIDATE_INT, $options) !== false) {
        echo "Número válido.";
    } else {
        echo "Número inválido.";
    }
    ?>
    
  3. Exercício 3: Sanitize uma string recebida via POST para remover tags HTML e caracteres especiais (use FILTER_SANITIZE_STRING ou htmlspecialchars). Exiba o resultado.

    ✓ Resposta:
    <?php
    $texto = $_POST['texto'] ?? '';
    // Usando htmlspecialchars (recomendado para exibição)
    $textoLimpo = htmlspecialchars($texto, ENT_QUOTES, 'UTF-8');
    echo $textoLimpo;
    // Alternativa com filter_var (obsoleto)
    // $textoLimpo = filter_var($texto, FILTER_SANITIZE_STRING);
    ?>
    
  4. Exercício 4: Crie uma função que receba uma URL e retorne a URL sanitizada (removendo caracteres inválidos) e validada. Se for inválida, retorne false.

    ✓ Resposta:
    <?php
    function validarESanitizarURL($url) {
        // Sanitiza primeiro
        $urlSanitizada = filter_var($url, FILTER_SANITIZE_URL);
        // Valida
        if (filter_var($urlSanitizada, FILTER_VALIDATE_URL)) {
            return $urlSanitizada;
        }
        return false;
    }
    
    $url = "http://exemplo.com/teste<script>";
    $resultado = validarESanitizarURL($url);
    if ($resultado) {
        echo "URL válida e sanitizada: $resultado";
    } else {
        echo "URL inválida.";
    }
    ?>
    
  5. Exercício 5: Explique com suas palavras por que é importante validar e sanitizar dados no servidor, mesmo que o front-end já tenha feito a validação. Dê um exemplo de ataque que poderia ser evitado.

    ✓ Resposta:

    A validação no servidor é essencial porque o cliente pode ser manipulado. Um invasor pode desabilitar JavaScript, usar ferramentas como curl ou Postman para enviar requisições diretamente, ou interceptar e modificar dados em trânsito. A validação no front-end é apenas para melhorar a experiência do usuário, não para segurança. Por exemplo, um campo de e-mail pode ser validado no front-end, mas um invasor pode enviar uma requisição POST com um payload malicioso como "<script>alert('XSS')</script>" no campo de e-mail. Se o servidor não sanitizar ou validar, esse script pode ser executado no navegador de outros usuários (XSS). A validação e sanitização no servidor impedem que dados maliciosos sejam processados ou armazenados.