PHP-вставка двоичных данных в MySQL с использованием подготовленных операторов - PullRequest
12 голосов
/ 17 ноября 2009

Мне нужно вставить строку, используя улучшенную библиотеку php mysql, в таблицу в mysql, у которой есть первичный ключ типа VARBINARY. Содержимое этого поля представляет собой вычисленный хэш sha1.

Если я запускаю запрос по-старому, он отлично работает:

$mysqli->$query("INSERT INTO table (id, field1) VALUES (0x" . $id . ",'" . $field1 . "')");

Но когда я пытаюсь выполнить его как подготовленное утверждение, я не могу понять, как это сделать. Если Я выполняю эквивалентное действие:

if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (?, ?)")) {
    $stmt->bind_param('ss', "0x".$id, $field1);
    //execute statement
}

Выдает исключение, говорящее, что содержимое было слишком большим для этого поля. И если я попытаюсь вставить его как поле BLOB:

if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (?, ?)")) {
    $stmt->bind_param('bs', $id, $field1);
    //execute statement
}

Ошибка не выдается, строка вставлена, но поле идентификатора теперь пустое (не пустое, пустое).

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

Ответы [ 3 ]

7 голосов
/ 17 ноября 2009

PHP * функция sha1 возвращает строковое представление шестнадцатеричного числа.

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

Итак, возьмите шестнадцатеричное число 1A2F. Как ASCII в памяти это будет 0x31413246 вместо 0x1A2F

Нормальный интерфейс MySQL отправляет все аргументы в виде строк. При использовании обычного интерфейса MySQL преобразует строку ASCII в двоичное значение.

Новый метод подготовленного оператора отправляет все в двоичном виде. Таким образом, ваше приятное значение «1A2F» теперь будет отправлено как 0x31413246 и вставлено в столбец. - источник: dev.mysql.com - подготовленные заявления

Вместо этого преобразуйте свою шестнадцатеричную строку, упаковав ее в двоичную строку, используя:

$binId = pack("H*", $id); // this string is not ASCII, don't print it to the screen! That will be ugly.

и затем передайте $binId в подготовленный оператор MySQLi вместо $ id.

5 голосов
/ 17 ноября 2009

попробуйте вместо этого:

if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (unhex(?), ?)") {
    $stmt->bind_param('ss', $id, $field1);
    //execute statement
}
0 голосов
/ 04 мая 2015

tl; dr: check send_long_data () .

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

Это сбивает с толку, потому что единственная ссылка на то, как действовать с "b" типами в документации PHP bind_param , косвенно относится к данным, превышающим допустимый размер пакета (который я изначально пропущено):

Если размер данных переменной превышает макс. допустимый размер пакета (max_allowed_packet), вы должны указать b в типах и использовать mysqli_stmt_send_long_data () для отправки данных в пакетах.

Оказывается, двоичные типы должны отправляться сами по себе перед выполнением вставки. Я узнал об этом из статьи с сайта Oracle .

Поскольку они объясняют это так кратко, я просто перефразирую самую важную часть:

Хранение BLOB-объектов

Вот код для хранения блоба с использованием MySQLi:

$stmt = $mysqli->prepare("INSERT INTO images (image) VALUES(?)")
$null = NULL; //bolded
$stmt->bind_param("b", $null);

$stmt->send_long_data(0, file_get_contents("osaka.jpg")); //bolded

$stmt->execute();

Я выделил два куска кода, которые, я думаю, стоит посмотреть:

Требуется переменная $ null , потому что bind_param () всегда хочет ссылку на переменную для заданных параметров. В этом случае «б» (как в blob) параметр. * * * * * * * * * * * * * * * * * * * * * * * * $ null - просто фиктивная, чтобы заставить синтаксис работать.

На следующем шаге мне нужно «заполнить» мой параметр blob фактическими данными. Это делается с помощью send_long_data () . Первый параметр этот метод указывает, с каким параметром связать данные. Параметры нумеруются начиная с 0. Второй параметр send_long_data () содержит фактические данные для хранения.

При использовании send_long_data () , пожалуйста, убедитесь, что BLOB-объект не больше, чем у MySQL max_allowed_packet

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...