PHP-使用预准备语句在mysql中插入二进制数据

时间:2009-11-17 10:24:07

标签: php mysql prepared-statement

我必须使用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和其他字段作为预准备语句的绑定参数,但我只想知道插入这个的正确方法是什么,也许它会帮助将来的某个人。

3 个答案:

答案 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_pa​​cket),您必须在类型中指定 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_pa​​cket