Как применить метод 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.
10 answers
Я помню, что раньше у меня была такая проблема. Приведите значение к целому числу, прежде чем передавать его в функцию привязки. Я думаю, что это решает проблему.
$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);
Самым простым решением было бы отключить режим эмуляции . Вы можете сделать это либо в качестве опции подключения, либо просто добавив следующую строку
$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);
Глядя на отчет об ошибке, может сработать следующее:
$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
ко всем переменным в массиве, а для LIMIT
вам абсолютно необходимо целое число.
Значение привязки или параметр привязки, как вы хотите.
$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
Это просто краткое изложение.
Существует четыре варианта параметризации ПРЕДЕЛЬНЫХ/СМЕЩЕННЫХ значений:
-
Отключить
PDO::ATTR_EMULATE_PREPARES
, как упоминалось выше., который не позволяет значениям, передаваемым в
->execute([...])
, всегда отображаться в виде строк. -
Переключитесь на ручное заполнение параметров
->bindValue(..., ..., PDO::PARAM_INT)
., что, однако, менее удобно, чем ->список выполнения[].
-
Просто сделайте исключение здесь и просто интерполируйте простые целые числа при подготовке SQL-запрос.
$limit = intval($limit); $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
Кастинг важен. Чаще всего вы видите
->prepare(sprintf("SELECT ... LIMIT %d", $num))
используется для таких целей. -
Если вы используете не MySQL, а, например, SQLite или Postgres; вы также можете использовать привязанные параметры непосредственно в SQL.
SELECT * FROM tbl LIMIT (1 * :limit)
Опять же, MySQL/MariaDB не поддерживают выражения в предложении LIMIT. Ещё нет.
Смещение и ограничение значения привязки с помощью PDO::PARAM_INT, и это будет работать
Поскольку никто не объяснил, почему это происходит, я добавляю ответ. Причина, по которой он ведет себя так, заключается в том, что вы используете trim()
. Если вы посмотрите руководство по PHP для trim
, тип возвращаемого значения string
. Затем вы пытаетесь передать это как PDO::PARAM_INT
. Несколько способов обойти это:
- Используйте
filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
, чтобы убедиться, что вы передаете целое число. - Как говорили другие, используя
intval()
- Кастинг с помощью
(int)
- Проверка, является ли оно целым числом с
is_int()
Есть еще много способов, но это в основном первопричина.
//ДО (присутствует ошибка) $запрос = ".... ПРЕДЕЛ: p1, 30;"; ... $stmt->Параметр привязки (':p1', $limiteinferior);
//ПОСЛЕ (исправлена ошибка) $запрос = ".... ПРЕДЕЛ: p1, 30;"; ... $limiteinferior = (int) $лимитеинфериор; $stmt->Параметр привязки (':p1', $limiteinferior, PDO::PARAM_INT);
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 ) {
...
}
Я сделал следующее на своем, где $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 );
}
Это частично основано на коде Себаса.