2009-11-17 59 views
8

我必须使用php的mysql改进的库插入一行到mysql中具有VARBINARY类型主键的表中。 该字段的内容是一个计算出来的sha1散列。PHP-使用预准备语句在mysql中插入二进制数据

如果我运行查询的老路上它完美的作品:

$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

你对的$ id什么样的价值观和$ FIELD1,当你做这样大? $ id是一个整数?如果是这样,你有没有尝试过绑定它? 'stmt-> bind_param('是',$ id,$ field1);' – nash 2009-11-17 11:43:10

+0

$ id的值是一个sha1散列。它不是一个整数。其他领域不会导致问题,但主要是字符串。 – 2009-11-17 13:37:44

+0

另外一个用于在解决此问题的同时保留准备好的语句的安全性。 – HoldOffHunger 2016-05-25 01:13:38

回答

6

PHP的sha1函数返回一个十六进制数字的字符串表示。

这意味着如果您将其打印到屏幕上,它将显示一个十六进制数字。但在内存中,它是一堆ASCII字符。

因此,取十六进制数1A2F。作为内存中的ASCII将是0x31413246,而不是0x1A2F

MySQL的正常接口将所有参数作为字符串发送。当使用普通接口时,MySQL会将ASCII字符串转换为二进制值。

新准备的语句方法将所有内容以二进制形式发送。所以你的“1A2F”的好值现在将作为0x31413246发送并插入到列中。 - source: dev.mysql.com - Prepared statements

相反,通过打包成用二进制字符串转换您的十六进制字符串:

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

,然后通过$binId到的MySQLi准备语句而不是$ ID。

+0

你说得对。这是做到这一点的方法。非常感谢你。 – 2009-11-18 11:23:20

+0

想知道这个我自己!只需要注意,你也可以使用'hex2bin'作为'pack'的一个方便的替代方法,并且在再次拉出数据时(而不是在你的语句中使用'HEX()')时可以使用'bin2hex'。 – Haravikk 2016-10-23 10:39:15

3

试试这个:

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

tl; dr:检出send_long_data()

我知道这是一个非常古老的问题,但它是正好是我正在尝试做什么和失败。在尝试了上面的答案并花费了很多时间试验之后,我终于找到了一些能够解决问题的方法,并且我正在尝试。

这是令人困惑的,因为如何与“b”的类型在PHP bind_param documentation继续进行的唯一引用是间接参照数据超标分组大小(我最初跳过)时:

如果变量的数据大小超过最大值。允许的数据包大小 (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(); 

我粗体显示了两段代码,其中第I行油墨是值得看的:

$空变量是必要的,因为bind_param()总是想对于一个给定的参数变量引用。在这种情况下,“b”(如 blob)参数。所以$ null只是一个虚拟的,使语法工作。

在接下来的步骤中,我需要用实际数据填充我的blob参数。这由send_long_data()完成。该方法的第一个参数 指示将数据与哪个参数相关联。 参数从0开始编号。第二个参数 send_long_data()包含要存储的实际数据。

在使用send_long_data(),请确保团块不 比MySQL的max_allowed_pa​​cket的

相关问题