Как применить метод связыванияValue в предложении LIMIT?

StackOverflow https://stackoverflow.com/questions/2269840

Вопрос

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

$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 Server для правильного синтаксиса, чтобы использовать около '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 );

Это не только решит вашу проблему с параметром привязки, но и позволит вам отправлять значения в методе выполнения(), что сделает ваш код намного короче.

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

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

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

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

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

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

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

    Что предотвращает передачу значений ->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.Еще нет.

для LIMIT :init, :end

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

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], 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()

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

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

// до (настоящая ошибка) $ Query = "....ПРЕДЕЛ :p1, 30;";...$stmt->bindParam(':p1', $limiteInferior);

// после (исправленная ошибка) $ Query = "....ПРЕДЕЛ :p1, 30;";...$limiteInferior = (int)$limiteInferior;$stmt->bindParam(':p1', $limiteInferior, PDO::PARAM_INT);

PDO::ATTR_EMULATE_PREPARES дал мне

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

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

$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 ) {
    ...
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top