您的代码中的某些内容没有将字符串作为 UTF8 处理。它可能是您的 PHP/HTML,可能是您与 DB 的连接,也可能是 DB 本身 - 必须始终将所有内容设置为 UTF8,如果不是,则字符串将完全按照您的方式截断查看何时通过 UTF8/非 UTF8 边界。
我会假设你的数据库是 UTF8 兼容的——这是最容易检查的。请注意,排序规则可以设置在服务器级别、数据库级别、表级别和表内的列级别。在列上设置 UTF8 排序规则应该覆盖任何其他用于存储的内容,但如果它们不是 UTF8,则在与数据库交谈时其他内容仍会启动。如果您不确定,请在打开连接后将连接显式设置为 UTF8:
$dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
现在您的数据库和连接是 UTF8,请确保您的网页也是如此。同样,这可以设置在多个位置(.htaccess、php.ini)。如果您不确定/没有访问权限,只需覆盖页面顶部默认选择的 PHP:
<?php ini_set('default_charset', 'UTF-8'); ?>
请注意,在从页面输出任何文本之前,您希望在开始时使用上述内容。一旦文本得到输出,尝试指定编码可能为时已晚 - 您可能已经被锁定在服务器上的默认值中。然后我也在我的标题中重复这一点(可能有点矫枉过正):
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
</head>
我在我正在获取数据的表单上覆盖它:
<FORM NAME="utf8-test" METHOD="POST" ACTION="utf8-test.php" enctype="multipart/form-data" accept-charset="UTF-8">"
老实说,如果您将编码设置在顶部,我的理解是不需要其他覆盖 - 但我仍然保留它们,因为它也不会破坏任何东西,我宁愿只说明显式编码,而不是让服务器做出假设。
最后,您提到在 phpMyAdmin 中插入了字符串,它看起来与预期一样 - 您确定 phpMyAdmin 页面是 UTF8 吗?我不认为他们是。当我从我的 PHP 代码中存储 UTF8 数据时,它会在 phpMyAdmin 中查看原始 8 位字符。如果我采用相同的字符串并将其直接存储在 phpMyAdmin 中,它看起来“正确”。所以我猜 phpMyAdmin 使用的是我本地服务器的默认字符集,不一定是 UTF8。
例如,从我的网页存储的以下字符串:
I can¹t wait
在我的 phpMyAdmin 中是这样的:
I can’t wait
因此,以这种方式进行测试时要小心,因为您并不真正知道 phpMyAdmin 用于显示或数据库连接的编码。
如果您仍然遇到问题,请尝试下面的代码。首先,我创建一个表以 UTF8 存储文本:
CREATE TABLE IF NOT EXISTS `utf8_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`my_text` varchar(8000) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
这里有一些 PHP 来测试它。它基本上将您的输入输入到表单中,将输入的内容回显给您,并从数据库中存储/检索文本。就像我说的,如果您直接在 phpMyAdmin 中查看数据,您可能会发现它看起来不正确,但是通过下面的页面,它应该总是按预期显示,因为页面和数据库连接都被锁定为 UTF8。
<?php
// Override whatever is set in php.ini
ini_set('default_charset', 'UTF-8');
// The following should not be required with the above override
//header('Content-Type:text/html; charset=UTF-8');
// Open the database
$dbh = new PDO('mysql:dbname=utf8db;host=127.0.0.1;charset=utf8', 'root', 'password');
// Set the connection to UTF8
$dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
// Tell MySql to do the parameter replacement, not PDO
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// Throw exceptions (and break the code) if a query is bad
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$id = 0;
if (isset($_POST["StoreText"]))
{
$stmt = $dbh->prepare('INSERT INTO utf8_test (my_text) VALUES (:my_text)');
$stmt->execute(array(':my_text' => $_POST['my_text']));
$id = $dbh->lastInsertId();
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
<title>UTF-8 Test</title>
</head>
<body>
<?php
// If something was posted, output it
if (isset($_POST['my_text']))
{
echo "POSTED<br>\n";
echo $_POST['my_text'] . "<br>\n";
}
// If something was written to the database, read it back, and output it
if ($id > 0)
{
$stmt = $dbh->prepare('SELECT my_text FROM utf8_test WHERE id = :id');
$stmt->execute(array(':id' => $id));
if ($result = $stmt->fetch())
{
echo "STORED<br>\n";
echo $result['my_text'] . "<br>\n";
}
}
// Create a form to take some user input
echo "<FORM NAME=\"utf8-test\" METHOD=\"POST\" ACTION=\"utf8-test.php\" enctype=\"multipart/form-data\" accept-charset=\"UTF-8\">";
echo "<br>";
echo "<textarea name=\"my_text\" rows=\"20\" cols=\"90\">";
// If something was posted, include it on the form
if (isset($_POST['my_text']))
{
echo $_POST['my_text'];
}
echo "</textarea>";
echo "<br>";
echo "<INPUT TYPE = \"Submit\" Name = \"StoreText\" VALUE=\"Store It\" />";
echo "</FORM>";
?>
<br>
</body>
</html>