Как применить метод bindValue в предложении LIMIT?

Вот снимок моего кода:

$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);

я получил

У вас есть ошибка в вашем синтаксисе SQL;
проверьте руководство, которое соответствует
ваша версия сервера MySQL для
правильный синтаксис для использования около » 15 ‘, 15’ в
строка 1

Кажется, что PDO добавляет одинарные кавычки к моим переменным в части LIMIT кода SQL. Я искал это, я нашел эту ошибку, которая, я думаю, связана:
http://bugs.php.net/bug.php?id=44639

Это то, на что я смотрю? Эта ошибка была открыта с апреля 2008 года!
Что мы должны делать в это время?

Мне нужно построить несколько страниц, и перед отправкой оператора sql нужно убедиться, что данные чистые и безопасны для инъекций.

106

Решение

Я помню эту проблему раньше. Приведите значение к целому числу, прежде чем передавать его в функцию связывания. Я думаю, что это решает это.

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

Другие решения

Простейшим решением было бы переключить режим эмуляции выкл. Вы можете сделать это либо как вариант подключения, либо просто добавив следующую строку

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

Это не только решит вашу проблему с bind param, но и позволит вам отправлять значения в execute (), что сделает ваш код значительно стреляющим

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

Глядя на отчет об ошибке, может работать следующее:

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

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

но вы уверены, что ваши входные данные верны? Потому что в сообщении об ошибке, кажется, только один кавычка после числа (в отличие от целого числа, заключенного в кавычки). Это также может быть ошибка с вашими входящими данными. Вы можете сделать print_r($_GET); выяснить?

15

Это так же, как резюме.
Существует четыре варианта параметризации значений LIMIT / OFFSET:

  1. запрещать PDO::ATTR_EMULATE_PREPARES как уже упоминалось выше.

    Что мешает значениям, переданным за ->execute([...]) чтобы всегда показываться как строки.

  2. Переключиться на ручной ->bindValue(..., ..., PDO::PARAM_INT) параметр населения.

    Что, однако, менее удобно, чем -> выполнить список [].

  3. Просто сделайте исключение и просто интерполируйте простые целые числа при подготовке запроса SQL.

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

    Кастинг важен. Чаще вы видите ->prepare(sprintf("SELECT ... LIMIT %d", $num)) используется для таких целей.

  4. Если вы не используете MySQL, но, например, SQLite или Postgres; Вы также можете привести связанные параметры непосредственно в SQL.

     SELECT * FROM tbl LIMIT (1 * :limit)
    

    Опять же, MySQL / MariaDB не поддерживают выражения в предложении LIMIT. Еще нет.

6

за LIMIT :init, :end

Вы должны связать таким образом. если бы у вас было что-то вроде $req->execute(Array()); это не сработает PDO::PARAM_STR для всех переменных в массиве и для LIMIT вам абсолютно необходимо целое число.
bindValue или BindParam, как вы хотите.

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

Поскольку никто не объяснил, почему это происходит, я добавляю ответ. Это происходит потому, что вы используете trim(), Если вы посмотрите на руководство по PHP для trimтип возвращаемого значения string, Затем вы пытаетесь передать это как PDO::PARAM_INT, Несколько способов обойти это:

  1. использование filter_var($integer, FILTER_VALIDATE_NUMBER_INT) чтобы убедиться, что вы передаете целое число.
  2. Как говорили другие, используя intval()
  3. Кастинг с (int)
  4. Проверка, является ли оно целым числом с is_int()

Есть еще много способов, но это в основном основная причина.

2

смещение и ограничение bindValue с использованием PDO :: PARAM_INT, и это будет работать

1

// ДО (текущая ошибка)
$ query = «…. LIMIT: p1, 30;»;

$ stmt-> bindParam (‘: p1’, $ limiteInferior);

// ПОСЛЕ (ошибка исправлена)
$ query = «…. LIMIT: p1, 30;»;

$ limiteInferior = (int) $ limiteInferior;
$ stmt-> bindParam (‘: p1’, $ limiteInferior, PDO :: PARAM_INT);

0