iPad端Safari提交阿拉伯语词汇时出现字符不一致问题
1. 后端SQL语句未执行的低级错误
你当前的后端代码里,$correctAnswer = 'SELECT answer FROM answers WHERE correct = 1';只是定义了SQL字符串,根本没有执行查询操作,直接拿字符串和用户提交的答案对比,肯定不相等。正确的做法是执行这条SQL并获取数据库中的正确答案:
$answer = $_POST['answer']; // 执行SQL查询获取正确答案 $stmt = $conn->prepare("SELECT answer FROM answers WHERE correct = 1"); $stmt->execute(); $correctAnswer = $stmt->fetchColumn(); if ($correctAnswer == $answer) { echo 'equal'; }else{ echo 'not equal'; }
2. Unicode字符归一化问题
即使修正了SQL问题,阿拉伯文的变音符号(比如تَشكيل)可能存在不同的Unicode编码表示形式:一种是预组合字符(单个Unicode码点),另一种是基础字符加组合变音符号(多个码点)。视觉上完全一样,但底层编码不同,直接用==对比会失败。
比如اللَّيلِ中的لَّ,可能是单个预组合码点,也可能是ل + ّ(Shadda)两个码点组成。这时候需要对两个字符串做Unicode归一化,统一成相同形式后再对比:
// 归一化为NFC(标准等价组合形式)或NFD(标准等价分解形式) $normalizedUserAnswer = Normalizer::normalize($answer, Normalizer::FORM_C); $normalizedCorrectAnswer = Normalizer::normalize($correctAnswer, Normalizer::FORM_C); if ($normalizedUserAnswer == $normalizedCorrectAnswer) { echo 'equal'; }else{ echo 'not equal'; }
注意:需要确保PHP安装了intl扩展才能使用Normalizer类。
3. AJAX提交时未做URL编码
你的AJAX代码中直接拼接'answer=' + userAnswer,没有对阿拉伯文进行URL编码,Safari在处理非ASCII字符的编码时可能和其他浏览器不一致,导致后端接收到的字符串被损坏。应该使用encodeURIComponent()对用户答案编码:
const request = new XMLHttpRequest(); request.open('POST', 'submit.php', true); request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); request.responseType = 'json'; // 对用户答案进行URL编码 var data = 'answer=' + encodeURIComponent(userAnswer); request.send(data);
4. 数据库字段的排序规则设置
确保数据库中answer字段的排序规则是utf8mb4_unicode_ci(或utf8_unicode_ci),而不是utf8_general_ci。unicode_ci排序规则会考虑Unicode字符的等价性,能正确处理阿拉伯文的变音符号对比,而general_ci只是简单的字节对比,容易出现不一致。
同时,数据库连接建议使用utf8mb4而非utf8,因为MySQL的utf8实际上是utf8mb3,不支持某些Unicode字符:
$conn = new PDO("mysql:host=$servername;dbname=$db;charset=utf8mb4", $username, $password); // 不需要额外的SET NAMES,charset参数已经处理
内容的提问来源于stack exchange,提问作者mmdev

