Как применить метод 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 добавляет одинарные кавычки к моим переменным в ПРЕДЕЛЬНОЙ части кода SQL. Я посмотрел его, я нашел эту ошибку, которая, я думаю, связана: http://bugs.php.net/bug.php?id=44639

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

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

Author: systemovich, 2010-02-16

10 answers

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

$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);
 144
Author: Stephen Curran, 2010-02-16 00:35:34

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

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

Это не только решит вашу проблему с параметром привязки, но и позволит вам отправлять значения в 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);
 36
Author: Your Common Sense, 2017-10-14 01:37:34

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

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

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

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

 14
Author: Pekka 웃, 2010-02-16 00:32:02

Для LIMIT :init, :end

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

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
 5
Author: Nicolas Manzini, 2011-11-11 05:36:39

Это просто краткое изложение.
Существует четыре варианта параметризации ПРЕДЕЛЬНЫХ/СМЕЩЕННЫХ значений:

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

 5
Author: mario, 2017-05-23 12:02:45

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

 1
Author: Karel, 2015-05-21 20:53:12

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

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

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

 1
Author: Melissa Williams, 2016-06-17 21:48:21

//ДО (присутствует ошибка) $запрос = ".... ПРЕДЕЛ: p1, 30;"; ... $stmt->Параметр привязки (':p1', $limiteinferior);

//ПОСЛЕ (исправлена ошибка) $запрос = ".... ПРЕДЕЛ: p1, 30;"; ... $limiteinferior = (int) $лимитеинфериор; $stmt->Параметр привязки (':p1', $limiteinferior, PDO::PARAM_INT);

 0
Author: Brayan Josue Medina Melendez, 2017-08-15 06:51:20

PDO::ATTR_EMULATE_PREPARES дал мне

Драйвер не поддерживает эту функцию: Этот драйвер не поддерживает ошибку настройки атрибутов.

Мой обходной путь состоял в том, чтобы установить переменную $limit в виде строки, а затем объединить ее в инструкции prepare, как в следующем примере:

$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 ) {
    ...
}
 0
Author: Fins, 2018-07-19 12:38:54

Я сделал следующее на своем, где $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 );
    }

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

 -3
Author: spyke01, 2013-08-05 16:42:49