SQL, validações e PHP

Posted on qui 19 novembro 2009 in HowTo

Dicas quando o assunto é SQL e PHP.

<?php
/* 
    sanitizar:
    Esta função realiza :
            - remove espaços no começo e fim do parâmetro
        - remove os caracteres *?--%'&#@"/,;
        - remoção de acentos, torna tudo minúsculo, preserva apenas: letras, números, .:-_

 */

function sanitizar($parametro=false)
{
    $parametro=stripslashes(trim($parametro)); 
    $parametro=str_replace(array("*","?", "--", "%", "'", "&", "#", "@", "\"", "/", ",", ";"),
 "", $parametro);
    $parametro=strtolower(preg_replace('/[^[:alnum:]|_|.|:|-]/', " ",strtr($parametro,
 "áàãâéêíóôõúüçÁÀÃÂÉÊÍÓÔÕÚÜÇ-:","aaaaeeiooouucAAAAEEIOOOUUC-:")));
    return $parametro;
} 

/* 
    anti_sql:
    Esta função realiza :
            - remove caracteres e palavras reservadas de SQL.

            Obs: esta idéia foi retirada de um fórum de discussão.

 */

function anti_sql($varivel)
{
    $varivel = preg_replace("/(from|union select|select|insert|delete|
where|drop table|show tables|#|\*|--|;|=|@|\\\\)/i","",$varivel);
    $varivel = trim($varivel);
    return $varivel;
}


    /*
    Para evitar XSS, ao exibir valores recuperados na tela, utilize a função nativa htmlentities
    exemplo:
    */

    $str="não encontrei o valor";
    echo $str."<br />";
    $str="não encontrei o valor <img src='uma_imagem_nao autorizada.png' />";
    echo $str."<br />";
    echo htmlentities($str)."<br />";


    /* Inserir valor de campos numericos não tratados sempre oferecem risco de SQL Injection
            devido a não utilização da aspa na composição da query 

            ex: SELECT titulo,mensagem FROM noticia WHERE noticia_id=234;

            já em campos text/string a SQL Injection torna-se dificultada pela existência da aspa

            ex: SELECT titulo,mensagem FROM noticia WHERE noticia_titulo='Meu titulo';

            porém pode ser contornada, se o interpretador  não estiver habilitado para escapar aspas

            logo seguem algumas forma de evitar a SQL Injection:
            */

            //campo numérico:

            /* ---- ERRADO: ---- */

            $numero = $_GET['numero'];

            $sql= "SELECT titulo,mensagem FROM noticia WHERE noticia_id=".$numero;

            /* ---- Fazer: ---- */

            $numero = (int) $_GET['numero'];
            //ou
            $numero = intval($_GET['numero']);

            $sql= "SELECT titulo,mensagem FROM noticia WHERE noticia_id=".$numero;

            /*   ou  então pode-se usar o sprintf */


            $sql= sprintf( "SELECT titulo,mensagem FROM noticia WHERE noticia_id = %u",$numero);

            /*   inclusive para casos compostos */

            $numero=22;
            $titulo='Minha noticia';
            $sql= sprintf( "SELECT titulo,mensagem FROM noticia WHERE noticia_id = %u OR titulo = '%s'",$numero, $titulo);

            /* a SQL Injection no meio da string irá exigir a entrada de uma aspa 

            Ex:
             "SELECT titulo,mensagem FROM noticia WHERE titulo = 'Meu Teste'

             SQL Injection:
                 "SELECT titulo,mensagem FROM noticia WHERE titulo = 'Meu Teste' OR 1=1 --'

                 a entrada deverá ser:  Meu Teste' OR 1=1 --

                 para resolver esta entrada, usar as funções pertinente conforme o banco de dados 

            Ex:

            pg_escape_string
            pg_escape_bytea
            dbx_escape_string
            db2_escape_string
            maxdb_escape_string
            mysql_escape_string
            sqlite_escape_string
            mysqli_escape_string
            ingres_escape_string
            maxdb_real_escape_string
            mysql_real_escape_string

            */
            $titulo = @pg_escape_string($_POST['titulo']);

            /* o 'arroba' à frente da função é usado para evitar warning oyu fatal error  */

            $sql="SELECT titulo,mensagem FROM noticia WHERE titulo = '".$titulo."'";

            /* 
                    o uso das funções de preparação de query também é recomendado 
                    pois faz o trabalho de escapar e validar dados antes da execução

                    ex: 
                            pg_prepare
                            mysqli_stmt_prepare
                            ingres_prepare
                            pg_send_prepare
                            ovrimos_prepare
                            maxdb_stmt_prepare
                            db2_prepare
                            ifx_prepare
                            odbc_prepare
                            maxdb_prepare
                            swish_prepare
                            ibase_prepare
                            sdo_das_relational_executepreparedquery



                    exemplo retirado de:

                    http://br2.php.net/manual/pt_BR/function.pg-prepare.php

                    $dbconn = pg_connect("dbname=mary");

                    $result = pg_prepare($dbconn, "my_query", 'SELECT * FROM shops WHERE name = $1');

                    //---> Execute the prepared query.  Note that it is not necessary
                                                to escape the string "Joe's Widgets" in any way:


                    $result = pg_execute($dbconn, "my_query", array("Joe's Widgets"));

                    //---> Execute the same prepared query, this time with a different parameter:

                    $result = pg_execute($dbconn, "my_query", array("Clothes Clothes Clothes"));

            */


            /* 

                    alguns padrões podem ser verificados com o uso de expressões regulares 

                    seguem exemplos para uma máscare de telefone e uma máscara de CPF 
                    - mas sem validação dos dados, apenas do padrão.



                    */


    /*verdadeiro se o parâmetro for algo como (99)9999-9999 */

            function checar_padrao_telefonico($valor=false)
    {
            return preg_match('/^\([0-9]{2}\)[0-9]{4}-[0-9]{4}$/',$valor)?true:false;
    }

    /*verdadeiro se o parâmetro for algo como 999.999.999-99 */

    function checar_padrao_cpf($valor=false)
    {
            return preg_match('/^([0-9]{3}\.){2}[0-9]{3}-[0-9]{2}$/',$valor)?true:false;
    }


?>