Ir para conteúdo
Omar~

[Resolvido] sql-inject quando não dar para impedir!

Recommended Posts

Alguém conhece alguma documentação bacana que eu possa está lendo sobre esse caso:

 

Bem nunca tive problema enquanto a isso, sempre me utilizei de funções e regex para filtrar caracteres em impedir injeção dos mesmos em uma tabela, impedindo um post e forçando a pessoa a não utilizar esses caracteres que podem "bugar" o banco.

 

Na aplicação que estou trabalhando agora, sou obrigado a permitir a postagem de qualquer caractere, e por teste executei o código em uma textarea somente com algumas letras e áspas escapadas. O resultado foi o a tabela ficou inutilizada, entre outros teste com alguns códigos usados em inject.

 

E o problema é esse não posso impedir a postagem disso, mas tenho que manter a segurança do banco, como devo proceder então?

Até agora o que pensei melhor é fazer uma lista de caracteres e modificar-los quando forem usados e salvar no banco, e quando forem lidos retornarem ao que eram antes, mas como fazer uma vez que qualquer caractere pode ser usado a area do post?

Compartilhar este post


Link para o post
Compartilhar em outros sites
10 horas atrás, BrunoMs disse:

Mesmo utilizando PDO não resolveria esse problema de segurança contra inject?

 

Nem mesmo... Pois só me utilizo da PDO.

 

Na verdade tem uma solução que não passa de gabiarra.

O campo da tabela que vai salvar os dados que podem ser uados para injetar o código pode ser um 'text' e o post problemático pode ser codificado usando base64_encode então é só mandar o código codificado para a classe salvar o texto.

Na hora de ler é só recuperar utilizando base64_decode para exibir o original depois da query

$a = 'texto ou um código qualquer';
$code = base64_encode($a);

// Vai exibir um texto todo codificado,
// então é salvar esse texto no banco
echo $code;
echo "<hr>";

// Isso aqui já mostra o texto decodificado,
// que pode ser usado na hora da leitura da tabela
echo base64_decode($code);

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Omar~ rapaiiz, me encontrei na mesma situação que você, precisei aceitar qualquer tipo de caractere no meu banco, utilizei a sua ideia do base64_encode, porém o scanner do meu provedor de hospedagem sempre embaça com o base64_encode por ser muito utilizado pra scripts maliciosos, o scanner remove todos os arquivos que tem base64_encode/decode e consequentemente quebra meu site. Acho que vou ter que fazer a listagem dos caracteres tudo e fazer algum tratamento.

Você teve problema ao usar base64 aí na sua hospedagem?

Compartilhar este post


Link para o post
Compartilhar em outros sites
Em 19/12/2017 at 18:39, Omar~ disse:

Na aplicação que estou trabalhando agora, sou obrigado a permitir a postagem de qualquer caractere, e por teste executei o código em uma textarea somente com algumas letras e áspas escapadas. O resultado foi o a tabela ficou inutilizada, entre outros teste com alguns códigos usados em inject.

A solução para isso definitivamente não é ofuscar (me refiro ao base64 citado) o que vem do banco.

Até pelo fato de que uma hora você precisa desofuscar, e nesse momento você se torna vítima de outras duas vulnerabilidades:

- SQL Injection de segunda ordem

- XSS

 

@BrunoBit, para o banco, sempre utilize (ou ao menos em todas as consultas que utilizam variáveis do tipo string) prepared statements com os tipos corretamente definidos.

Isso é 70% do caminho e algo extremamente simples de ser feito.

 

Para XSS e outros abusos, há dois recursos eficientes:

htmlentities()

Definições apropriadas dos cabeçalhos de respostas

  • Gostei 1
  • Obrigado! 2

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Matheus Tavares rapaizz, não conhecia esse sql injection de segunda ordem, li aqui e vou ficar ligado.

Os prepared statements que você diz são esse no código abaixo né?

$stmt->bindParam("exemplo" , $exemplo, PDO::PARAM_STR);
$stmt->bindValue("exemplo2", $exemplo2, PDO::PARAM_INT);

sei que tem o PARAM_STR e PARAM_INT pra definir os tipos, porém não sei se existe algum parâmetro específico pra código, pq eu preciso enviar pro banco de dados javascripts e o usuário vai poder enviar qualquer tipo de script. Existe algum parâmetro específico pra tratamento de códigos? Se não tiver, talvez algo que eu possa fazer é tirar as tags de códigos e colocar um código específico pra identificar eles pra depois reconstruir os códigos na hora de ler eles.

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

1 hora atrás, Matheus Tavares disse:

A solução para isso definitivamente não é ofuscar (me refiro ao base64 citado) o que vem do banco.

Até pelo fato de que uma hora você precisa desofuscar, e nesse momento você se torna vítima de outras duas vulnerabilidades:

Bom depois irei fazer alguns testes com htmlentries, porque na falta de solução me segurei no base_encode e decode.

 

No caso onde a pessoa pode inserir um código qualquer e o sistema não pode aplicar filtros sobre a postagem, pelos testes que fiz no caso de barras escapadas e áspas, aniquilam a tabela.

Exemplo tenho já uns 10 registros na tabela, ao inserir o próximo registro que virá bugado, esses 10 últimos registros se tornam ilegíveis, ao fazer o backup em sql da tabela constatei o erro de semântica.

Tipo assim:

(37, 'teste-ID-6040so7a5cLo6A4gzpe', 'Teste de formatação', 'if (1 == 1) {' $a = null'; $b=\" sss ' }', '20', '2018-01-22', '2018-01-23', '20'),

É simples olhar esse INSERT INTO e ver o "quão bugado" ele está.

 

No meu caso e não sei se é a do @BrunoBit. Ter um local onde a pessoa pode simplesmente entrar digitar toda um código de uma página como se fosse um editor, essa página pode conter até mesmo scripts em javascript, então ele salva e a nova página está criada com, válido com tudo que ele transcreveu na postagem.

Exemplo se eu postar aqui:

Citar

<button onclick="myFnc()">Clicar</button>

<script type="text/javascript">

function myFnc() {

    alert('Botão clicado');

}

</script>

 

O ckEditor faz um mapa de caractere e coloca isso como imprimível e não executa. E a questão é essa permitir esse tipo de coisa. No que abre uma brecha enorme na segurança.

  • Obrigado! 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Omar~ meu caso é exatamente o seu, só que ao invés de um editor eu tenho um campo textarea pra pessoa colocar o javascript já pronto, o base64 encode/decode funcionou filé, inclusive o meu provedor fez com que o scanner não implicasse mais com o base64 no meu host, porém o @Matheus Tavares mostrou o sql injection de segunda ordem, e no meu caso o site ficaria passivo à ataque de XSS + sql injection de segunda ordem.

Compartilhar este post


Link para o post
Compartilhar em outros sites
8 minutos atrás, BrunoBit disse:

@Omar~ meu caso é exatamente o seu, só que ao invés de um editor eu tenho um campo textarea pra pessoa colocar o javascript já pronto, o base64 encode/decode funcionou filé, inclusive o meu provedor fez com que o scanner não implicasse mais com o base64 no meu host, porém o @Matheus Tavares mostrou o sql injection de segunda ordem, e no meu caso o site ficaria passivo à ataque de XSS + sql injection de segunda ordem.

 

É o base 64 nessa questão não é solução e sim um "quebra-galho ou (severino)" se assim quiser chamar.

Hora que vamos supor um código JS com 50 linhas usando base64_encode vai gerar uma string, sei lá mais de 1000 caracteres, então imagine um código de 100, 300, 500 linhas ou mais? O pode deixar a query lenta tanto para insert quanto para select conforme a demanda mesmo que seja baixa.

Compartilhar este post


Link para o post
Compartilhar em outros sites
15 minutos atrás, Omar~ disse:

O ckEditor faz um mapa de caractere e coloca isso como imprimível e não executa

Pois é isso que faz o htmlentities().

 

O fato é: impedir JS/html é fácil. Use prepared statements (ainda não entendi pq você não está usando, @Omar~, seria algum impedimento do seu cliente ou do host?) e htmlentities().

Colocando os headers corretos então, você coloca a cereja no bolo. Eles ajudam muito contra XSS e outras brechas relacionadas ao cliente (clickjacking, cross frame scripting, etc).

 

Difícil é precisar propositalmente permitir que o usuário poste esses códigos e permitir a execução deles, como para criar um jsfiddle da vida. Ou seja, propositalmente você conceder esse acesso ao seu usuário.

 

Não entendi se o caso de vocês é o primeiro ou o segundo...

 

Se for o segundo, a situação é outra. Eu tive um cliente que queria oferecer a possibilidade de os clientes dele (usuários do sistema) fossem capazes de inserir códigos JS no site (o sistema gera sites aos clientes). Eu perguntei qual a razão disso e ele disse que era principalmente por causa do Google Analytics.

Daria para permitir JS? Sim, mas o buraco é bem mais em baixo... a solução nesse caso foi bem mais simples (para mim, para o cliente e para os usuários): bastava inserir em um campo o ID do google analytics, que o site iria adicionar automaticamente o script no padrão imposto pelo GA. Exemplo:

<script nonce="<!-- implementação do nonce-hash aqui (prevenção do navegador) -->">
    (function ( i, s, o, g, r, a, m ) {
        i[ 'GoogleAnalyticsObject' ] = r;
        i[ r ] = i[ r ] || function () {
            (i[ r ].q = i[ r ].q || []).push( arguments );
        }, i[ r ].l = 1 * new Date();
        a = s.createElement( o ),
            m = s.getElementsByTagName( o )[ 0 ];
        a.async = 1;
        a.src = g;
        m.parentNode.insertBefore( a, m );
    })( window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga' );
    
    ga( 'create', '<?= $id_google; ?>', 'auto' );
    ga( 'send', 'pageview' );
</script>

 

Compartilhar este post


Link para o post
Compartilhar em outros sites
1 hora atrás, BrunoBit disse:

Os prepared statements que você diz são esse no código abaixo né?

Exatamente, @BrunoBit. Esqueci de responder isso no meu post anterior.

Quando você binda, o seu driver de banco de dados (PDO, Mysqli...) toma uma certa responsabilidade pela segurança do transporte dessa informação, encapsulando-a entre o seu código até o banco de dados (impedindo interferências na query em si).

  • +1 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
8 minutos atrás, Matheus Tavares disse:

Difícil é precisar propositalmente permitir que o usuário poste esses códigos e permitir a execução deles, como para criar um jsfiddle da vida. Ou seja, propositalmente você conceder esse acesso ao seu usuário.

 

Bingo!! É isso.

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Matheus Tavares no meu caso o usuário vai inserir o script pra realizar a execução dentro do site, mas por aqui ta mais fácil de resolver pq é possível eu definir um padrão nesses scripts, assim como você fez com o ID do analytics, vou implementar algo parecido por aqui.

 

1 minuto atrás, Matheus Tavares disse:

Exatamente, @BrunoBit. Esqueci de responder isso no meu post anterior.

Quando você binda, o seu driver de banco de dados (PDO, Mysqli...) toma uma certa responsabilidade pela segurança do transporte dessa informação, encapsulando-a entre o seu código até o banco de dados (impedindo interferências na query em si).

Sim sim, to usando eles em tudo, passei a usar pq a galera aqui sempre recomendava, passei a usar e curti pra caramba.

Compartilhar este post


Link para o post
Compartilhar em outros sites
19 minutos atrás, Omar~ disse:

Bingo!! É isso.

Certo... nesse caso é muito relativo com o seu modelo de negócios.

 

1 - Analise primeiramente se isso é realmente necessário. Faça apenas em último caso e preferencialmente se houver algum nível de confiança no usuário que vai mexer (não existe confiança em um visitante qualquer, anônimo e de qualquer lugar do mundo).

 

2 - Cuide dos cabeçalhos. Estude-os e implemente-os.

 

3 - Conheça javascript e seus poderes. Hoje em dia você consegue até minerar bitcoin com JS (imagina um G1 da vida fazendo todos os visitantes minerarem por eles... isso já é uma realidade em muitos sites).

 

O JSFiddle, por exemplo, não é algo tão perigoso, pois JS roda no cliente e só quem acessar um fiddle específico iria executar o código malicioso, bastando fechar a janela para sair, mas no meu exemplo que citei anteriormente, seria mais complicado. Você precisaria varrer o código e bloquear algumas coisas manualmente, provavelmente. Não cheguei a implementar isso de fato (e nem sei se me sentiria confortável com isso rodando no meu código), então minha noção é um pouco limitada em relação às dificuldades, precisamente falando.

 

Esse vídeo é simplesmente uma obra-prima. Se vocês entendem bem inglês ou encontrarem legendado, recomendo MUITO, pois mesmo sendo um pouco antigo, é válido nos dias atuais: https://www.youtube.com/watch?v=YDW7kobM6Ik

 

No final ele dá umas pinceladas a respeito do acesso totalmente invasivo que o Google tem sobre nossas redes físicas (wireless) e como é relativamente fácil você mudar a senha de roteadores usando puramente JS remoto.

Editado por Matheus Tavares
Atualização do link do vídeo. O anterior tinha qualidade muito baixa.
  • Gostei 1
  • Obrigado! 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Certo, seguindo o caso que o Matheus mencionou, então o que vocês acham disso?

O cara vai lá e posta isso na textarea:

Citar

<script type="text/javascript">
function myFnc() {
  alert('olá');
}
</script>        

<button onclick="myFnc()">Executar função</button>
<div style="width: 200px; height: 200px; background: red">

 

Aplico isso a validação: (É só um exemplo genérico)

<?php
$post = htmlspecialchars($_POST['???']); // Post da textarea
$html = htmlentities($post);

 

Então se der um var_dump na variável $html teremos isso:

Citar

&lt;script type=&quot;text/javascript&quot;&gt; function myFnc() { alert('olá'); } &lt;/script&gt; &lt;button onclick=&quot;myFnc()&quot;&gt;Executar função&lt;/button&gt; &lt;div style=&quot;width: 200px; height: 200px; background: red&quot;&gt;

 

Ótimo já evita que a pessoa poste algum código que possa bagunçar o DB?

 

Então salvamos isso no banco.

 

Se dermos echo no resultado da consulta o que vai ser exibido é o texto e não será executado o código em sí.

Mas se fizer isso no arquivo que vai receber os dados já lidos:

 

echo(html_entity_decode($resultadoDaConsultaPDO));

Pronto, o código passa a ser executado somente quando eu permito que seja executado.

 

E o melhor pelo que testei, com a PDO por causa do PARAM_STR, não sei porque, mas faz com que uma função ou código PHP ou SQL não seja executado. O que era uma um dos meus temores. Porque se o fulano que vai postar por ventura descobre os dados de acesso ao banco e nome de tabelas e tal poderia postar um código para fazer modificação no servidor. Ou até mesmo se sabe o nome de diretórios e arquivo poder imprimi-los em tela.

 

  • Obrigado! 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Omar~ testei aqui a sua lógica e funcionou filé, com o htmlspecialchars ele só imprime o texto e só executa com html_entity_decode. Posso ta enganado, mas pelo o que li no link que o matheus enviou sobre o sql injection de segunda ordem, com esse código aí que você fez já elimina a possibilidade desse tipo de injection. Talvez o único problema é que, se for um script malicioso que o usuário inseriu, o html_entity_decode vai executar mesmo assim quando ele decodar, aí nesse caso talvez cairia em algum tipo de ataque XSS.

Compartilhar este post


Link para o post
Compartilhar em outros sites
1 hora atrás, Omar~ disse:

E o melhor pelo que testei, com a PDO por causa do PARAM_STR, não sei porque, mas faz com que uma função ou código PHP ou SQL não seja executado

Exatamente... você não precisa se preocupar com SQL injection se usar prepared statements.

Elas te dão a proteção que você queria inicialmente (relacionada ao banco de dados).

 

A questão é que toda essa volta com htmlentities() para depois usar o html_entity_decode() é a mesma coisa que nada (contra XSS)... A ideia do htmlentities() é justamente quando você quer escapar os html/js, impedindo injeção de HTML/CSS e consequentemente ataques XSS em geral.

 

Sobre o JS, eu já citei os perigos. Isso tudo é algo que você não deveria fazer ao menos que confie no seu usuário... mas se é isso mesmo que você quer, então você pode tirar o htmlentities/html_entity_decode tranquilamente.

 

EDIT:  só complementando: esse assunto de sql injection é bem polêmico. Já vi alguns casos de abuso por parte de uso de caracteres fora do encoding, mas que eu saiba, utilizando UTF-8 e seguindo princípios básicos de segurança, principalmente o uso de prepared statements com os devidos parâmetros propriamente definidos, são suficientes.

Por outro lado, ainda existem alguns caras que dizem que não, que as prepared statements não são suficientes por si só, mas eu nunca vi uma "proof of concept" a respeito dessas invasões, com exceção do abuso de encoding, que é facilmente resolvido com sanitização através do htmlentities e definição apropriada do encoding.

Na dúvida (e um pouco de paranoia), ignore o que eu disse no início desse post e faça como você já está fazendo... Como eu sempre utilizo prepared statements com htmlentities, não parei para pesquisar isso ainda mais a fundo.

É um assunto interessante, mas cheio de falácias e controvérsias.

Editado por Matheus Tavares
Complementar resposta
  • +1 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ah, @Omar~, muito importante também, para você que usa PDO:

 

Desabilite as multi-queries na sua conexão PDO. Dessa forma, além da segurança das prepared statements, você impede a execução de mais de uma instrução SQL em uma consulta.

 

Veja um exemplo:

<?php
$Pdo = new \PDO(
    "mysql:host=localhost;dbname={$base};charset=utf8",
    $usuario,
    $senha,
    [
        \PDO::MYSQL_ATTR_MULTI_STATEMENTS => false, //desabilita multi-queries
        \PDO::ATTR_ERRMODE => \PDO::ERRMODE_SILENT, //desabilita erros. Faça em produção somente
        \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" //garante utf8
    ]
);

 

Desabilitar os erros em produção também é extremamente importante, pois além de expor detalhes indesejados, é sabido que o PDO pode expor a senha do banco quando dispara um erro (!).

  • Obrigado! 1
  • +1 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Certo, certo então vou sinalizar o tópico como resolvido, serve de consultas futuras.

Mesmo porque nada que a pessoa faça garante 100% de segurança. O que ele pode fazer e enfiar segurança por cima de segurança, que vai deixar a aplicação lenta e ainda não é totalmente confiável.

 

Deixarei aqui minhas classes que trata de conexão, injeção, e leitura.

Connect

Spoiler

<?php
class Connect {
    private static $host = HOST;
    private static $user = USER;
    private static $pass = PASS;
    private static $data = DATA;
    private static $isConnect = null;

    /** ************************************************
     * @Method: Para construir a conexão com o banco 
     * de dados
     * *************************************************/
    private static function makeConnect() {
        try {
            if (self::$isConnect == null) {
                $dsn = 'mysql:host=' . self::$host . '; dbname=' . self::$data;
                $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8'];
                self::$isConnect = new PDO($dsn, self::$user, self::$pass, $options);
            }
        } catch (PDOException $error) {
            die("<br>Não foi possível conectar com o banco de dados!<br Descrição: {$error->getMessage()}<br>");
        }
        self::$isConnect->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return self::$isConnect;
    }

    /** ************************************************
     * @Method: Chama o construtor da conexão
     * *************************************************/
    protected function callConnect() {
        return self::makeConnect();
    }
}

 

 

Insert

Spoiler

<?php
class Insert extends Connect {
    /** @Attr: Armazena a tabela **/
    private $insertTable;
    /** @Attr: Armazena a ARRAY de valores **/
    private $insertFilds;
    /** @Attr: Armazena a syntax da query **/
    private $insertSyntax;
    /** @Attr: Armazena a conexão **/
    private $insertConn;
    /** @Attr: Armazena se houve sucesso na incerssão **/
    private $insertData;

    /** ************************************************
     * @Method: Recebe os dados para inserir.
     * @Param: ($table) Tabela para inserir.
     * @Param: ($field) Valores a inserir.
     * *************************************************/
    public function insertQuery($table, array $fields) {
        $this->insertTable = (string) $table;
        $this->insertFilds = $fields;
        $this->insertConstruct();
        $this->insertExecute();
    }

    /** ************************************************
     * @Method: Informa se o registro foi concluído.
     * @Return: (bool) TRUE or FALSE
     * *************************************************/
    public function insertResult() {
        return $this->insertData;
    }

    /** ************************************************
     * @Method: Controi a Syntax da query através da 
     * array recebida, para compor a uso de 
     * Prepare Statements.
     * *************************************************/
    private function insertConstruct() {
        $Column = implode(', ', array_keys($this->insertFilds));
        $values = ':' . implode(', :', array_keys($this->insertFilds));
        $this->insertSyntax = "INSERT INTO {$this->insertTable} ({$Column}) VALUES ({$values})";
    }

    /** ************************************************
     * @Method: Inicia a conexão e faz o
     * Prepare Statements.
     * *************************************************/
    private function insertConnect() {
        $this->insertConn = parent::callConnect();
        $this->insertSyntax = $this->insertConn->prepare($this->insertSyntax);
    }

    /** ************************************************
     * @Method: Executa os métodos e obtem os
     * resultados.
     * @Return: (EXCEPTION) TRUE or FALSE
     * *************************************************/
    private function insertExecute() {
        $this->insertConnect();
        try {
            $this->insertSyntax->execute($this->insertFilds);
            $this->insertData = $this->insertConn->lastInsertId();
            
        } catch (PDOException $error) {
            $this->insertData = null;
            die("<br><b>Erro ao inserir dados:</b> {$error->getMessage()} {$error->getCode()}");
        }
    }
}

 

Exemplo de uso

Spoiler

<?php
$create = new Insert();
$create->insertQuery("users", [
    'userlogin' => 'login qualquer', 
    'userpass' => 'senha qualquer'
]);

if ($create->insertResult()) {
    echo "Dados inseridos";
}

 

 

 

Select

Spoiler

<?php
class Select extends Connect {
    /** @Attr: Armazena a tabela **/
    private $selectTable;
    /** @Attr: Armazena os valores **/
    private $selectFields;
    /** @Attr: Armazena a syntax da query **/
    private $selectSyntax;
    /** @Attr: Armazena a conexão **/
    private $selectConn;
    /** @Attr: Armazena se houve sucesso na incerssão **/
    private $selectData;

    /** ************************************************
     * @Method: Recebe os dados para ler.
     * @Param ($table) : Tabela para ler.
     * @Param ($fields) : Campos para ler.
     * *************************************************/
    public function selectQuery($table, $fields = null, $statements = null) {
        if (!empty($statements)) {
            parse_str($statements, $this->selectFields);
        }
        $this->selectTable = 'SELECT * FROM ' . $table . (isset($fields) ? ' WHERE ' . $fields : null);
        $this->selectExecute();
    }

    /** ************************************************
     * @Method: Para leitura de múltipas tabelas
     * simultâneas com uso de "INNER_JOIN / LEFT_JOIN".
     * @Param ($Query) : Tabela para ler.
     * @Param ($statements) : Valores para ler.
     * @Note: (LIMIT/OFFSET) São opcionais.
     * *************************************************/
    public function selectQueryFull($Query, $statements = null) {
        $this->selectTable = (string) $Query;
        if (!empty($statements)) {
            parse_str($statements, $this->selectFields);
        }
        $this->selectExecute();
    }

    /** ************************************************
     * @Method: Informa quantos resultados que foram
     * encontrados.
     * @Return: (INT) Quantidade de registros
     * *************************************************/
    public function selectCount() {
        return $this->selectSyntax->rowCount();
    }

    /** ************************************************
     * @Method: Informa os resultados que foram
     * encontrados.
     * @Return: (ARRAY) Resultados em String
     * *************************************************/
    public function selectResult() {
        return $this->selectData;
    }

    /** ************************************************
     * @Method: Constroi a Syntax para query.
     * Altomaticamente detecta o uso de vinculos
     * atribuitivos de resultado (LIMIT/OFFSET) e
     * trata os mesmos como INTEGER.
     * *************************************************/
    private function selectConstruct() {
        if ($this->selectFields) {
            foreach ($this->selectFields as $type => $value) {
                if ($type == 'limit' || $type == 'offset') {
                    $value = (int) $value;
                }
                $this->selectSyntax->bindValue(":{$type}", $value, (is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR));
            }
        }
    }

    /** ************************************************
     * @Method: Inicia a conexão e faz o
     * Prepare Statements.
     * *************************************************/
    private function selectConnect() {
        $this->selectConn = parent::callConnect();
        $this->selectSyntax = $this->selectConn->prepare($this->selectTable);
        $this->selectSyntax->setFetchMode(PDO::FETCH_OBJ);
    }

    /** ************************************************
     * @Method: Executa os métodos e obtem os
     * resultados.
     * @Return: (EXCEPTION) TRUE or FALSE
     * *************************************************/
    private function selectExecute() {
        $this->selectConnect();
        try {
            $this->selectConstruct();
            $this->selectSyntax->execute();
            $this->selectData = $this->selectSyntax->fetchAll();
        } catch (PDOException $error) {
            $this->selectData = null;
            die("<br><b>Erro ao ler dados:</b> {$error->getMessage()} {$error->getCode()}");
        }
    }
}

 

Exemplo de uso:

Spoiler

<?php
$varlogin = "login qualquer";
$varpass = "senha qualquer";

echo "<b>Leitura de um único dado com statements</b><br>";
$read = new Select();
$read->selectQuery("users", "userlogin = :datalogin AND userpass = :datapass", "datalogin={$varlogin} & datapass={$varpass}");

if ($read->selectCount()) {
    foreach ($read->selectResult() as $value) {
        echo "Nome: {$value->userlogin}<br>";
        echo "Senha: {$value->userpass}<br>";
    }
} else {
    echo "Sem resultados";
}

echo "<hr><b>Leitura de todos os dados em uma tabela</b><br>";
$read2 = clone $read;
$read2->selectQuery("users");
if ($read2->selectCount()) {
    foreach ($read2->selectResult() as $value2) {
        echo "Nome: {$value2->userlogin}<br>";
        echo "Senha: {$value2->userpass}<br>";
    }
} else {
    echo "Sem resultados";
}

 

 

 

É muito importante que personalize os gatilhos de exceções porque quando há erro a PDO vai informar corretamente qual o erro que foi disparado. E isso não é legal para mostrar para um usuário.

Como sugestão que é como uso uma classe Exeption personalizada que ofusca os erros, ao qual usará toda vez que necessitar dos métodos dessas classes, assim sendo você pode mostrar o erro que quiser para o usuário e ainda por exemplo salvar logs de erros reais da aplicação, usando os apresentados originalmente, para futuras consultas de manutenção.

 

  • +1 2

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.