Mysqli bind_param() не работает должным образом

Может ли кто-нибудь сказать мне, что я делаю неправильно? Когда я выполняю и получаю это, я становлюсь правильным результатом.

$message = '100';
if($stmt = $mysqli->prepare("select english from table where message=? LIMIT 1")) {
$stmt = bind_param("i", $message);
} //Return the Message in English

Но когда я помещаю язык в переменную и использую bind_param(). Я просто получаю новую переменную в результате, например:

$message = '100';
$language = 'english';
if($stmt = $mysqli->prepare("select ? from table where message=? LIMIT 1")) {
$stmt = bind_param("si", $language, $message);
} //Returns "english"

Я предполагаю, что проблема в том, что "$language" привязан как "String". Каким будет правильный тип? Пробовал уже изменить его на blob или double безрезультатно.


person Dennis    schedule 20.08.2015    source источник


Ответы (1)


Давайте посмотрим, что делает bind_param.

$stmt = $mysqli->prepare("select * from users where name=?");
$stmt->bind_param("s", "Dennis");

примерно эквивалентно

$stmt = $mysqli->prepare("select * from users where name='Dennis'");

Однако использование bind_param намного безопаснее, чем вставлять значение вручную в SQL-запрос. Потому что при вставке значения руками нужно аккуратно обращаться со специальными символами; в противном случае злонамеренно созданное значение может заставить SQL-анализатор рассматривать части значения не как значение, а как команды, имена таблиц, имена столбцов и т. д. bind_param сделает это за вас; с bind_param вам не нужно беспокоиться о том, что Dennis должно быть преобразовано в 'Dennis' перед вставкой в ​​SQL-запрос, но Dennis O'Brian должно превратиться в 'Dennis O\'Brian' (а не 'Dennis O'Brian'), и NUL-символ должен превратиться в '\0' (не оставаться как NUL-символ).

Параметр bind_param подходит только для вставки значений в SQL-запрос. Потому что, когда вам нужно вставить имя столбца или таблицы в SQL-запрос, вам на самом деле нужно обратное - вам нужно, чтобы имя столбца было вставлено в SQL-запрос напрямую (без добавления каких-либо кавычек и т. д.). Итак, вам действительно нужно:

select english from table where message=... LIMIT 1

нет

select 'english' from table where message=... LIMIT 1

Итак, просто сделайте это:

$message = '100';
$language = 'english';
$sql = "select " . $language . " from table where message=? LIMIT 1";
if($stmt = $mysqli->prepare($sql)) {
    $stmt->bind_param("i", $message);
}

Единственное, что вы должны быть уверены, что $language содержит действительное имя столбца. В противном случае, если пользователь принудительно пропустит что-то плохое через $language, вы получите SQL-injection.

$message = ...;
$language = ...;
...;
if(!in_array($language, array('english', 'german', 'french'), true))
    $language = 'english';
$sql = "select " . $language . " from table where message=? LIMIT 1";
if($stmt = $mysqli->prepare($sql)) {
    $stmt->bind_param("i", $message);
}
person Sasha    schedule 20.08.2015
comment
Вау, спасибо за быстрый и подробный ответ. Это очень помогло - person Dennis; 20.08.2015