包含非ASCII字符的字符串被PHP / MySQL截断

时间:2012-09-27 06:34:16

标签: php html mysql utf-8 character-encoding

我有一个翻译函数here的页面。我的问题在于,当我将语言翻译成法语时,单词会被删除,因为页面没有正确解释单词。我检查了与我的问题相关的帖子,但没有一个工作。

在我的页面中,我提出了这些内容:

  • header ('Content-Type:text/html; charset=WINDOWS-1252'); - >这只是为了坚持编码启动。我认为这个是可选的,但我仍然使用它。
  • <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
  • 从数据库表名中提取等效翻译:标签标签的表格类型是InnoDB,其中 utf8 - UTF-8 Unicode 作为默认字符集。

正在削减é之后的字符。我需要做些什么来正确显示字符吗?谢谢!

3 个答案:

答案 0 :(得分:2)

我认为在后端使用Unicode和在多语言应用程序的前端使用代码页没有任何意义。您可以在整个项目中使用相同的编码,也可以在UTF-8windows-1252之间来回手动转换。

我不认为你的阅读有问题。标签从数据库中截断,否则您的浏览器将显示乱码。所以这不是PHP / HTML的问题,而是MySQL。在èéàòì之类的情况下,MySQL肯定能够从UTF-8转换为CP1252(latin1)。但是,如果不是这种情况(就好像我们尝试将相同的字符串从UTF-8转换为CP1251),MySQL会显示问号?

在您的情况下,我认为这是一个输入问题,即标签在数据库中被截断。这怎么可能?您可能有一个UTF8 PHP和MySQL,但是当您的浏览器从加载了这样一个字符集的页面提交表单时,它会发送windows-1252个字符串。在PHP脚本中,您应该将此字符串转码为UTF-8 ,然后将其插入数据库,或使用SET NAMES 'CP1252'连接到MySQL。由于您没有这样做,最终会尝试插入一堆无效的UTF-8字节,因此MySQL会截断字符串并且您的标签为空。附件是一个测试用例。这是test

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

这是PHP部分。请注意,此脚本是UTF-8编码的,因此出现在其中的每个文字字符串都具有相同的编码。

// This is a UTF-8 file, so my editor uses UTF-8 and thus each literal
// string is a UTF-8 string, since PHP only has binary strings.
$label = "Référence";

// Now let's translate this string as if it came from a browser submitting
// a form loaded from a cp1252 encoded page
$src = mb_convert_encoding($label, "CP1252", "UTF-8");

// But connect as if I were UTF-8
$db = new PDO('mysql:host=localhost;dbname=test;charset=utf8',
    'test', 'test');

// Insert the string
$stmt = $db->prepare('INSERT INTO test (name) VALUES ( ? )');
$stmt->bindValue(1, $src);
$stmt->execute();

// Read it
header("content-type: text/plain; charset=windows-1252");
foreach($db->query('SELECT * FROM test') as $row)
    echo $row['name'] . "\n";

你如何恢复?您可以使用cp1252字符集连接到MySQL并让MySQL为您翻译,或者您在脚本中对字符串进行转码。

在正确获取数据后,您必须提取它们并将其放在HTML页面上。这次你会遇到同样的问题,但是反过来了:在CP1252文档中显示一个UTF-8字符串。 DB中的字节不合适,因为UTF-8是可变长度编码,而在CP1252中,char正好是1个字节长。如果您将这些字节直接放入页面,浏览器将显示一些随机的乱码,用于额外的字节。所以,再次,您要么连接到指定CP1252字符集的数据库,以便MySQL负责转换并为您提供正确的字节,或者您自己在PHP端转码字节。

或者你最好帮个忙:在任何地方使用相同的编码。我建议UTF-8,因为今天是正确的事情,但你可以成功选择CP1252因为它可以代表英语和法语字符(并节省一些存储空间,但我不要认为这是一个问题)

答案 1 :(得分:1)

我的建议是在整个过程中使用相同的编码。在标头和元标记中使用UTF-8作为字符集。

答案 2 :(得分:0)

在我看来,您的数据未正确存储在数据库中。如果您正在使用mysqli,您可以在读取或写入数据库之前尝试设置连接对象的字符集。

// tells the mysqli connection to deliver UTF-8 encoded strings.
$db = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);
$db->set_charset('utf8');

对于其他数据库,请参阅UTF-8 for PHP and MySQL。也许有必要再次插入法语文本(使用此设置),因为现有的文本现在可能无效。

您的链接示例页面使用UTF-8(文件格式)正确编码,但您的元标记有点不正确:

<!meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<!未被注释掉,您必须改为编写<!--。最好的方法是只为UTF-8声明一次并删除其他元标记。