+5

Protegendo dados que vem do formulário

criado por Hudolf Hess em 10/04/2010 11:13pm
Bom, este é meu primeiro artigo no site. O objetivo do artigo é explicar um pouco sobre uma classe que fiz, chamada de "Input", de fácil utilização, porém de grande importância.

Durante um bom tempo, usava as funções htmlentities / mysql_escape_string / addslashes em todas as variáveis que iria salvar no banco de dados, o que gerava algumas repetições de códigos em todas as classes.

A solução que encontrei foi criar uma classe que tratasse todos os campos vindos de um formulário e após isso salvar no banco.

Classe Input:
<?php
/*
 * CLASSE DE PROTEÇÃO EM DADOS VINDOS DE FORMULÁRIO
 * Hudolf Jorge Hess < hudolf@gmail.com >
 * http://www.hudolfhess.com/
 *
 * Proteger entradas INPUTS vindas de formulários tanto GET quanto POST.
 */

class Input {

    private $tmp = array();
    private $html = array();

    function __construct($type, $html = array()){
        $this->html = $html;
        if ($type == "post"){
            $this->tmp = $_POST;
            $this->protegendo();
            $_POST = $this->tmp;
        }
        else if ($type == "get"){
            $this->tmp = $_GET;
            $this->protegendo();
            $_GET = $this->tmp;
        }
        else if ($type == "session"){
            $this->tmp = $_SESSION;
            $this->protegendo();
            $_SESSION = $this->tmp;
        }

        
    }

    private function protegendo(){
        foreach ($this->tmp as $index=>$valor){
			//SE FOR UMA ARRAY IRÁ ACESSAR TODOS OS OUTROS VALORES DELA
            if (is_array($valor)){
                $this->tmp[$index] = $this->subProtegendo($valor);
            }
            else {
                //ESTA VERIFICAÇÃO SERVE PARA DADOS VINDOS ATRAVÉS DO jQuery Form Plugin
                if (mb_detect_encoding($valor) == "UTF-8"){
                    $xvalor = utf8_decode($valor);
                    if (mb_detect_encoding($xvalor) == "UTF-8"){
                        $valor = $xvalor;
                    }
                    
                }
                if (in_array($index, $this->html)){
                    if (!get_magic_quotes_gpc()){
                    $this->tmp["$index"] = addslashes($valor);
                    }
                    else {
                        $this->tmp["$index"] = $valor;
                    }
                }
                else {
                    if (!get_magic_quotes_gpc()){
                    $this->tmp["$index"] = htmlspecialchars(addslashes($valor));
                    }
                    else {
                        $this->tmp["$index"] = htmlspecialchars($valor);
                    }
                }
            }
        }
    }

    private function subProtegendo($valor){
        $xvalor = array();
        foreach ($valor as $index=>$nvalor){
            if (is_array($nvalor)){
                $xvalor[$index] = $this->subProtegendo($nvalor);
            }
            else {
                //ESTA VERIFICAÇÃO SERVE PARA DADOS VINDOS ATRAVÉS DO jQuery Form Plugin
                if (mb_detect_encoding($nvalor) == "UTF-8"){
                    $xvalor = utf8_decode($nvalor);
                    if (mb_detect_encoding($xvalor) == "UTF-8"){
                        $nvalor = $xvalor;
                    }

                }
                if (in_array($index, $this->html)){
                    if (!get_magic_quotes_gpc()){
                    $xvalor["$index"] = addslashes($nvalor);
                    }
                    else {
                        $xvalor["$index"] = $nvalor;
                    }
                }
                else {
                    if (!get_magic_quotes_gpc()){
                        $xvalor["$index"] = htmlspecialchars(addslashes($nvalor));
                    }
                    else {
                        $xvalor["$index"] = htmlspecialchars($nvalor);
                    }
                }
            }
        }

        return $xvalor;
    }

}
?>

Exemplo de utilização (Protegendo dados $_POST):
require_once "Input.class.php";

//Trata os dados vindo de um formulário usando o método POST
$inputObj = new Input("post");

print_r($_POST);

A classe da suporte a "post", "get" e "session".

Permitindo códigos HTML em determinado campo
require_once "Input.class.php";

//Campos a serem permitidos HTML
$html = array("Noticia", "Descricao");

//Trata os dados vindo de um formulário usando o método POST
//Porém os campos contidos no array $html exibirão o HTML normalmente
$inputObj = new Input("post", $html);

print_r($_POST);

Observação importante:
Ao pegar as informações do banco de dados, deve-se utilizar a função stripslashes($variavel) para remover as \ (contra barras)

Caso queira contribuir com críticas, sugestões ou até mesmo postanto uma atualização para esta classe, sinta-se a vontade.

Comentários:

Mostrando 1 - 10 de 13 comentários
Josue Samuel disse:
Inspirado no artigo do Hudolf Hess e no comentário do Gilberto Albino (de 19/06/2010 2:28pm), fiz algumas adaptações desta classe pro meu uso e compartilho com vocês.

<?php
/**
* Classe criada inspirada no script "Protegendo dados que vem do formulário", criado por Hudolf Hess em 10/04/2010 11:13pm e publicado em http://phpbrasil.com/artigo/E-0MqgwFW6Cw/protegendo-dados-que-vem-do-formulario e no post de Gilberto Albino feito em 19/06/2010 2:28pm.
* @author Josué Cintra josuecintra.desenvolvedor at gmail com
* @version 1.00 24-11-2010 15:50 Criação da classe
*
*/


/*
* Esta classe pode ser ampliada os filtros suportados, colocando outros cases de acordo do o $filterType recebido.
* - lista de filtros http://br.php.net/manual/pt_BR/intro.filter.php
* - exemplo de uso http://br.php.net/manual/pt_BR/function.filter-var-array.php
*/

/* acredito que este é um nome mais condizente pelo que a classe faz */
class FilterData
{
/**
* @param mixed $data array ou string a ser filtrada (dessa forma a classe não fica engessada às superglobais)
* @param string $filterType default: sanitize
*/
public function __construct( $data, $filterType='sanitize' )
{
if(empty($data)) return null;
switch($filterType)
{
case 'sanitize': { return self::SanitizeData($data); break; }
}
}

private static function SanitizeData($data)
{
if(is_array($data)) return filter_var_array($data, FILTER_SANITIZE_STRING);
elseif(is_string($data)) return filter_var($data, FILTER_SANITIZE_STRING);
return null; /* retorna nulo */
}
}
?>
24/11/2010 4:37pm (~6 anos atrás)

Show de bola o artigo..
30/09/2010 11:02am (~6 anos atrás)

Carlos Eduardo Gomes Monteiro, cada caso o seu caso, neh?

Se quiser manter a impressão visual das entidades HTML é só fazer o seguinte:

Trocar:

FILTER_SANITIZE_STRING

por

FILTER_SANITIZE_SPECIAL_CHARS

Vai fazer as duas coisas, proteger e manter a impressão visual, no caso de:

"Oi, eStoU cOm <xAuDaDEs>"

O que vai ser obtido é:

&#34;Oi, eStoU cOm &#60;xAuDaDEs&#62;&#34;




22/07/2010 6:44pm (~6 anos atrás)

jeanderson disse:
:}
11/07/2010 12:57am (~6 anos atrás)

Mas hein Hudolf
O seu código está correto!
O que estava falando que remove as tags é esta linha de código abaixo...
filter_var_array($var, FILTER_SANITIZE_STRING);

Esta sim remove as tags...
Mas o seu código não...

Foi mal, não fui muito claro...
07/07/2010 7:00pm (~6 anos atrás)

Hudolf Hess disse:
Carlos Eduardo, ele não removerá os códigos HTML, ele irá converte-los apenas.

< para &lt; e assim por diante, no momento da exibição, não será reconhecido como um código HTML e sim como um texto normal.
30/06/2010 11:13am (~6 anos atrás)

Bem...
O problema no código apresentado, é que ele vai remover as tags HTML.
Então, se o usuário que gosta de inventar moda, escrever um texto assim...

"Oi, eStoU cOm <xAuDaDEs>"

...

E quanto ao lance do reconhecimento de caracteres...
Bem, meus códigos nem preciso.
E acho que é isso que tem que ser feito.
Como disse, tem que ser tudo planejado e documentado.
E os programadores que vierem a trabalhar no sistema futuramente, tem que ver a documentação. É para isso que ela serve...

Na minha opnião, é até desnecessário o reconhecimento de caracteres num código daqueles.
Pra mim, isso é necessário quando se faz comunicação com entidades externas.
Aí sim, pois é algo que está fora da documentação, e que até certo ponto, não podemos prever ao certo o que é recebido da entidade externa.
30/06/2010 10:47am (~6 anos atrás)

Hehe.
Então, Carlos Eduardo Gomes Monteiro,
Acho que você distorceu um pouco o que falei:

Veja o que eu disse:
>>E vale citar que o reconhecimento de caractere por multibytes não >>está habilitado por padrão no PHP, e não vai servir pra nada neste >>caso se estiver desabilitado!

E veja o que você respondeu:
>>Você falou sobre o reconhecimento de caracteres como se fosse algo >>que não devessemos usar.

Bom, de fato. Não disse que não era necessário usar! Se a empresa de hospedagem não habilitar esta extensão, vai acontecer o mesmo que aconteceu na empresa que trabalho e não tinha o php com esta extensão habilitada e o antigo programador jogou o codigo lá no servidor, ai as secretárias acessavam a página, geravam um cadastro e os caracteres iam convertidos errado, e depois os dados não eram achados numa busca qualquer.
Logo, a forma mais óbvia é gerar um controle direto no script em Ajax em questão com outra classe de manipulação de codificação de caracteres e só confiar neste recurso se tiver a certeza de está habilitado.

Outra coisa que você falou:
>> E quanto ao código que você mostrou, bem, acho que fugiu bastante da >> proposta do Hudolf...

Não sei onde que fugi bastante da proposta, pois, o que apresentei, faz basicamnete a mesma coisa e mais rápido.

Pra quem não sabe FILTER_SANITIZE_STRING converte para entidades HTML os caracteres que propiciariam uma INJEÇÃO SQL e logo, o uso de addslashes() é desnecessário, pois não há nada a se escapar!
E como os dados vão ser procurados por uma busca, e precisarão ser protegidos por esta mesma classe, então serão achados igualmente!
Onde fugi? a classe dele é para proteção, não para controle de bytecode!
Isto pode ser feito no script em ajax e não sobrecarregar a aplicação à toa!

23/06/2010 1:01pm (~6 anos atrás)

Hudolf Hess disse:
Gilberto e Carlos, agradeço aos comentários.
Realmente, costumo utilizar ISO como charset padrão, como utilizo servidores padrões, não tive problemas com esta classe.
Mas irei seguir os conselhos passados aqui e implementar a parte dos slashes, que realmente é interessante.
Assim que eu tiver tempo, irei alterar e colocar aqui novamente.
Agradeço aos comentários.
23/06/2010 12:06am (~6 anos atrás)

Então Gilberto, você entrou em um assunto importante aí
Gostaria de mensionar dois pontos...

Você falou sobre o reconhecimento de caracteres como se fosse algo que não devessemos usar.
Mas, só pelo fato de não estar habilitado, não creio que isto seja inútil.
A maioria dos programadores utilizam um mesmo servidor para vários sistema (Exceto excessões).
Então acho válido adicionar às bibliotecas pessoais dos programadores códigos como este, uma vez que saibamos que o servidor está habilidade e que tenhamos consciência que se trocar de servidor, poderá haver problemas.

E quanto ao código que você mostrou, bem, acho que fugiu bastante da proposta do Hudolf...
Bem, cada um tem seu estilo não é...
E quando digo estilo. Me refiro desde algo que é muito esquecido na hora do planejamento que é o encode até a escrita do código.
Então tem programadores que preferem ISO, outro UTF8 e etc...
Pelo que eu ví no código, o Hudolf prefere ISO assim como eu...

Então por isso que derrepente ao ser ver, o código não é muito interessante, mas, ao meu ver, é uma boa sugestão.

E escrevendo este comentário me lembrei de algo interessante para este código...

Uma sugestão aí para o Hudolf...
Acho que seria interessante adicionar um parametro para os slashes...
Pois nem sempre precisamos adiciona-los, como por exemplo, um formulário de contato.
Basta receber os dados do formulário e enviar por e-mail.
Então acho que seria desvantajoso, utilizar esta classe para agilizar para o programador, mas, depois, ter que usar um stripslashes() só para corrigir algo que é simples de arrumar...
22/06/2010 11:21pm (~6 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)