PDO PHP bindValue не работает
Я знаю, что это было задано 1000 раз, но по какой-то причине я продолжаю биться головой о стену..
это работает:
$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( ' . $regGUID . ' ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = "' . $game . '" order by a.eventTime desc, a.actionCode asc';
$stmt = $db->prepare($sql);
$results = $stmt->execute();
это не так:
$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc';
$stmt = $db->prepare($sql);
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();
что я упустил? Спасибо
4 ответов
проблема:
$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
Я предполагаю, что $regGUID-это разделенный запятыми список цитируемых строк.
каждый параметр запроса принимает только одно скалярное значение. Не списки ценностей.
Итак, у вас есть два варианта:
-
продолжайте интерполировать строку $regGUID, даже если вы используете параметры для других скалярных значений. Но вы все равно хотите быть осторожны, чтобы избежать SQL-инъекции, поэтому вы должны правильно сформируйте строку $regGUID. Вы не можете просто вызвать PDO::quote() во всей строке, что сделало бы ее одной строкой с кавычками, содержащей UUID и запятые. Вы должны убедиться, что каждая строка UUID экранирована и цитируется отдельно, а затем свернуть список вместе и интерполировать его в предложение IN.
$regGUIDs = explode(',', $regGUID); $regGUIDs = array_map(function ($g) { return $db->quote($g); }, $regGUIDs); $regGUID = implode(',', $regGUIDs); $sql = $sql . 'WHERE a.regGUID in (' . $regGUID . ') and ';
-
explode()
$regGUID в массив и добавьте один параметр запроса для каждого элемента в массиве. Интерполировать динамический список параметров запроса подстановки.$regGUIDs = explode(',', $regGUID); $params = array_fill(1, count($regGUIDs), '?'); $sql = $sql . ' WHERE a.regGUID in ( ' . implode(',', $params) . ' ) and ';
вы можете bindValue () в цикле для массива, но имейте в виду, что другие параметры также должны быть связаны позицией, а не именем. PDO есть ошибки, которые делают его не счастлив, когда вы пытаетесь смешать два разных стиля параметров в одном запросе.
вместо использования bindValue () я просто передаю массив значений параметров в PDOStatement::execute (), что намного проще.
$paramValues = $regGUIDs;
$paramValues[] = $game;
$results = $stmt->execute($paramValues);
это действительно было задано 1000 раз.
подготовленные заявления могут принимать только скалярные значения, а не произвольные части SQL-запроса.
вы должны сформировать оператор IN (), используя столько заполнителей, сколько элементов вы должны поместить, а затем связать их один за другим.
для облегчения этой задачи можно использовать некоторые вспомогательные функции.
говорят, используя библиотека SafeMysql этот код может быть написан as
$sql = 'SELECT * FROM events a, players b WHERE regGUID in (?a) and';
$sql .= ' a.playerCode=b.playerCode and a.gameCode = ?s';
$sql .= ' order by a.eventTime desc, a.actionCode asc';
$results = $db->getAll($sql,$regGUID,$game);
отметим, что $regGUID
должен быть массив, а не строку, а $results
уже содержат все запрошенные данные без какой-либо дальнейшей обработки.
содержание $regGUID
? Поскольку вы используете in
предложение, я подозреваю, что список разделен запятыми.
привязка переменной к параметру не похожа на замену этой строки в запросе; это похоже на то, как сказать MySQL, как использовать ваши фактические переменные PHP. Поэтому, если вы связываете строку как '1,2,3'
для параметра запроса он остается одной строкой и не интерпретируется как список чисел.
следовательно, если $regGUID
- Это что-то вроде "'AAA1', 'BBB2'"
ваша первая запрос становится
... WHERE a.regGUID in ( 'AAA1', 'BBB2' ) ...
но ваш второй запрос больше похож на
... WHERE a.regGUID in ( '\'AAA1\', \'BBB2\'' ) ...
что означает
... WHERE a.regGUID = '\'AAA1\', \'BBB2\'' ...
поскольку другие имеют состояние, вы можете привязать только одно скалярное значение к заполнителю. Таким образом, это означает, что вам действительно нужен заполнитель для каждого значения в вашем IN
заявление. Обычно я делаю что-то вроде следующего. Следует отметить, что я никогда не использую bindValue
поэтому, если у него есть правила о вещах, которые должны быть ссылками, такими как Mysqli, то ниже может потребоваться изменить:
$regGUIDPlaceholders = array();
// prepare the placeholders
// assume regGUID is an array - if its a string then explode on whatever to make it an array
foreach($regGUID as $k => $v) {
$placeholder = ':regGUID' . $k;
$regGUIDPlaceholders[$key] = $value;
}
// prepare the IN statememnt
$in = sprintf('IN (%s)', implode(',', array_keys($regGUIDPlaceholders)));
$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
// USE the IN statement dynamically prepared above
$sql = $sql . 'WHERE a.regGUID '. $in . ' and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc';
$stmt = $db->prepare($sql);
// bind each GUID to its placeholder
foreach($regGUIDPlaceholders as $placeholder => $value) {
$stmt->bindValue($placeholder, $value, PDO::PARAM_STR);
}
$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();