解决json_encode因未知字符失败的问题——USSD响应文本乱码导致JSON序列化失败
解决USSD响应乱码导致json_encode失败的问题
这个问题我之前处理过不少——本质就是USSD响应的编码和PHP默认的UTF-8不兼容导致的乱码,进而卡壳了json_encode。咱们一步步来解决:
核心原因
USSD协议的文本通常采用GSM 03.38编码(俗称GSM字符集),而PHP默认的字符串处理是基于UTF-8的。当你直接读取USSD响应时,那些GSM特有的字符(比如特殊问号、控制字符)会被解析成无效的UTF-8字节,也就是你看到的��乱码,而json_encode对非UTF-8的字符串会直接编码失败。
具体解决步骤
1. 把GSM编码字符串转成UTF-8
这是最关键的一步,你可以用PHP的mb_convert_encoding或者iconv函数来完成转换:
方法一:用mb_convert_encoding
// 从数组中取出乱码的text字段 $rawText = $responses[0]['text']; // 从GSM 03.38转成UTF-8 $utf8Text = mb_convert_encoding($rawText, 'UTF-8', 'GSM-03.38');
如果你的PHP环境不识别GSM-03.38这个编码名,试试简写GSM。
方法二:用iconv(带错误忽略)
如果mb_convert_encoding转换失败,可以用iconv并加上//IGNORE参数,忽略无法转换的无效字符:
$utf8Text = iconv('GSM-03.38', 'UTF-8//IGNORE', $rawText);
2. 清理残留的无效字符
转换后可能还会残留一些USSD里的控制字符、多余符号(比如你看到的%),可以用正则过滤掉非打印的UTF-8字符,只保留正常的文本内容:
// 保留字母、数字、标点、空格,去掉其他无效字符 $cleanText = preg_replace('/[^\p{L}\p{N}\p{P}\p{Z}]/u', '', $utf8Text);
如果你需要保留Yes 2 No, CANCEL, SEND这些选项内容,这个正则不会影响它们。
3. 验证并执行json_encode
最后确认转换后的字符串是有效的UTF-8,再执行编码:
if (mb_check_encoding($cleanText, 'UTF-8')) { $result = json_encode(['responses' => [['date' => $responses[0]['date'], 'text' => $cleanText]]]); // 现在应该能正常生成JSON了 } else { // 处理极端情况:修复无效的UTF-8字节 $cleanText = mb_convert_encoding($cleanText, 'UTF-8', 'UTF-8'); $result = json_encode(['responses' => [['date' => $responses[0]['date'], 'text' => $cleanText]]]); }
额外提示
如果尝试GSM编码转换后还是有问题,可能你的USSD响应采用了其他编码(比如ISO-8859-1),可以用mb_detect_encoding尝试检测原编码,但注意这个函数的准确性有限,优先还是用GSM 03.38测试。
内容的提问来源于stack exchange,提问作者Alaa Morad
相关产品推荐
相关产品推荐

