Filtrando e validando dados no PHP com filter_var()

Filtrando e validando dados no PHP com filter_var()

O assunto de hoje é segurança. É bastante comum o seguinte cenário: o programador precisa validar um e-mail e vai para o Google e digita “expressão regular para validar e-mail” ou então “como validar e-mail com PHP”. O que acontece nesse caso? Somos soterrados por uma infinidade de informações e ficamos sem saber exatamente o que irá nos servir.

Contudo, desde a versão 5.2 do PHP está disponível a função filter_var(). Seu objetivo é filtrar e validar informações dentro do PHP. No artigo de hoje, vou realizar um estudo sobre as peculiaridades dessa função e mostrar como é fácil utilizá-la para aumentar a segurança de sua aplicação.

Validate e Sanitize

Os filtros dividem-se em dois tipos: validate e sanitize. Gosto de traduzi-los como validação e limpeza, respectivamente. O objetivo dos filtros de validação (validate) é verificar se determinado valor corresponde a um padrão previamente especificado. Já os filtros de limpeza (sanitize) irão retirar caracteres que não correspondam ao padrão permitido.

Cada filtro possui uma constante correspondente. No capítulo de filtros do manual do PHP é possível encontrar uma lista completa com todos os filtros disponíveis.

A função filter_var() obedece ao seguinte protótipo:

mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )

Sendo assim, o único parâmetro obrigatório é o primeiro, que indica o valor a ser filtrado. Porém, o filtro padrão é não aplicar filtro nenhum. Dessa forma, pra que ocorra de fato uma filtragem, é necessário especificar o segundo parâmetro.

Basicamente, para aplicarmos um filtro em uma variável precisamos apenas indicar filter_var($valor, CONSTANTE_DE_FILTRO).

Os filtros estão organizados em constantes. Validações encontram-se nas constantes FILTER_VALIDATE_* e os filtros de limpeza nas constantes FILTER_SANITIZE_*.

Nos casos de validação, o retorno da função será o valor passado como entrada, em caso de sucesso, e false em caso contrário. Já os filtros de limpeza irão retornar o valor após retirados os caracteres impróprios.

Validando variáveis

Conforme já mencionei, no manual do PHP existe uma lista com todos os filtros disponíveis. Aqui, apresento uma lista com os filtros que julgo serem mais relevantes e o objetivo de cada um.

Filtro Objetivo
FILTER_VALIDATE_EMAIL Validação de e-mails de acordo com o padrão RFC 822.
FILTER_VALIDATE_INT Validação de inteiros. Caso seja passada uma string contendo um inteiro, o valor será convertido e validado.
FILTER_VALIDATE_IP Validação de formato IP. Funciona tanto com IPv4 quanto IPv6.
FILTER_VALIDATE_MAC Validação de MAC address, endereço físico de placas de rede.
FILTER_VALIDATE_URL Validação de URLs de acordo com o padrão RFC 2396.

Separei alguns exemplos de retorno com FILTER_VALIDATE_INT e  FILTER_VALIDATE_EMAIL.

Entrada FILTER_VALIDATE_INT
'7' int(7)
7 int(7)
0 int(0)
true int(1)
false bool(false)
'10 teste' bool(false)
'palavra' bool(false)
-5 int(-5)
3.1 bool(false)
+0 bool(false)
-0 bool(false)
Entrada FILTER_VALIDATE_EMAIL
"fulano@site.com.br" string(18) "fulano@site.com.br"
5 bool(false)
"site.com.br" bool(false)
"1@2.3" bool(false)
"1@2" bool(false)
"fulano beltrano"@site.com bool(false)

Observação: Esse último exemplo, embora alguns servidores aceitem, o PHP considera inválido para fins de validação.

Limpando variáveis

Quando utilizamos filtros do tipo sanitize, todos os caracteres que não pertecem ao padrão escolhido são retirados do valor passado na entrada. Da mesma forma que fiz com os filtros de validação, preparei uma listagem de alguns filtros sanitize.

Filtro Objetivo
FILTER_SANITIZE_EMAIL Remove todos os caracteres, exceto letras, números e os caracteres !#$%&'*+-=?^_`{|}~@.[].
FILTER_SANITIZE_NUMBER_FLOAT Remove todos os caracteres, exceto números, +- e, opcionalmente, .,eE.
FILTER_SANITIZE_NUMBER_INT Remove todos os caracteres, exceto números e sinais de positivo e negativo.
FILTER_SANITIZE_SPECIAL_CHARS Escapa em formato de entidades HTML os caracteres '"<>& e todos os caracteres que possuam valor ASCII menor que 32. Opcionalmente é possível retirar ou converter outros caracteres especiais.
FILTER_SANITIZE_STRING Retira tags. Opcionalmente é possível retirar ou converter outros caracteres especiais.
FILTER_SANITIZE_URL Remove todos os caracteres, exceto letras, números e $-_.+!*'(),{}|\^~[]`<>#%";/?:@&=.

Preparei também alguns exemplos de retorno com FILTER_SANITIZE_URL e  FILTER_SANITIZE_STRING.

Entrada FILTER_SANITIZE_URL
"http://phpit.com.br" string(19) "http://phpit.com.br"
"http://phpit.com.br£" string(19) "http://phpit.com.br"
"phpitº.com.br" string(12) "phpit.com.br"
"br¶" string(2) "br"
"®" string(0) ""
Entrada FILTER_SANITIZE_STRING
"uma string" string(10) "uma string"
"<tag>uma string *" string(12) "uma string *"
"<tag>uma string&lt;tag&gt;" string(21) "uma string&lt;tag&gt;"

Opções extras

É importante ler a documentação do PHP pois existem algumas maneiras de modificar o comportamento desses filtros de validação. Os filtros de validação podem aceitar flags e opções, enquanto os de limpeza podem aceitar apenas flags. Todos esses atributos estão listados junto às definições de cada filtro no manual.

Você pode utilizar um array de opções e/ou flags, indicados pelos índices optionsflags, respectivamente. Em funções que aceitam apenas flags, você pode optar por passá-las diretamente.

O trecho de código abaixo foi adaptado da página sobre a função filter_var() no manual do PHP. Adicionei alguns comentários para tentar elucidar melhor a maneira de funcionamento das opções.

Das opções, a única que está presente em todas é default, que vai indicar o valor a ser retornado caso o dado não seja validado. Fora essa, você encontrará outras opções, como min_range max_range, que indicam qual o valor mínimo e máximo para que o dado seja validado.

As flags são mais específicas do que as opções. Na validação de inteiros, por exemplo, você pode utilizar a flag  FILTER_FLAG_ALLOW_OCTAL, que irá permitir valores do sistema octal.

// você pode utilizar opções dessa maneira
$opcoes = array(
  // as opções ficam neste índice
  'options' => array(
    // valor a ser retornado se o filtro falhar
    'default' => 3,
    // outras opções vão sendo inseridas aqui
    'min_range' => 0
  ),
  // as flags ficam neste índice
  'flags' => FILTER_FLAG_ALLOW_OCTAL,
);
$var = filter_var('0755', FILTER_VALIDATE_INT, $opcoes);

// para filtros que aceitam apenas flags, você pode passá-las diretamente
$var = filter_var('algum valor', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);

// para filtros que aceitam apenas flags, você também pode passar como array
$var = filter_var('algum valor', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE));

Considerações finais

O sistema de validação utilizado pelo filter_var() é bastante completo e, justamente por isso, complexo. Foi bastante trabalhoso escrever essa postagem pois existem muitos detalhes que dizem respeito à filtragem de dados. Vale a pena estudar a maneira como a função trabalha e identificar de que maneira ela pode resolver o seu problema.

Espero que tenha sido proveitoso e que possam aprender formas de aumentar o nível de segurança do código produzido. Caso alguém encontre algum erro ou tenha sugestão para melhorar o post, deixe um comentário!

Um abraço a todos e fiquem com Deus.
Rafael Jaques

  • genecy

    Olá, parabéns pelo blog! Você passa um conhecimento gratuito que vários "professores" de quem eu já comprei vários cursos, não passam.
    Queria sugerir um artigo, não sei se esse é o melhor lugar, mas o artigo é sobre o seguinte:
    Eu estou aprendendo php e já tenho uma lógica de programação, já consigo com muito esforço e tempo, fazer uma conexão com o banco de dados…kkkk. Então, para quem está começando, é muito difícil saber o que estudar e quando estudar. Você poderia fazer um artigo mostrando para um iniciante que já tenha lógica de programação, uma ordem de estudos , até começar a aprender orientação a objetos e o estudo sobre classes e padrões de projeto.
    Desde já, parabéns pelo blog, sucesso, e muito obrigado! Abraço

  • Diogo Alexsander Cavilha

    Olá.

    Ótimo post!
    Não faz muito tempo, criei um package justamente abstraindo essas validações e filtros. Espero que seja últil…
    https://github.com/diogocavilha/array-validation

  • CELSO RAMOS

    Quero, endossar as palavras de genecy e parabenizá-lo pelo BLOG, MUITO BOM !

  • Rodrigo Soares

    O manual do PHP é super importante, mas achar a informação bem detalhada assim é muito proveitoso e soma muito mais fácil nossa busca por esclarecimento.
    Parabéns e obrigado pelo post.