我有一个 PHP 7.3 项目,目前使用 MySQL 5.5,带有utf8
表格。一些表格包含表情符号数据,这些数据在当前项目中显示正常。我试图将项目更新到 MySQL 8.x,但当我这样做时,表情符号数据显示不正确。
首先,我更新了所有 5.5 表以使用uf8mb4
。在此状态下,数据显示了出来。然后我更新到了 5.7,一切继续正常。我转储了这些数据,更新到了 8.0,然后重新加载了它(我--default-character-set=utf8mb4
在转储和加载时都使用了标志),然后数据就无法正确显示了,例如灯泡显示为💡
。
我正在 docker 中运行这些服务。我能够使用相同的数据卷从 5.5 更新到 5.7,没有任何问题,但是当尝试从 5.7 升级到 8.0 时,我遇到了无法解决的错误,最终进行了数据转储/恢复。
带有表情符号字段的示例表:
DROP TABLE IF EXISTS `forums`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `forums` (
`forumID` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci,
`forumType` varchar(1) COLLATE utf8_unicode_ci DEFAULT 'f',
`parentID` int(11) DEFAULT NULL,
`heritage` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
`order` int(5) NOT NULL,
`gameID` int(11) DEFAULT NULL,
`threadCount` int(11) NOT NULL,
PRIMARY KEY (`forumID`),
UNIQUE KEY `heritage` (`heritage`),
KEY `parentID` (`parentID`)
) ENGINE=MyISAM AUTO_INCREMENT=11551 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `forums`
--
LOCK TABLES `forums` WRITE;
/*!40000 ALTER TABLE `forums` DISABLE KEYS */;
INSERT INTO `forums` VALUES (8003,'💡 Gamers\' Plane development',NULL,'f',2,'0002-8003',3180,3181,4);
/*!40000 ALTER TABLE `forums` ENABLE KEYS */;
UNLOCK TABLES;
为了将表格更新为 utf8mb4,我做了
ALTER TABLE forums CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
我如何测试该数据的返回:
<?php
$mysql = new PDO("mysql:host=mysql;dbname=gamersplane", 'gamersplane', 'mypass');
$mysql->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$mysql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$forum = $mysql->query('select * from forums where forumID = 8003')->fetch();
?>
<html>
<header>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</header>
<body>
<?php print_r($forum['title']); ?>
</body>
</html>
我已经读完了 [UTF-8] [1] 并且
[1]:全部使用 UTF-8 编码,
utf8mb4
在数据库中使用- 在
charset=utf8mb4
我的 PDO 字符串中 - 已
default_charset
在我的 php.ini 中明确设置,并尝试在运行时设置它 - 已经尝试过
Content-Type: text/html; charset=utf-8
作为 PHP 标头以及 HTML 元标记
数据库中的编码总是很有趣!不幸的是,当您更改字符集时,它不会更新数据,只会更新数据库如何解释数据,而且 MySQL 不会动态执行编码更改,并且始终按来自客户端的字节数记录它们。从示例中您可以看到,这
💡
就是latin1
的表示💡
,当您转储数据时,它会以错误的编码转储数据。要验证该问题,您可以尝试使用以下查询转换数据:
在您最新的 MySQL8 环境中,它应该可以正确显示表情符号。如果是这样,您应该尝试再次转储数据,这次使用最初编码的字符集,最有可能
latin1
使用--default-character-set=latin1
。转储文件应该包含表情符号,而不是💡
类似文本。请注意,如果表中有新内容,它将被双重编码,或者转储填充将失败,如果新文本与编码不兼容
latin1
,最好使用原始集进行执行(如果您仍然可以访问它)。