Pergunta

Aqui está um instantâneo do meu código:

$fetchPictures = $PDO->prepare("SELECT * 
    FROM pictures 
    WHERE album = :albumId 
    ORDER BY id ASC 
    LIMIT :skip, :max");

$fetchPictures->bindValue(':albumId', $_GET['albumid'], PDO::PARAM_INT);

if(isset($_GET['skip'])) {
    $fetchPictures->bindValue(':skip', trim($_GET['skip']), PDO::PARAM_INT);    
} else {
    $fetchPictures->bindValue(':skip', 0, PDO::PARAM_INT);  
}

$fetchPictures->bindValue(':max', $max, PDO::PARAM_INT);
$fetchPictures->execute() or die(print_r($fetchPictures->errorInfo()));
$pictures = $fetchPictures->fetchAll(PDO::FETCH_ASSOC);

eu recebo

Você tem um erro na sintaxe SQL;Verifique o manual que corresponde à sua versão do MySQL Server para obter a sintaxe certa para usar próximo '' 15 ', 15' na linha 1

Parece que o PDO está adicionando aspas simples às minhas variáveis ​​na parte LIMIT do código SQL.Pesquisei e encontrei esse bug que acho que está relacionado:http://bugs.php.net/bug.php?id=44639

É isso que estou olhando?Este bug foi aberto desde abril de 2008!O que devemos fazer enquanto isso?

Preciso construir alguma paginação e ter certeza de que os dados estão limpos e seguros para injeção de sql, antes de enviar a instrução sql.

Foi útil?

Solução

Lembro-me de ter tido esse problema antes.Transforme o valor em um número inteiro antes de passá-lo para a função de ligação.Acho que isso resolve.

$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);

Outras dicas

A solução mais simples seria desligar o modo de emulação.Você pode fazer isso como uma opção de conexão ou simplesmente adicionando a seguinte linha

$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );

Isso não apenas resolverá seu problema com parâmetros de ligação, mas também permitirá que você envie valores em execute(), o que tornará seu código muito mais curto

$skip = $_GET['skip'] ?: 0;
$sql  = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
$stmt  = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->fetchAll(PDO::FETCH_ASSOC);

Olhando o relatório do bug, o seguinte pode funcionar:

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);  

mas você tem certeza de que seus dados recebidos estão corretos?Porque na mensagem de erro, parece haver apenas um aspas após o número (em vez de o número inteiro estar entre aspas).Isso também pode ser um erro nos dados recebidos.Você pode fazer um print_r($_GET); descobrir?

Isso é apenas um resumo.
Existem quatro opções para parametrizar valores LIMIT/OFFSET:

  1. Desativar PDO::ATTR_EMULATE_PREPARES como mencionado acima.

    O que impede que valores passados ​​por ->execute([...]) para sempre aparecer como strings.

  2. Mudar para manual ->bindValue(..., ..., PDO::PARAM_INT) população de parâmetros.

    O que, no entanto, é menos conveniente do que uma ->executar lista[].

  3. Simplesmente abra uma exceção aqui e interpole números inteiros simples ao preparar a consulta SQL.

     $limit = intval($limit);
     $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
    

    O elenco é importante.Mais comumente você vê ->prepare(sprintf("SELECT ... LIMIT %d", $num)) usados ​​para tais fins.

  4. Se você não estiver usando MySQL, mas por exemplo SQLite ou Postgres;você também pode converter parâmetros vinculados diretamente no SQL.

     SELECT * FROM tbl LIMIT (1 * :limit)
    

    Novamente, MySQL/MariaDB não suporta expressões na cláusula LIMIT.Ainda não.

para LIMIT :init, :end

Você precisa se vincular dessa maneira.se você tivesse algo parecido $req->execute(Array()); não funcionará, pois será lançado PDO::PARAM_STR para todos os vars na matriz e para o LIMIT você absolutamente precisa de um número inteiro.bindValue ou BindParam conforme desejar.

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

Como ninguém explicou por que isso está acontecendo, estou adicionando uma resposta.A razão pela qual está se comportando assim é porque você está usando trim().Se você olhar o manual do PHP para trim, o tipo de retorno é string.Você está então tentando passar isso como PDO::PARAM_INT.Algumas maneiras de contornar isso são:

  1. Usar filter_var($integer, FILTER_VALIDATE_NUMBER_INT) para ter certeza de que você está passando um número inteiro.
  2. Como outros disseram, usando intval()
  3. Fundição com (int)
  4. Verificando se é um número inteiro com is_int()

Existem muitas outras maneiras, mas esta é basicamente a causa raiz.

deslocamento e limite de bindValue usando PDO::PARAM_INT e funcionará

// antes (erro presente) $ query = "....LIMITE:p1, 30;";...$stmt->bindParam(':p1', $limiteInferior);

// depois (Erro corrigido) $ query = "....LIMITE:p1, 30;";...$limiteInferior = (int)$limiteInferior;$stmt->bindParam(':p1', $limiteInferior, PDO::PARAM_INT);

PDO::ATTR_EMULATE_PREPARES me deu o

O driver não suporta esta função:Este driver não suporta o erro dos atributos de configuração.

Minha solução alternativa foi definir um $limit variável como uma string e combine-a na instrução prepare como no exemplo a seguir:

$limit = ' LIMIT ' . $from . ', ' . $max_results;
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE company_id = :cid ORDER BY name ASC' . $limit . ';' );
try {
    $stmt->execute( array( ':cid' => $company_id ) );
    ...
}
catch ( Exception $e ) {
    ...
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top