混合UTF-8和latin1表与PDO

时间:2012-11-29 09:52:55

标签: php mysql character-encoding pdo

有一个现有的数据库/表格,我无法更改字符集。这些表使用排序规则“latin1_swedish_ci”,但内部存储了UTF-8数据。例如,字符串“fußball”(德国足球)保存为“fußball”。这是我无法改变的部分。

我的整个脚本可以正常使用UTF-8和它自己的UTF-8表,我使用PDO(mySQL)和UTF-8连接进行查询。但有时我不得不查询一些“旧的”latin1表。是否有任何“酷”方式来解决这个问题,而不是发送SET NAMES。

这是我在stackoverflow的第一个问题! : - )

2 个答案:

答案 0 :(得分:2)

  1. 实际上很容易认为数据以一种方式编码,当它实际上以其他方式编码时:这是因为任何直接检索数据的尝试都会导致首先转换为数据库连接的字符集,然后转换为输出媒体的字符集 - 因此,您应首先通过SELECT BINARY myColumn FROM myTable WHERE ...SELECT HEX(myColumn) FROM myTable WHERE ...验证存储数据的实际编码。

  2. 一旦某些你有一个存储在Windows-1252编码列中的UTF-8编码数据(即你看到0xc39f所在的字符{{1}你希望真正想要的是从列中删除编码信息,然后告诉MySQL数据实际编码为UTF-8。正如ALTER TABLE Syntax所述:

      

    警告

         

    ß操作会在字符集之间转换列值。如果您在一个字符集中有一列(如CONVERT TO),那么你想要的是什么,但存储的值实际上使用了一些其他不兼容的字符集(如latin1) 。在这种情况下,您必须为每个此类列执行以下操作:

    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
    
         

    这样做的原因是当您转换为BLOB列或来自{{3}}列时没有转化。

  3. 此后,MySQL会根据需要将所选数据正确转换为连接字符集的数据。也就是说,如果连接使用UTF-8,则不需要转换;而使用Windows-1252的连接将接收转换为该字符集的字符串。

  4. 不仅如此,还可以正确执行MySQL中的字符串比较。例如,如果您当前使用UTF-8字符集连接并搜索utf8,则不会得到任何结果;而你会在上面的修改之后。

  5. 您提到的必须更改大量遗留脚本的陷阱只适用于那些遗留脚本使用不正确的连接字符集(例如,告诉MySQL他们使用Windows-1252而他们实际上是发送并期望收到UTF-8中的数据。你真的应该在任何情况下解决这个问题,因为它可能导致各种各样的恐怖事件发生。

答案 1 :(得分:1)

我通过在我的DB类中创建另一个数据库句柄来解决它,它使用latin1所以每当我需要查询“遗留表”时我都可以使用

$pdo    = Db::getInstance();
$pdo->legacyDbh->query("MY QUERY");
# instead of
$pdo->dbh->query("MY QUERY");

如果有人有一个更好的解决方案,也不触及表..: - )