PHP / PDO / MySQL:插入MEDIUMBLOB存储坏数据

时间:2011-06-14 15:46:48

标签: php mysql pdo blob

我有一个简单的PHP Web应用程序,通过文件上传接受图标图像并将它们存储在MEDIUMBLOB列中。

在我的机器(Windows)和两台Linux服务器上,这很好用。在第三台Linux服务器上,插入的映像已损坏:在SELECT之后无法读取,并且MySQL length()函数报告的列数据长度比上载文件的大小大约40%。

(每个服务器连接到一个单独的MySQL实例。)

当然,这让我想到了编码和字符集问题。 BLOB列没有关联的字符集,因此看起来最可能的罪魁祸首是PDO及其对该列的参数值的解释。

  • 我尝试将bindValue与PDO :: PARAM_LOB一起使用,没有效果。
  • 我已经验证了服务器上正在接收图像(即上传后没有问题),所以这绝对是一个DB / PDO问题。
  • 我搜索了服务器之间明显的配置差​​异,但我不是PHP配置方面的专家,所以我可能错过了一些东西。

插入代码大致如下:

$imagedata = file_get_contents($_FILES["icon"]["tmp_name"]);
$stmt = $pdo->prepare('insert into foo (theimage) values (:theimage)');
$stmt->bindValue(':theimage', $imagedata, PDO::PARAM_LOB);
$stmt->execute();

任何帮助都将非常感激。

UPDATE :有问题的服务器上的默认MySQL字符集是utf8;这是其他人的拉丁文。

通过将PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES latin1 COLLATE latin1_general_ci"添加到PDO构造函数来“解决”问题。

对我来说这似乎是一个错误的设计:为什么 connection 的字符集对二进制列的数据有任何影响,特别是当它被识别为二进制到PDO本身与PARAM_LOB?

请注意,在所有情况下,DB表都定义为latin1:它只是服务器的默认字符集不一致。

1 个答案:

答案 0 :(得分:2)

  

这对我来说似乎是一个错误:为什么连接的字符集会对二进制列的数据产生任何影响,特别是当它被PARAM_LOB识别为PDO本身的二进制时?

我认为这不一定是个错误。我可以想象,只要客户端与服务器通话并且说下面的命令是UTF-8并且服务器需要它在Latin-1中,那么查询可能在解析和执行之前被重新编码。所以这是数据传输的编码问题。由于整个查询先前的解析将受到此重新编码的影响,因此BLOB列的二进制数据也将更改。

From the Mysql manual:

  

服务器收到语句后应该将哪个字符集转换为

     

为此,服务器使用character_set_connection和collat​​ion_connection系统变量。它将客户端发送的语句从character_set_client转换为character_set_connection(除了具有_latin1或_utf8等导入器的字符串文字)。 collat​​ion_connection对于文字字符串的比较很重要。对于具有列值的字符串的比较,collat​​ion_connection无关紧要,因为列具有自己的排序规则,其具有更高的排序规则优先级。

或者在回来的路上:来自商店的Latin1数据将转换为UTF-8,因为客户告诉服务器它更喜欢UTF-8用于运输。

您命名的PDO本身的标识符看起来完全不同:

  

PDO :: PARAM_LOB 告诉PDO将数据映射为流,以便您可以使用PHP Streams API对其进行操作。 (Ref

我不是MySQL专家,但我会这样解释。客户端和服务器需要协商他们正在使用哪些字符集,我认为他们出于某种原因这样做。