发现问题
问题似乎是$mysqli->set_charset()不接受`utf8mb4'作为有效编码(就像我在第一次更新中"推测"的那样)。 MySQL版本是5.5.41,PHP版本是5.4.41(没问题)。
对不起,标题,我一直在搜索/阅读问题可能在哪里/什么地方,对此我已经太困惑了...
我最近开始在mysql中使用utf8mb4。我将utf8mb4用作字符集,并将utf8mb4_unicode_ci用作所有表/列的排序规则。
所以我首先改变了:
$mysqli->set_charset('utf8');
至
$mysqli->set_charset('utf8mb4');
确保我的php文件是utf8(我使用的是Visual Studio Code,因此默认情况下以UTF-8创建文件),并且php / html标头设置为utf8:
的index.php
header('Content-type: Text/HTML; Charset=UTF-8');
main.php(包含在index.php的末尾)
问题是,对于某些表,我必须手动插入数据,并且该数据按原样存储:带有特殊字符,带有重音符号,?等。当我在网站上显示此数据时,我可以看到这些字符?已替换特殊/重音字符。
所以我的问题是:有没有办法在mysql中按原样存储数据(而不替换/转换特殊/带有重音符号的字符)并能够正常显示它?
如果我恢复为$mysqli->set_charset('utf8');,则数据显示正常...因此,我一直想知道存储utf-8字符应该没有问题,并且某个地方存在编纂问题...
我正在使用sqlyog社区(带有wine),并且我读到某个地方,当您更改某些db / table配置时,有时gui无法正常工作,唯一的方法是旧方法(运行查询),但是我还没有尝试过 s>。我运行查询来设置所有表/列的字符集和排序规则。
你怎么看?
UPDATE
我开始认为mysqli不接受utf8mb4作为有效的字符编码并使用php而非mysql中的utf8 ...我也认为mysql会创建utf8mb4而不是更新现有的utf8以支持4个字节... 。
当我使用mysqli charset utf8测试时,所有内容均按原样存储并按原样显示(将mysql charset和collat??ion设置为utf8mb4 ...)。
更新2
SELECT name, HEX(name) FROM person LIMIT 1
这是它的输出:
New Person has name Alta?r 416C7461C3AF72
但是正如我已经说过的,这正在使用:
$mysqli->set_charset('utf8');
插入并选择。如果我改用utf8mb4,它就是它存储的内容:
Alta?ˉr
但是显示没问题。好的,如果名称按原样存储,则显示为Alta?r。
因此问题是:为什么mysqli / mysql使用utf8mb4将?存储为?ˉ?当在mysqli中设置utf8mb4时,为什么为什么php在?中显示特殊字符,如??
有人可以确认mysqli::set_charset接受utf8mb4作为有效编码吗?
更新3
我有一个从表" es"中选择字符串的类函数,例如:Iniciar Sesión(这是存储的内容),如果mysqli charset是utf8,则正在选择/显示的是Iniciar Sesi?3n。
这可能是一个完全不同的问题,但显然是另一个编纂问题。据我了解,如果表/列为utf8mb4且mysqli设置为utf8,则mysql必须将utf8(3字节)编码为ut8mb4(全字节支持)。因此,这意味着mysqli不会从php使用utf8,而是从mysql使用。这样对吗?
我的应用程序目前在编码方面比较艰难...(但是可能是一些服务器配置问题...)
更新4
问题可以在这里吗?我真的不知道这种配置:
SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| collation_connection | utf8_general_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | latin1_swedish_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)
更新4-1 / 2(从评论复制)
CREATE TABLE `es` (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
text varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`
没有转换?您是说BLOB吗?处理UTF8的经验法则是:始终记录转换+编码+解码方法。
什么是BLOB?我以为php为我处理了这件事...如果php与utf8一起使用并从mysql取得utf8mb4,则需要哪种转换?
BLOB是一种MySQL数据类型,通常用于存储大量文本或二进制数据。看到这里dev.mysql.com/doc/refman/5.7/en/blob.html。
对啊不,我不使用BLOB,我只使用基本数据类型作为text和var / char。
要检查的另一件事是您在列定义中为特殊字符分配了足够的空间。例如,varchar(255)的大小不足以包含255个特殊字符。
您的问题是:有没有办法在mysql中按原样存储数据(无需替换/转换特殊/重音字符)?或者您想将问题更改为更合适的内容:使用php将UTF-8 /编码字符串存储到mysql的最佳实践是什么?
显然,我更喜欢最佳实践,但是我问这个问题是因为如果我必须手动插入数据并且其中包含特殊字符,它们将无法正确显示...所以...我只是更加困惑了:P
@Vadim幸运的是,在4.1之前,现在它以字符而不是字节为单位来计算长度dev.mysql.com/doc/refman/5.0/en/string-type-overview.html
请提供SELECT col, HEX(col) FROM ...,以便我们可以看到文本的存储方式。这将告诉我们文本是存储错误还是获取错误。 ?和有不同的原因。
和是CHARACTER SET latin1中的十六进制F1和EF。它们是utf8或utf8mb4中的C3B1和C3AF(无差异)。
@RickJames我只是回显专栏吗?
@RickJames将mysqli字符集设置为utf8,即时得到此消息:416C7461C3AF722049626E2D4C612741686164。 utf8mb4:416C7461C383C2AF722049626E2D4C612741686164。
填写表名,WHERE子句并将col更改为相关列名后,执行我建议的SELECT。
@RickJames您希望我在WHERE子句中添加什么?我更新了我的问题。
很好... Altar,当用utf8(或utf8mb4)编码时,是41 6C 74 61 C3AF 72。也就是说,表中的数据正确为utf8。您正在运行什么版本的PHP和MySQL?
在Centos 5下,PHP是5.4.41,而MySQL是5.5.41。
@RickJames我刚刚注意到,只有当mysqli charset为utf8mb4(并且表中的数据为utf8)时,框架中的类函数才能正常打印字符。它是一种语言系统,它根据浏览器/ Cookie /配置区域设置选择一个表或另一个表。这越来越奇怪了。
否,使用mysqli charset utf8mb4 Altar是41 6C 74 61 C383C2AF 72时。
Sesin的utf8 / utf8mb4十六进制为53 65 73 69 C3B3 6E。 Sesin /十六进制53 65 73 69 C383 C2B3 6E表示"双重编码"。
引入utf8mb4时是MySQL 5.5.3,因此在那里很安全。 PHP可能只是简单地将字符串传递而无需关心。执行charset后尝试一下:printf("Current character set: %s
", mysqli_character_set_name($link));
请提供SHOW CREATE TABLE es。
$mysqli = new mysqli(); $mysqli->set_charset(utf8mb4); printf("Current character set: %s
", mysqli_character_set_name($mysqli));这是打印的内容:Current character set: latin1。如果我将其更改为utf8,它说的是utf8 ...所以我是正确的(第一次更新),mysqli不接受utf8mb4 ...
SHOW CREATE TABLE es-> CREATE TABLE es`(id int(11)NOT NULL AUTO_INCREMENT,name varchar(30)COLLATE utf8mb4_unicode_ci DEFAULT NULL,text varchar(100)COLLUT utf8mb4_unicode_ci DEFAULT NULL,PRIMARY KEY( x2>),唯一键name(name))ENGINE = InnoDB AUTO_INCREMENT = 76 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci`
问题可能源于您在MySQL列定义中未使用utf8mb4的事实(至少您没有说出正在使用的编码)。
这是一个MySQL表定义的示例,其中的列使用utfmb4:
CREATE TABLE `person` (
`name` varchar(255) CHARACTER SET utf8mb4
)
UPDATE
使用下表定义:
CREATE TABLE `person` (
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
和以下PHP脚本:
$mysqli = new mysqli('localhost', 'username', 'password', 'database');
$mysqli->set_charset('utf8mb4');
$mysqli->query("INSERT INTO `person` VALUES ('Alta?r Ibn-La\'Ahad')");
$result = $mysqli->query("SELECT * FROM `person` LIMIT 1");
$person = $result->fetch_object();
if($person)
printf ("New Person has name %s.
", $person->name);
$result->close();
$mysqli->close();
当我在数据库中插入" Alta?r Ibn-La'Ahad"时,该名称将按原样存储而没有更改。该脚本还会打印名称,而无需更改:"新人的名字是Alta?r Ibn-La'Ahad。"
我希望这可以帮助您解决问题。让我知道是否可以。
我使用utf8mb4作为字符集,并使用utf8mb4_unicode_ci作为所有表/列的排序规则。
当您插入数据时,它在数据库中看起来是否正确:1)直接插入数据库时??; 2)何时用PHP插入?
当我直接插入数据时,它看起来保持不变。但是,当我用php插入它时,这取决于我如何处理php中的用户输入。如果我使用过滤器,它将转换特殊字符,但它们会按照原样显示。例如:我插入名称" Altar Ibn-LaAhad",这就是存储的" Altar Ibn-LaAhad"。如果我不过滤,则只是转换为的内容。
我用一个例子更新了我的原始答案。在按原样存储数据时,它会产生所需的输出。
我已经用查询创建了表并执行了脚本。但是名称存储如我上次所说,存储为。我的mysql服务器肯定有问题...我已将您的答案标记为正确的,我不得不进一步研究服务器配置。
值得一提的是,我使用Mac编写了此脚本。 Windows可能以不同的方式处理事情。另外,当我从脚本中删除$mysqli->set_charset(utf8mb4);时,对我来说也将替换为。也许您会忽略set_charset语句?您可能还想阅读此页面mathiasbynens.be/notes/mysql-utf8mb4,了解如何在MySQL中支持完整的unicode。最后,您始终可以尝试使用PDO代替MySQLi(尽管不能保证可以解决您的问题)。解决问题后发布解决方案,以使他人受益。 :)
当然,我总是发布解决方案。我使用的是Manjaro(Arch Linux),服务器是centos5。我更喜欢使用mysqli,因为它不包含查询中的值,它们是单独发送的或类似的东西。
您是否做了一些特殊的mysql配置?我正在使用mysql 5.5.41。
如果我使用$mysqli->set_charset(utf8);运行脚本,则名称将按原样存储,并且将正常显示。
这是否意味着它现在对您有用?
是的,我不知道为什么,但它不接受utf8mb4 ...您也知道如何检查mysql是否从utf8(php)转换为utf8mb4?还是在$mysqli->set_charset()中设置的编码(utf8或utf8mb4)相同? MySQL必须做复杂的事情...
对不起,那也不起作用。我不接受您的回答,因为我和@RickJames找到了真正的问题。生病等待接受解决问题的答案。
utf8mb4 Alta?r is 41 6C 74 61 C383C2AF 72
哎哟。那就是"双重编码"。 latin1 EF已转换为utf8 / utf8mb4 C3AF;然后将被错误地视为latin1的C3转换为C383,将AF转换为C2AF。
这可能是发生了什么:
客户端的字符编码为utf8(良好);和
SET NAMES latin1谎称客户使用了latin1编码;和
表中的列声明为CHARACTER SET utf8(或utf8mb4)(良好)。
第二步应该已经由
$mysqli->set_charset('utf8mb4');
我假设您没有混合使用mysql_*和mysqli_*接口。仅使用后者。
如何发布一个简短的,可复制的测试用例。
是的,我很希望能够复制它,但是它可能在我的框架/应用程序本身中存在一些问题,并且我不知道从哪里开始...但是,当mysqli charset为utf8mb4时,我拥有的此类函数可以选择并显示所有内容,但我的应用程序其余部分显示?。当mysqli字符集只是utf8时,此功能不会显示?但典型的html编码问题,我将更新我的问题以添加此内容。
显示是棘手的。浏览器是宽容的。他们将尝试不同的方式来解释字节,并在某些情况下使乱码的文本看起来正确。如果无法成功,则会出现黑色菱形。
如果您存储了很多"双重编码"数据,请参见以下有关修复数据的信息:mysql.rjweb.org/doc.php/charcoll#fixing_double_encoding_但您还必须修复代码以免继续存储此类数据。
不,该应用程序仍在开发中,唯一重要的数据是城市等列表,但它们已正确插入(至少我认为它们很好)。如果我只能找到导致此问题的代码...您是否看到我的问题的最新更新?
您对C383C2AF的提及促使我谈论"双重编码"。 utf8和utf8mb4之间的差异仍然是个谜。"更新4"看起来很正常。在连接期间执行SET NAMES utf8mb4将更改其中的4个。
您提到的某些内容听起来像您INSERTed,其中SET NAMES和SELECTed的一种设置具有不同的设置。
那是不可能的,在初始化mysqli之后,我只在类db中调用一次$mysqli->set_charset(utf8mb4);。
我们俩都缺少一些东西。编写最小的测试用例就可以显示问题所在。
$mysqli->set_charset(utf8mb4);它??不起作用...您知道为什么不接受utf8mb4吗?
"不工作"表示给出错误消息?还是从printf("Current character set: %s
", mysqli_character_set_name($link));返回错误的值?或者是其他东西?
抱歉,"不起作用"表示它返回FALSE,并使用默认字符集latin1代替。 mysqli_character_set_name($mysqli)返回latin1(我假设是默认字符集)。
让我们尝试另一种方法。代替使用charset(),通过mysqli接口执行命令SET NAMES utf8mb4。由于那只是一个字符串,PHP不能拒绝它。
哦,你有假。但是什么错误信息?检查mysqlis错误消息例程。
运行此命令:SHOW CHARACTER SET WHERE Charset LIKE utf8%;您应该获得2行。如果没有,那是一个线索。
抱歉,我忘记了与检查查询错误相同的...我试图摆脱此问题已有两天了,我无法睡个好觉,所以我有点慢...这是错误,我的服务器中存在问题:Cant initialize character set utf8mb4 (path: usrsharemysqlcharsets)。所以这是一个mysql问题?
是的,我从运行该查询得到2行。
嗯...那条路是什么?我猜每个字符集一个文件。但是也许缺少utf8mb4吗?该路径不可读?执行ls -ld等进行检查。安装问题? utf8mb4带有5.5.3,因此您应该拥有它。最近有5.1版本的升级吗?还有其他线索吗?
我要我的朋友检查一下,他没有给我ssh访问权限。请告诉您问题出在哪里以及我的朋友如何解决该问题,并更新问题,以便有此问题的任何人都知道如何解决。
先生解决了! mysql安装/升级/配置错误,并且未正确安装utf8mb4。
该函数的问题在于它正在使用utf8_encode()重新编码db值,并以某种方式导致这些字符ó-> ?3。
您能否让我们详细了解您如何解决此问题。我遇到了同样的问题,现在拔头发了:(
抱歉,延迟,我正在享受我的假期:) MySQL(在我的情况下为MariaDB)缺少必需的文件,因此编码不存在。需要编译文件(我认为应使用必要的标志重新编译)或重新安装最新版本。这是在旧的cent os 5服务器上发生的,因此在较新的版本中不应发生这种情况,实际上我安装了cent os 6.7,并且检测到utf8mb4没有问题。