微信小程序的请求(wx.request)默认用 application/x-www-form-urlencoded,参数是键值对,里面的字符串会被 URL 编码。服务器端如果没有正确 urldecode() 或处理,字符串里的转义就被保留。
案例1:
string(615) “”[{\\”id\\”:3,\\”admin_id\\”:1,\\”project_id\\”:1,\\”name\\”:\\”浜у搧2\\”,\\”thumb\\”:\\”about_pic/241129/67493ec54ed05.png\\”,\\”product_type\\”:0,\\”stock\\”:999,\\”market_price\\”:\\”9600.00\\”,\\”title\\”:\\”浜у搧2\\”,\\”thumb_url\\”:\\”http://test.com/upfile/about_pic/241129/67493ec54ed05.png\\”,\\”tags\\”:[],\\”price\\”:\\”9600.00\\”,\\”quantity\\”:2,\\”totalprice\\”:\\”19200.00\\”}]””
问题:
-
外面多了一层/两层引号(
"" ... ""
),json 语法要求最外层直接是[
或{
或"
,不能是""[
。 -
内部双引号被反斜杠转义 成了
\"
,并且还可能因为多重处理变成\\"
,产生不合法的转义序列。 -
可能还包含 HTML 实体(
"
)或 URL 编码(%5B
)等。
这些都会让 json_decode()
报 Syntax error, malformed JSON
。
1、使用
/**
* 兼容性强的 JSON 还原解析(处理多层转义 / HTML 实体 / urlencode 等)
* 返回 array|object|null
*/
function robust_json_decode($raw) {
if ($raw === null) return null;
$original = $raw;
// 尝试次数
for ($i = 0; $i < 6; $i++) {
// 1. 去除首尾空白
$s = trim($raw);
// 2. HTML 实体还原(处理 " 等)
$s = html_entity_decode($s, ENT_QUOTES | ENT_HTML5, ‘UTF-8’);
// 3. 如果像 URL encoded(含 %5B/%7B),尝试 urldecode
if (strpos($s, ‘%5B’) !== false || strpos($s, ‘%7B’) !== false || strpos($s, ‘%22’) !== false) {
$s = urldecode($s);
}
// 4. 剥离前后非 JSON 有效字符,直到遇到 { [ 或 “
while ($s !== ” && !in_array($s[0], [‘{‘,'[‘,'”‘], true)) {
$s = substr($s, 1);
}
while ($s !== ” && !in_array(substr($s, -1), [‘}’,’]’,'”‘], true)) {
$s = substr($s, 0, -1);
}
// 5. 如果最外层被双引号包了(整个 JSON 又被当字符串包了一层),去掉外层一对引号
if (strlen($s) >= 2 && $s[0] === ‘”‘ && substr($s, -1) === ‘”‘) {
$s = substr($s, 1, -1);
}
// 6. 去反斜杠(模拟 stripslashes 的多次效果),并把 \” 换回 “
// 循环几次以处理 \\\” 等多重转义
$prev = null;
for ($k = 0; $k < 6; $k++) {
$prev = $s;
// 先把常见的 \\ -> \ 再把 \” -> “
$s = str_replace(‘\\\\’, ‘\\’, $s);
$s = str_replace(‘\\”‘, ‘”‘, $s);
$s = str_replace(“\\'”, “‘”, $s);
$s = html_entity_decode($s, ENT_QUOTES | ENT_HTML5, ‘UTF-8’); // 再次解实体
if ($s === $prev) break;
}
// 7. 再次去除外层的空白/控制字符
$s = trim($s, “\x00..\x1F”);
// 8. 尝试 json_decode
$decoded = json_decode($s, true);
if ($decoded !== null) {
return $decoded;
}
// 有时第一次 decode 后返回的是字符串(内层仍然是 JSON),
// 或者 decode 失败但我们可以对 s 做些轻微替换再尝试
// 准备下次循环的输入:把 \” 进一步替换成 “
$raw = str_replace(‘\\”‘, ‘”‘, $s);
}
// 解析失败,记录诊断(便于排查)
// $err = function_exists(‘json_last_error_msg’) ? json_last_error_msg() : json_last_error();
// p(“robust_json_decode_php failed. json_error={$err}. original_sample=” . substr((string)$original, 0, 200));
return null;
}