我必须使用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
}
没有错误,插入行,但标识符字段现在为空(不为空,为空)。
我知道我可以混合查询并输入字符串中连接的id和其他字段作为预准备语句的绑定参数,但我只想知道插入这个的正确方法是什么,也许它会帮助将来的某个人。
答案 0 :(得分:7)
PHP的sha1
函数返回十六进制数字的字符串表示。
这意味着如果您将其打印到屏幕,它将显示十六进制数字。但在内存中,它是一堆ASCII字符。
所以,取十六进制数1A2F
。内存中的ASCII为0x31413246
,而不是0x1A2F
MySQL的普通接口将所有参数作为字符串发送。使用普通接口时,MySQL会将ASCII字符串转换为二进制值。
新的预处理语句方法将所有内容发送为二进制文件。因此,“1A2F”的漂亮值现在将作为0x31413246发送并插入到列中。 - source: dev.mysql.com - Prepared statements
相反,请使用以下方法将Hex字符串转换为二进制字符串:
$binId = pack("H*", $id); // this string is not ASCII, don't print it to the screen! That will be ugly.
然后将$binId
传递给MySQLi预处理语句而不是$ id。
答案 1 :(得分:5)
试试这个:
if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (unhex(?), ?)") {
$stmt->bind_param('ss', $id, $field1);
//execute statement
}
答案 2 :(得分:0)
tl; dr:看看send_long_data()。
我知道这是一个非常古老的问题,但完全我正在尝试做什么并且失败了。在尝试上述答案并花费大量时间进行实验之后,我终于发现了一些与我正在尝试的方式相同的方法。
令人困惑,因为在引用超出允许数据包大小的数据(我最初跳过的数据)时,间接引用如何在PHP bind_param documentation中继续“b”类型的唯一参考):
如果变量的数据大小超过最大值。允许的包大小 (max_allowed_packet),您必须在类型中指定 b 并使用 mysqli_stmt_send_long_data()以数据包形式发送数据。
事实证明,在执行插入之前必须自己发送二进制类型。我是从article from Oracle's website发现的。
由于他们如此简洁地解释,我只想解释最相关的部分:
存储blob
以下是使用MySQLi存储blob的代码:
$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()总是需要给定参数的变量引用。在这种情况下,“b”(如 blob)参数。所以 $ null 只是一个假人,以使语法有效。
在下一步中,我需要用实际数据“填充”我的blob参数。这是由 send_long_data()完成的。第一个参数 此方法指示将数据与哪个参数相关联。 参数从0开始编号。第二个参数 send_long_data()包含要存储的实际数据。
使用 send_long_data()时,请确保blob不是 大于MySQL的 max_allowed_packet