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

问题描述 投票:12回答:3

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

php mysql prepared-statement
3个回答
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。


5
投票

试试这个:

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

0
投票

tl;博士:看看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

© www.soinside.com 2019 - 2024. All rights reserved.