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 em sua sintaxe SQL; verifique o manual que corresponde à versão do seu servidor MySQL para a sintaxe correta para usar próximo a '' 15 ', 15' na linha 1
Parece que o PDO está adicionando aspas simples às minhas variáveis na parte LIMIT do código SQL. Eu pesquisei e encontrei este bug que acho que está relacionado: http://bugs.php.net/bug.php?id=44639
É isso que estou olhando? Este bug está 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.
Respostas:
Eu me lembro de ter esse problema antes. Converta o valor em um inteiro antes de transmiti-lo à função de vinculação. Eu acho que isso resolve tudo.
fonte
(int) trim($_GET['skip'])
, tenteintval(trim($_GET['skip']))
.A solução mais simples seria desligar o modo de emulação. Você pode fazer isso simplesmente adicionando a seguinte linha
Além disso, este modo pode ser definido como um parâmetro do construtor ao criar uma conexão PDO . Poderia ser uma solução melhor, já que alguns relatam que o driver não suporta a
setAttribute()
função.Isso não apenas resolverá seu problema com vinculação, mas também permitirá que você envie valores diretamente para o
execute()
, o que tornará seu código muito mais curto. Supondo que o modo de emulação já tenha sido definido, todo o caso levará até meia dúzia de linhas de códigofonte
SQLSTATE[IM001]: Driver does not support this function: This driver doesn't support setting attributes
... Por que nunca é tão simples para mim :) Embora tenha certeza de que isso levará a maioria das pessoas até lá, no meu caso acabei tendo que usar algo semelhante à resposta aceita. Apenas um aviso aos futuros leitores!PDO::ATTR_EMULATE_PREPARES Enables or disables emulation of prepared statements. Some drivers do not support native prepared statements or have limited support for them
. É um novo para mim, mas, novamente, estou apenas começando com o PDO. Normalmente uso mysqli, mas achei melhor tentar ampliar meus horizontes.setAttribute
a instrução ($ stm, $ stmt) não para o objeto pdo.Olhando para o relatório de bug, o seguinte pode funcionar:
mas tem certeza de que seus dados de entrada estão corretos? Porque na mensagem de erro, parece haver apenas uma citação após o número (em oposição ao número inteiro sendo colocado entre aspas). Isso também pode ser um erro com os dados de entrada. Você pode fazer um
print_r($_GET);
para descobrir?fonte
Isso é apenas um resumo.
Existem quatro opções para parametrizar os valores LIMIT / OFFSET:
Desative
PDO::ATTR_EMULATE_PREPARES
conforme mencionado acima .O que evita que os valores passados por
->execute([...])
sempre apareçam como strings.Mude para
->bindValue(..., ..., PDO::PARAM_INT)
população de parâmetro manual .O que, entretanto, é menos conveniente do que um -> execute list [].
Basta abrir uma exceção aqui e apenas interpolar inteiros simples ao preparar a consulta SQL.
O elenco é importante. Mais comumente você vê
->prepare(sprintf("SELECT ... LIMIT %d", $num))
usado para tais fins.Se você não estiver usando MySQL, mas por exemplo SQLite ou Postgres; você também pode lançar parâmetros vinculados diretamente no SQL.
Novamente, MySQL / MariaDB não oferece suporte a expressões na cláusula LIMIT. Ainda não.
fonte
{$_GET->int["limit"]}
para esses casos.para
LIMIT :init, :end
Você precisa ligar dessa forma. se você tiver algo parecido
$req->execute(Array());
, não funcionará, pois será lançadoPDO::PARAM_STR
para todos os vars no array e, para isso,LIMIT
você absolutamente precisa de um inteiro. bindValue ou BindParam como você deseja.fonte
Como ninguém explicou por que isso está acontecendo, estou adicionando uma resposta. A razão está se comportando dessa era é porque você está usando
trim()
. Se você olhar o manual do PHP paratrim
, o tipo de retorno éstring
. Você está então tentando passar isso comoPDO::PARAM_INT
. Algumas maneiras de contornar isso são:filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
para certificar-se de que está passando um número inteiro.intval()
(int)
is_int()
Existem muitas outras maneiras, mas esta é basicamente a causa raiz.
fonte
bindValue offset and limit usando PDO :: PARAM_INT e vai funcionar
fonte
// BEFORE (Erro presente) $ query = ".... LIMIT: p1, 30;"; ... $ stmt-> bindParam (': p1', $ limiteInferior);
// AFTER (erro corrigido) $ query = ".... LIMIT: p1, 30;"; ... $ limiteInferior = (int) $ limiteInferior; $ stmt-> bindParam (': p1', $ limiteInferior, PDO :: PARAM_INT);
fonte
PDO::ATTR_EMULATE_PREPARES
me deu oMinha solução alternativa foi definir uma
$limit
variável como uma string e, em seguida, combiná-la na instrução prepare como no exemplo a seguir:fonte
Há muita coisa acontecendo entre as diferentes versões do PHP e as esquisitices do PDO. Tentei 3 ou 4 métodos aqui, mas não consegui fazer o LIMIT funcionar.
Minha sugestão é usar formatação / concatinação de string COM um filtro intval () :
É muito importante usar intval () para prevenir injeção de SQL, particularmente se você está obtendo seu limite de $ _GET ou algo parecido. Se você fizer isso, esta é a maneira mais fácil de fazer o LIMIT funcionar.
Fala-se muito sobre 'O problema com LIMIT em PDO', mas meu pensamento aqui é que os parâmetros de PDO nunca foram usados para LIMIT, pois eles sempre serão inteiros e um filtro rápido funciona. Ainda assim, é um pouco enganador, pois a filosofia sempre foi não fazer nenhuma filtragem por injeção de SQL, mas sim 'Faça com que o PDO cuide disso'.
fonte