filter_var($value, FILTER_VALIDATE_EMAIL) retorna o valor quando ele é um endereço de e-mail válido e false quando não é. Troque o filtro para verificar outros formatos: FILTER_VALIDATE_INT, FILTER_VALIDATE_FLOAT, FILTER_VALIDATE_URL, FILTER_VALIDATE_BOOL, FILTER_VALIDATE_IP. Sempre compare o resultado com === false.
Dois resultados surpreendem. ada@example é rejeitado porque o domínio não tem ponto, e ' ada@example.com' é rejeitado por causa do espaço inicial, então aplique trim() na entrada antes de validá-la.
Validar um e-mail vindo de um formulário
A mesma verificação atrás de um formulário. Rode, digite um endereço e clique em Check; o bloco roda de novo com a sua entrada em $_POST.
O FILTER_VALIDATE_EMAIL verifica só o formato. nobody@example.com passa, e passaria também um endereço com erro de digitação no domínio. Caracteres fora do ASCII são rejeitados: adä@example.com só passa com FILTER_FLAG_EMAIL_UNICODE, que os permite antes do @, e um domínio como exämple.com falha mesmo com a flag, a menos que você o converta antes para a forma xn--. O único jeito de saber se um endereço funciona é enviar um link de confirmação para ele.
Validar um inteiro, com min_range e max_range
O FILTER_VALIDATE_INT transforma uma string válida num int e rejeita todo o resto. O array de opções adiciona um intervalo e um padrão:
Espaços em volta e um + inicial são aceitos, um zero à esquerda ('042') não, e o resultado para '42' é o inteiro 42, não a string. Fora do intervalo dá false; com a opção default você recebe o padrão em vez de false, o que é prático para coisas como ?page= (veja _POST). Adicione FILTER_FLAG_ALLOW_HEX ou FILTER_FLAG_ALLOW_OCTAL para aceitar 0x1A ou 0755.
A armadilha do 0 e do false
Um '0' válido retorna o inteiro 0, e 0 é falso. Um if simples o trata como falha:
O mesmo vale para FILTER_VALIDATE_FLOAT ('0.0') e FILTER_VALIDATE_BOOL, em que false é uma resposta válida. É para isso que serve o FILTER_NULL_ON_FAILURE.
Booleanos, floats, URLs e endereços IP
FILTER_VALIDATE_BOOL é o nome do PHP 8; FILTER_VALIDATE_BOOLEAN é o mesmo filtro. Sem FILTER_NULL_ON_FAILURE, 'maybe' retornaria false, impossível de distinguir de 'off'.
Uma URL válida não é um link seguro
O FILTER_VALIDATE_URL verifica se a string tem formato de URL, com qualquer esquema. Isso inclui esquemas que você nunca quer num href:
javascript://comment%0Aalert(1) passa no FILTER_VALIDATE_URL, e um navegador o executa como JavaScript quando o link é clicado, porque o %0A encerra o //comment. Verifique o esquema com parse_url() antes de imprimir a URL de um usuário numa página. Você também pode exigir partes com FILTER_FLAG_PATH_REQUIRED e FILTER_FLAG_QUERY_REQUIRED.
Filtros de sanitização
Filtros de sanitização removem caracteres em vez de dizer sim ou não. Eles servem para normalizar a entrada, não para torná-la segura para impressão:
Olhe a primeira linha: Order #12-345 (x2) vira 12-3452, um número que nunca esteve na entrada, e a terceira linha é um endereço que ninguém digitou. Se você sanitizar, valide o resultado depois. Para tudo o que você imprime no HTML, o htmlspecialchars() na hora da saída é a ferramenta certa (FILTER_SANITIZE_FULL_SPECIAL_CHARS faz o mesmo escape). O FILTER_SANITIZE_STRING está depreciado desde o PHP 8.1; veja htmlspecialchars para o que usar no lugar.
Validar um formulário inteiro com filter_var_array
O filter_var_array() aplica um filtro por chave e retorna um array com todas as chaves que você pediu: o valor filtrado, false quando a validação falhou, ou null quando a chave não existia.
role sumiu: chaves que você não listou são descartadas, o que impede um visitante de adicionar role=admin a um formulário e tê-lo salvo. country é null porque não foi enviado. Num servidor web, filter_input_array(INPUT_POST, $rules) faz o mesmo lendo direto da requisição.
Perguntas frequentes
Como valido um endereço de e-mail no PHP?
Use filter_var($email, FILTER_VALIDATE_EMAIL), que retorna a string do e-mail se for válida e false se não for: if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { /* invalid */ }. Ele verifica só o formato; para saber se o endereço existe, envie um e-mail de confirmação.
Como verifico se uma string é um inteiro no PHP?
filter_var($s, FILTER_VALIDATE_INT) retorna o int para "42", "-7" e " 42 ", e false para "4.2", "42abc" ou "042". Compare com !== false, porque um "0" válido retorna 0, que é falso.
Por que o filter_var retorna false para 0?
Não retorna: filter_var('0', FILTER_VALIDATE_INT) retorna o inteiro 0. O bug está na verificação, if (filter_var(...)), que trata 0 como false. Escreva if (filter_var($v, FILTER_VALIDATE_INT) !== false).
O que substituiu o FILTER_SANITIZE_STRING no PHP 8.1?
Nada diretamente; ele foi depreciado porque o nome prometia uma segurança que ele não dava. Valide a entrada que você espera, guarde-a como está e escape-a ao imprimir com htmlspecialchars(). Se precisar remover tags, use strip_tags().
Qual a diferença entre filter_var e filter_input?
O filter_var() filtra qualquer valor que você passar. filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) lê direto da requisição original, então retorna null quando o parâmetro não existe e ignora qualquer mudança que o seu código tenha feito em $_GET. Os dois recebem os mesmos filtros e opções.