关于php:将UTF-8编码的字符串插入UTF-8编码的mysql表失败,并显示“字符串值不正确”

Inserting UTF-8 encoded string into UTF-8 encoded mysql table fails with “Incorrect string value”

将utf-8编码的字符串插入到utf-8编码的表中会给出不正确的字符串值。

PDOException: SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9D\x84\x8E i...' for column 'body_value' at row 1: INSERT INTO

我有一个??字符,在一个字符串中,mb-detect-u编码声明是utf-8编码的。我试图将这个字符串插入到一个mysql表中,这个表被定义为(除其他外)DEFAULT CHARSET=utf8

编辑:drupal总是使用可选的COLLATE(至少在与mysql对话时)。

编辑2:更多相关的细节。我从PostgreSQL数据库中获取一些文本。我将它粘贴到一个对象上,使用mb_detect_编码来验证它是UTF-8,并使用node_save将该对象保存到数据库中。因此,虽然存在触发导入的HTTP请求,但数据并不来自浏览器。

编辑3:数据在两个表上非规范化:

SELECT character_set_name FROM information_schema.COLUMNS C WHERE table_schema ="[database]" AND table_name IN ("field_data_body","field_revision_body") AND column_name ="body_value";

1
2
3
4
5
6
>+--------------------+
| character_set_name |
+--------------------+
| utf8               |
| utf8               |
+--------------------+

编辑4:是否可能角色是"到新的"?我对unicode和utf-8之间的关系有点模糊,但这篇维基百科文章暗示这个字符最近被标准化了。

我不明白"不正确的字符串值"是如何失败的。


是吗??(u+1d10e)是在BMP(基本多语言平面)(在u+ffff之上)之外发现的Unicode字符,因此不能以3字节的utf-8表示。mysql字符集utf8只接受utf-8字符,前提是它们可以用3个字节表示。如果需要将其存储在MySQL中,则需要使用MySQL字符集utf8mb4。您需要MySQL5.5.3或更高版本。您可以使用alter table来更改字符集,而不会有太大的问题;因为存储字符需要更多的空间,所以会出现一些问题,可能需要您减小字符串大小。请参阅http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-upgrading.html。


要解决这个问题,首先将数据库字段更改为utf8m4b字符集。例如:

1
ALTER TABLE `tb_name` CHANGE `field_name` `field_name` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL;

然后在数据库连接中,将驱动程序选项设置为utf8mb4。例如,如果使用PDO

1
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');

或在Zend框架1.2中

1
2
3
4
5
6
7
$dbParam = array('host' => 'localhost', 'username' => 'db_user_name',
            'password' => 'password', 'dbname' => 'db_name',
            'driver_options' => array(
                '1002' =>"SET NAMES 'utf8mb4'",
                '12'    => 0
            )
        );


在PDO连接中,设置字符集。

1
new PDO('mysql:host=localhost;dbname=the_db;charset=utf8', $user, $password);