Как применить метод 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 убедитесь, что данные чистые, sql-инъекционные, безопасны.

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

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

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

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

Он не только решит вашу проблему с параметром bind, но также позволит вам отправлять значения в 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); - $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); 

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

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

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

для LIMIT :init, :end

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

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

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

  1. Отключите PDO::ATTR_EMULATE_PREPARES как указано выше .

    Это предотвращает передачу значений, переданных per ->execute([...]) всегда отображаемыми в виде строк.

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

    Это, однако, менее удобно, чем -> execute list [].

  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. Еще нет.

bindValue offset и limit с использованием PDO :: PARAM_INT, и он будет работать

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

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

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

// BEFORE (настоящая ошибка) $ query = "…. LIMIT: p1, 30;"; … $ stmt-> bindParam (': p1', $ limiteInferior);

// ПОСЛЕ (исправлена ​​ошибка) $ query = "…. LIMIT: p1, 30;"; … $ limiteInferior = (int) $ limiteInferior; $ stmt-> bindParam (': p1', $ limiteInferior, PDO :: PARAM_INT);

Я сделал следующее на моем, где $ info – это мой массив, содержащий мои связанные параметры:

  preg_match( '/LIMIT :(?P<limit>[0-9a-zA-Z]*)/', $sql, $matches ); if (count($matches)) { //print_r($matches); $sql = str_replace( $matches[0], 'LIMIT ' . intval( $info[':' . $matches['limit']] ), $sql ); } // LIMIT #, :limit# preg_match( '/LIMIT (?P<limit1>[0-9]*),\s?:(?P<limit2>[0-9a-zA-Z]*)/', $sql, $matches ); if (count($matches)) { //print_r($matches); $sql = str_replace( $matches[0], 'LIMIT ' . $matches['limit1'] . ',' . intval( $info[':' . $matches['limit2']] ), $sql ); } 

Это частично основано на коде Sebas.