我正在开发一个使用 JavaScipt 通过 AJAX POST 将数据发送到 PHP 脚本的页面。问题是,如果输入的语言不是基于拉丁语的,我最终会在 MySQL 表中存储乱码。拉丁字母工作正常。
页面本身能够呈现 UTF-8 字符,如果它们在页面加载时提供的数据中,那就是我挣扎的帖子。
اختبار
并保存。请参阅浏览器开发工具中的网络 POST 请求。
帖子是通过以下JS函数制作的
function createEmptyStack(stackTitle) {
return $.ajax({
type:'POST',
url:'ajax.php',
data: {
"do": 'createEmptyStack',
newTitle: stackTitle
},
dataType: "json"
});
}
这是我的PHP代码。
header('Content-Type: text/html; charset=utf-8');
$newTitle = trim($_POST['newTitle']);
$db->query("
INSERT INTO t1(project_id, label)
VALUES (".$_SESSION['project_id'].", '".$newTitle."')");
当我像这样检查页面上的编码时:
mb_detect_encoding($_POST['newTitle'], "auto");
我得到的结果:UTF-8
我还尝试了以下标题:
header("Content-type: application/json; charset=utf-8");
数据应该去的MySQL表排序规则设置为utf8_general_ci
我有另一个页面,它有一个表单,用户可以在其中填充同一个表格,并且它与任何语言都可以正常工作。当我在另一页上检查为什么它能够成功地将类似的数据插入数据库时,我看到以下上面的插入查询:
mysql_query("SET NAMES utf8");
我尝试在我的查询上方放置同一行,数据看起来仍然乱码。我还尝试了以下几种选择:
mysql_query("SET CHARACTER SET utf8 ");
和
mysql_set_charset('utf8', $db);
。但无济于事。我被跺了跺脚。需要帮助弄清楚。
环境:
<小时 />PHP 5.6.40 (cgi-fcgi)
MySQL 5.6.45
更新
我进行了更多的测试。
我在阿拉伯语中使用了一个短语"这是一个测试" - هذا اختبار
似乎 ajax.php 代码工作正常。db 插入后,它返回 UTF-8 编码值,如下所示:"\u0647\u0630\u0627 \u0627\u062e\u062a\u0628\u0627\u0631",编码设置为:"UTF-8",但是我的数据库表中插入的数据显示为:هذا Ø§Ø ØªØ®̈ار
那么为什么我不跳到将我的数据库表转换为不同的排序规则呢?几个原因:它有近 .5 密耳的记录,当我转到另一个执行非常相似的 INSERT 的页面时,它实际上可以正常工作。
事实证明,我的另一个页面在插入数据时使用ASCII编码。因此,我尝试在ajax.php上转换为ASCII是很自然的。问题我最终得到空白数据。我现在很困惑...
谢谢
>FIXED:根据一些线索,我最终将此页面的所有功能重写为 PDO,它奏效了!المراكز
是Mojibake,或者可能是"双重编码",用于المراكز - 请做SELECT col, hex(col) ...
看看这些看起来像:
莫吉巴克:D8A7D984D985D8B1D8A7D983D8B2
双重编码:C398C2A7C399E2809EC399E280A6C398C2B1C398C2A7C399C692C398C2B2
如果莫吉巴克:
- 要存储的字节需要采用 UTF-8 编码。修复此问题。
- 插入和选择文本时的连接需要指定 utf8 或 utf8mb4。修复此问题。
- 该列需要声明为字符集 utf8(或 utf8mb4)。修复此问题。
- HTML 应以
<meta charset=UTF-8>
开头。
如果是双重编码:这是由于从 latin1(或其他)转换为 utf8,然后将这些字节视为拉丁 1 并重复转换引起的。
更多讨论:
UTF-8 字符出现问题;我看到的不是我存储的
不要在 PHP 中使用mysql_*
接口;切换到mysqli_*
或 PDO 接口。mysql_*
在 PHP 5.7 中删除。
如果你的数据库是 latin1,它会将 unicode 字符存储为多字节字符。如果它是基于 utf-8 的,它仍将存储多个字符,但以更"明智"的方式显示。
如果您的ر字符表示为XYZ(3个字节),那么当您检索XYZ时,浏览器会将它们重新组合成可见的ر。
但是,如果您的数据库是 utf-8,它将进一步对每个组件进行编码,以便您最终"可靠地"看到 XYZ。假设 X 表示为 x1,x2,Y 只是 y,Z 是 z1,z2,z3,所以你现在看到的不是存储为 XYZ 的 ر,而是 x1x2yz1z2z3,它显示为 XYZ。
尝试将您的数据库转换为 latin1 以至少证实我的理论。谢谢。
编辑:
没有必要使用 utf8 js 库。确保页面的字符编码为 utf8:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
当您发布数据时,您可以在使用 XHR 请求发送之前使用 encodeURIComponent 对其进行编码。我不确定 $.ajax 的 jQuery 风格是否已经进行了编码。
这是我用来让你的代码工作的方法:
<?php
$db = mysqli_connect("localhost", "root", "", "demo");
$db->set_charset("utf8");
// Check connection
if ($db === false) {
die("ERROR: Could not connect. " . mysqli_connect_error());
}
$newTitle = trim($_POST['newTitle']);
$db->query("
INSERT INTO t1(project_id, label)
VALUES ('5', '" . $newTitle . "')");
将此标签添加到您的 HTML 标题中:
<meta charset="utf-8">
我用latin1_bin
和utf8_bin
进行了测试,它在两种情况下都有效。
PHP 版本 7.3.9
MySQLi 5.0.12-dev
大约一年前,我在运行MySQL 5.7的系统中遇到了一个非常相似的问题。在我看来,您的某些数据库设置应该设置为 utf8mb4 时,它们被设置为 utf8mb4。这允许数据库正确处理多字节字符。
注意:utf8mb4 编码在版本 5.5 中添加到 MySQL 中。
以下查询可用于更改编码。请确保更改数据库、表和列名称以及列数据类型以适合您的情况:
# For each database:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
# For each table:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# For each column:
ALTER TABLE table_name CHANGE column_name column_name DATATYPE CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
可以在此处找到对此的进一步解释。
MySQL 版本 (5.6) 上的文档
当前的 MySQL 8 文档
utf8 主题有点复杂。
在 MySql 中使用 UTF8 时,重要的是要了解 MySql 的 UTF8 仅支持 3 字节的数据,即使标准规范允许最多 4 字节。在 unicode 中,你有很多字符实际上使用了第 4 个字节,例如像这样的表情符号:💩. 使用utf8mb4,您实际上可以完全支持并将它们保存在数据库中,而不会出现问题。不过,仅 UTF8 就会让您失望。
只要遵循这些规则,你应该没问题:
- 确保所有源文件都采用 UTF8 编码。
确保在php.ini中将 utf8 作为默认字符集:
default_charset = "utf-8"
确保在 html 的标头中使用 utf-8 字符集:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
确保将标头字符集设置为 UTF8:
header("Content-type: application/json; charset=utf-8");
确保在PDO中为MySQL连接设置utf8mb4:
$dsn='mysql:host=example.com;dbname=testdb;port=3306;charset=utf8mb4';
如果必须,请确保在utf8mb4中创建数据库或转换数据库:
CREATE DATABASE mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
确保在utf8mb4中创建表,或者如果必须转换它们:
CREATE TABLE my_table ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
非常重要:确保在 PHP 中使用mb_字符串函数,因为普通字符串函数只会假定单字节数据。这意味着您应该使用
mb_strlen
而不是使用strlen
来计算每个字节。此外,简单的错误,如将字符串作为数组访问会破坏你的代码,因为$string[0]只会访问字符串的第一个字节,即使你的第一个字符可能有 4。在这种情况下使用mb_substr
!
对于最后一个,您将需要 php 的 mbstring 扩展名。另外,请注意,某些扩展需要首先加载 mbstring,因此加载扩展的顺序可能很重要,以防您需要安装它。
另外作为旁注:请使用PDO和准备好的语句。您会在网上找到很多很多教程。SQL注入仍然是Web上最大的漏洞,预处理语句是最有效的 防止SQL注入的方法!
如果您按照那里的列表进行操作,您将不再遇到问题。
玩得愉快。
一些参考: https://mathiasbynens.be/notes/mysql-utf8mb4