6
respostas

Erro - Como tratar ao inserir um produto no Form, com aspas simples, dupla / e \

Boa tarde pessoal, o tratamento do Login deu certo SQL Injection, mas quando insiro um novo produto por ex.: Bola d'agua ou Monitor LG 17" (aspas duplas) ou Monitor LG 17'' (aspas simples) acontece o erro na minha inserção. Sei que é devido o ' " como eu trato esse problema?

Erro ao inserir o Produto. Erro inserção nos campos: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'agua', '45', 'bola', '1', '1')' at line 1 

Tentei tratar dessa forma... igual foi realizado no login mas não deu certo.

$produto = mysqli_real_escape_string($conexao,$produto);
$descricao = mysqli_real_escape_string($conexao,$descricao);
$preco = mysqli_real_escape_string($conexao,$preco);

todas as pesquisas que procurei informa sobre login (usuário e senha), não sobre a inserção de produtos com aspas simples(') e outras. Tentei usar o str_replace, mas não deu certo...

function insereProduto($conexao, $produto, $preco, $descricao, $usado, $categoria){

    $query = str_replace("insert into produtos (nome, preco, descricao, usado, categoria_id) values ('{$produto}', '{$preco}', '{$descricao}', '{$usado}', '{$categoria}')");    
    return mysqli_query($conexao,$query);
}

Olhei no site: http://br2.php.net/manual/pt_BR/language.types.string.php e não entendi muito bem... Olhei as funções ( htmlspecialchars_decode e addslashes).

$produto = htmlspecialchars_decode("nome");
$descricao = htmlspecialchars_decode("descricao"); 
$query = "insert into produtos (nome, preco, descricao, usado, categoria_id) values ('{$produto}', '{$preco}', '{$descricao}', '{$usado}', '{$categoria}')";    
    return mysqli_query($conexao,$query);
                                        OU
$produto =  addslashes("nome");
$descricao = addslashes("descricao");
$query = "insert into produtos (nome, preco, descricao, usado, categoria_id) values ('{$produto}', '{$preco}', '{$descricao}', '{$usado}', '{$categoria}')";    
    return mysqli_query($conexao,$query);

Ambas funcionou a inserção no Banco de Dados , mas não aparece na lista o nome e a descrição do produto. Fica em branco... mas insere no BD

Pode me explicar melhor ou Há uma outra forma de tratar (', ", /. ) e aparece os nomes normalmente?

6 respostas

Oi Flávio, tudo bom?

Realmente as funções htmlspecialchars e mysqli_real_scape_string são mais limitadas (e antigas).

O ideal para lidar com as suas queries é dar uma olhada em prepared statements. aqui você encontra o exemplo da documentação.

A ideia é que ao invés de gerenciar os parâmetros da query manualmente injetando eles na string a gente use a função prepare que toma os devidos cuidados com SQL injection.

Mais pra frente, você pode dar uma olhada nos cursos de PDO também que abordam uma forma mais moderna de trabalhar esse lado do banco com PHP =)

Abraço

OK, meu proximo curso será o de PDO. Segui sua ideia de gerenciar os parâmettros com a método PDO, antes de fazer o curso. Segui um tutorial: https://www.codigofonte.com.br/artigos/evite-sql-injection-usando-prepared-statements-no-php.

$query = "SELECT * FROM tabela WHERE username = ?";

// o método PDO::prepare() retorna um objeto da classe PDOStatement ou FALSE se ocorreu algum erro (neste caso use $pdo->errorInfo() para descobrir o que deu errado)
$stmt = $pdo->prepare($query);

// agora que temos o statement preparado, precisamos "bindar" a variável
$username = "fulano";

// utilizamos o método PDOStatement::bindValue() que aceita como parâmetros a posição do ? que a variável irá substituir (a primeira é 1) e a própria variável
$stmt->bindValue(1, $username);

// executamos o statement
$ok = $stmt->execute();

// agora podemos pegar os resultados (partimos do pressuposto que não houve erro)
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

Então adaptei ao meu código:

function insereProduto($conexao, $produto, $preco, $descricao, $usado, $categoria){

    $query = "insert into produtos (nome, preco, descricao, usado, categoria_id) values ('{$produto}', '{$preco}', '{$descricao}', '{$usado}', '{$categoria}')";

    // o método PDO::prepare() retorna um objeto da classe PDOStatement ou FALSE se ocorreu algum erro (neste caso use $pdo->errorInfo() para descobrir o que deu errado)
    $stmt = $pdo->prepare($query);

    // agora que temos o statement preparado, precisamos "bindar" a variável
    // $produto = "nome";
    // $preco = preco;
    // $descricao = "descricao";
    // $usado = usado;
    // $categoria = categoria_id;  // já foi inserido (declarado) na query

    // utilizamos o método PDOStatement::bindValue() que aceita como parâmetros a posição do ? que a variável irá substituir (a primeira é 1) e a própria variável
    $stmt->bindValue(1, $produto, $preco, $descricao, $usado, $categoria);

    // executamos o statement
    $ok = $stmt->execute();

    // agora podemos pegar os resultados (partimos do pressuposto que não houve erro)
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);    
    return mysqli_query($conexao,$results);
}

Mas não obtive sucesso... a ideia seria essa?

Oi Flávio, a ideia é que você faça um bindValuepor variavel. Algo como:

$query = "insert into produtos (nome, preco, descricao, usado, categoria_id) values (?, ?, ?, ?, ?)";

    $stmt = $pdo->prepare($query);

    $stmt->bindValue(1, $nome);
    $stmt->bindValue(2, $preco);
    $stmt->bindValue(3, $descricao);
    $stmt->bindValue(4, $usado);
    $stmt->bindValue(5, $categoria);
...

André boa tarde;

Fiz o que vc me pediu.

<?php
require_once("conecta.php"); 
   // ---------------Insere Produto-----------------
function insereProduto($conexao, $produto, $preco, $descricao, $usado, $categoria){

    $query = "insert into produtos (nome, preco, descricao, usado, categoria_id) values ('{$produto}', '{$preco}', '{$descricao}', '{$usado}', '{$categoria}')";

    $stmt = $pdo->prepare($query);

    $stmt->bindValue(1, $produto);
    $stmt->bindValue(2, $preco);
    $stmt->bindValue(3, $descricao);
    $stmt->bindValue(4, $usado);
    $stmt->bindValue(5, $categoria);

    return mysqli_query($conexao,$stmt);
}

Porém me deu o seguinte erro:

Fatal error: Uncaught Error: Call to a member function prepare() on null in C:\xampp\htdocs\loja\BD-produto.php:8 Stack trace: #0 C:\xampp\htdocs\loja\adiciona-produto.php(21): insereProduto(Object(mysqli), 'Bola D'agua', '10', 'teste', true, '1') #1 {main} thrown in C:\xampp\htdocs\loja\BD-produto.php on line 8

ao olhar sobre o erro , tentei dessa forma tb, mas sem sucesso.

function insereProduto($conexao, $produto, $preco, $descricao, $usado, $categoria){

    global $conexao;

    $query = $conexao->prepare ("insert into produtos (nome, preco, descricao, usado, categoria_id) values ('{$produto}', '{$preco}', '{$descricao}', '{$usado}', '{$categoria}')");

    //$stmt = $pdo->prepare($query);

    $query->bindValue(1, $produto);
    $query->bindValue(2, $preco);
    $query->bindValue(3, $descricao);
    $query->bindValue(4, $usado);
    $query->bindValue(5, $categoria);

    $query->execute();

    return $query->fetch();

Onde $ conexão é a minha conexão ao BD. Na chamada conecta.php e me deu o seguinte erro.

Fatal error: Uncaught Error: Call to a member function bindValue() on boolean in C:\xampp\htdocs\loja\BD-produto.php:12 Stack trace: #0 C:\xampp\htdocs\loja\adiciona-produto.php(21): insereProduto(Object(mysqli), 'Bola D'agua', '15', 'teste', true, '1') #1 {main} thrown in C:\xampp\htdocs\loja\BD-produto.php on line 12

Parece que o problema é a chamada do método $PDO e prepare... junto com o conecta.php e tratamento de exceção...

try {
        $dbh = new PDO(
            DB_TYPE . ':host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_CHARSET,
            DB_USER,
            DB_PASS,
            [
                PDO::ATTR_PERSISTENT            => true,
                PDO::ATTR_ERRMODE               => PDO::ERRMODE_EXCEPTION,
                PDO::MYSQL_ATTR_INIT_COMMAND    => 'SET NAMES ' . DB_CHARSET . ' COLLATE ' . DB_COLLATE

            ]
        );
    } catch ( PDOException $e ) {
        echo 'ERROR!';
        print_r( $e );
    }

como é isso, parece que fiz uma salada de fruta....

Oi Flávio, tudo bom?

Foi quase! O erro:

Fatal error: Uncaught Error: Call to a member function bindValue() on boolean in C:\xampp\htdocs\loja\BD-produto.php:12 Stack trace: #0 C:\xampp\htdocs\loja\adiciona-produto.php(21): insereProduto(Object(mysqli), 'Bola D'agua', '15', 'teste', true, '1') #1 {main} thrown in C:\xampp\htdocs\loja\BD-produto.php on line 12

Indica que o método prepare retornou um valor booleano. Isso só acontece quando a query da erro. No nosso caso, o erro está nos parametros da query, que estão com a string sendo injetada diretamente. Tenta trocar pelas interrogações:

    $query = $conexao->prepare ("insert into produtos (nome, preco, descricao, usado, categoria_id) values (?, ?, ?, ?, ?)");

André fiz essa alteração e não funcionou.... Segue o código:

$query = $conexao->prepare ("insert into produtos (nome, preco, descricao, usado, categoria_id) values (?, ?, ?, ?, ?)");

    $query->bindValue(1, $produto);
    $query->bindValue(2, $preco);
    $query->bindValue(3, $descricao);
    $query->bindValue(4, $usado);
    $query->bindValue(5, $categoria);

    $query->execute();
    return $query->fetch(); 

Após inserir o código deu o seguinte erro:

Fatal error: Uncaught Error: Call to undefined method mysqli_stmt::bindValue() in C:\xampp\htdocs\loja\BD-produto.php:18 Stack trace: #0 C:\xampp\htdocs\loja\adiciona-produto.php(21): insereProduto(Object(mysqli), 'Celular', '123', 'teste', false, '2') #1 {main} thrown in C:\xampp\htdocs\loja\BD-produto.php on line 18

Esse erro na line 18 é

 $query->bindValue(1, $produto);

Depois disso fiz mais pequisa a respeito e fiz algumas mudança no código usando o método procedural

$query = mysqli_prepare($conexao, "insert into produtos (nome, preco, descricao, usado, categoria_id) values (?, ?, ?, ?, ?)");

    mysqli_stmt_bind_param($conexao,'sssd', $produto, $preco, $descricao, $usado, $categoria);

    /* execute prepared statement */
    mysqli_stmt_execute($query);

    return $query->fetch();

mas apareceu o seguinte erro:

Warning: mysqli_stmt_bind_param() expects parameter 1 to be mysqli_stmt, object given in C:\xampp\htdocs\loja\BD-produto.php on line 11
Erro ao inserir o Produto. Erro inserção nos campos:

Também coloquei o return mysqli_stmt_execute($query); e não mudou nada. Estou fazendo as alterações mas estou travado nessa funcionalidade e entender como ela funciona.