Concatenate in the PDO query

0

I've heard that concatenating a query using PDO can cause slowness and even make the system vulnerable, is that true?

I want to concatenate in query and am afraid to take certain risks.

public static function read($table, $where = null) {
    $sql = "SELECT * FROM '" . self::$_prefix . "{$table}' {$where}";
}
    
asked by anonymous 19.02.2016 / 20:04

1 answer

2

I use a class to read the generic database and never had a performance problem. The biggest problem is that you need to know exactly what is being passed in the parameters to make the query, otherwise, sql injection can be performed on your database, which can lead to problems.

I created a class in a course I did on the internet and since then I use it to do generic readings in the database. It is very complete, it treats the information passed by parameter, in order to try to minimize the risk of sql injection. If you want to use it, the operation is very simple:

index.php

    <?php

    include('Config.inc.php');

    // para consultas simples 
    $read = new Read;
    $read->ExeRead('tabela', 'WHERE campo = :valor', 'valor=1');

    if($read->getResult()){

        var_dump($read->getResult());
    } else {

        var_dump($read->getError());

    }

    // para consultas complexas
    $read2 = new Read;
    $read2->FullRead('SELECT tabela.id, tabela2.campo FROM tabela LEFT JOIN tabela2 ON tabela.id = tabela2.id WHERE tabela.id = :id', 'id=1');

    if($read2->getResult()){

        var_dump($read2->getResult());
    } else {

        var_dump($read2->getError());

    }

?>

Config.inc.php

<?php

// CONFIGRAÇÕES DO BANCO ####################
define('HOST', 'localhost');
define('USER', 'USUARIO');
define('PASS', 'SENHA');
define('DBSA', 'DATABASE');


// AUTO LOAD DE CLASSES ####################
function __autoload($Class) {

    $cDir = array('Conn');
    $iDir = null;

    foreach ($cDir as $dirName):
        if (!$iDir && file_exists(__DIR__ . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR . $Class . '.class.php') && !is_dir(__DIR__ . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR . $Class . '.class.php')):
            include_once (__DIR__ . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR . $Class . '.class.php');
            $iDir = true;
        endif;
    endforeach;

    if (!$iDir):
        trigger_error("Não foi possível incluir {$Class}.class.php", E_USER_ERROR);
        die;
    endif;

}

// TRATAMENTO DE ERROS #####################
//CSS constantes :: Mensagens de Erro
define('AW_ACCEPT', 'accept');
define('AW_INFOR', 'infor');
define('AW_ALERT', 'alert');
define('AW_ERROR', 'error');

//AWErro :: Exibe erros lançados :: Front
function AWErro($ErrMsg, $ErrNo, $ErrDie = null) {

    $CssClass = ($ErrNo == E_USER_NOTICE ? WS_INFOR : ($ErrNo == E_USER_WARNING ? WS_ALERT : ($ErrNo == E_USER_ERROR ? WS_ERROR : $ErrNo)));
    echo "<p class=\"trigger {$CssClass}\">{$ErrMsg}<span class=\"ajax_close\"></span></p>";

    if ($ErrDie):
        die;
    endif;
}

//PHPErro :: personaliza o gatilho do PHP
function PHPErro($ErrNo, $ErrMsg, $ErrFile, $ErrLine) {
    $CssClass = ($ErrNo == E_USER_NOTICE ? WS_INFOR : ($ErrNo == E_USER_WARNING ? WS_ALERT : ($ErrNo == E_USER_ERROR ? WS_ERROR : $ErrNo)));
    echo "<p class=\"trigger {$CssClass}\">";
    echo "<b>Erro na Linha: #{$ErrLine} ::</b> {$ErrMsg}<br>";
    echo "<small>{$ErrFile}</small>";
    echo "<span class=\"ajax_close\"></span></p>";

    if ($ErrNo == E_USER_ERROR):
        die;
    endif;
}

set_error_handler('PHPErro');
?>

/Conn/Conn.class.php

<?php

    abstract class Conn {

        private static $Host = HOST;
        private static $User = USER;
        private static $Pass = PASS;
        private static $Dbsa = DBSA;

        /** @var PDO */
        private static $Connect = null;

        /**
         * Conecta com o banco de dados com o pattern singleton.
         * Retorna um objeto PDO!
         */
        private static function Conectar() {
            try {
                if (self::$Connect == null):
                    $dsn = 'mysql:host=' . self::$Host . ';dbname=' . self::$Dbsa;
                    $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8');
                    self::$Connect = new PDO($dsn, self::$User, self::$Pass, $options);
                endif;
            } catch (PDOException $e) {
                PHPErro($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
                die;
            }

            self::$Connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return self::$Connect;
        }

        /** Retorna um objeto PDO Singleton Pattern. */
        protected static function getConn() {
            return self::Conectar();
        }

    }

    ?>

/Conn/Read.class.php

<?php

class Read extends Conn {

    private $Select;
    private $Places;
    private $Result;

    /** @var PDOStatement */
    private $Read;

    /** @var PDO */
    private $Conn;

    /**
     * <b>Exe Read:</b> Executa uma leitura simplificada com Prepared Statments. Basta informar o nome da tabela,
     * os termos da seleção e uma analize em cadeia (ParseString) para executar.
     * @param STRING $Tabela = Nome da tabela
     * @param STRING $Termos = WHERE | ORDER | LIMIT :limit | OFFSET :offset
     * @param STRING $ParseString = link={$link}&link2={$link2}
     */
    public function ExeRead($Tabela, $Termos = null, $ParseString = null) {
        if (!empty($ParseString)):
            parse_str($ParseString, $this->Places);
        endif;

        $this->Select = "SELECT * FROM {$Tabela} {$Termos}";
        $this->Execute();
    }

    /**
     * <b>Obter resultado:</b> Retorna um array com todos os resultados obtidos. Envelope primário númérico. Para obter
     * um resultado chame o índice getResult()[0]!
     * @return ARRAY $this = Array ResultSet
     */
    public function getResult() {
        return $this->Result;
    }

    /**
     * <b>Contar Registros: </b> Retorna o número de registros encontrados pelo select!
     * @return INT $Var = Quantidade de registros encontrados
     */
    public function getRowCount() {
        return $this->Read->rowCount();
    }

    public function FullRead($Query, $ParseString = null) {
        $this->Select = (string) $Query;
        if (!empty($ParseString)):
            parse_str($ParseString, $this->Places);
        endif;
        $this->Execute();
    }

    /**
     * <b>Full Read:</b> Executa leitura de dados via query que deve ser montada manualmente para possibilitar
     * seleção de multiplas tabelas em uma única query!
     * @param STRING $Query = Query Select Syntax
     * @param STRING $ParseString = link={$link}&link2={$link2}
     */
    public function setPlaces($ParseString) {
        parse_str($ParseString, $this->Places);
        $this->Execute();
    }

    /**
     * ****************************************
     * *********** PRIVATE METHODS ************
     * ****************************************
     */
    //Obtém o PDO e Prepara a query
    private function Connect() {
        $this->Conn = parent::getConn();
        $this->Read = $this->Conn->prepare($this->Select);
        $this->Read->setFetchMode(PDO::FETCH_ASSOC);
    }

    //Cria a sintaxe da query para Prepared Statements
    private function getSyntax() {
        if ($this->Places):
            foreach ($this->Places as $Vinculo => $Valor):
                if ($Vinculo == 'limit' || $Vinculo == 'offset'):
                    $Valor = (int) $Valor;
                endif;
                $this->Read->bindValue(":{$Vinculo}", $Valor, ( is_int($Valor) ? PDO::PARAM_INT : PDO::PARAM_STR));
            endforeach;
        endif;
    }

    //Obtém a Conexão e a Syntax, executa a query!
    private function Execute() {
        $this->Connect();
        try {
            $this->getSyntax();
            $this->Read->execute();
            $this->Result = $this->Read->fetchAll();
        } catch (PDOException $e) {
            $this->Result = null;
        }
    }

}
?>
    
19.02.2016 / 20:48