【问题标题】:Unescaping a string meant to be JSON nested in JSON in PHP在 PHP 中取消转义一个嵌套在 JSON 中的 JSON 字符串
【发布时间】:2021-02-07 13:51:06
【问题描述】:

我的服务器从真实设备接收 JSON 数据,然后将其保存在 MySQL JSON 字段中。不幸的是,制造商似乎在他们的代码中有一个错误,导致部分数据被字符串化转义 JSON。

[
  "foo",
  "bar",
  "info",
  {
    "data": "{\"parts\":[{\"id\":1,\"serial\":\"19777\",\"type\":\"NONE\",\"key\":\"\"}]}",
    "vendor": "Test",
    "message": "Hello world"
  }
]

即使使用JSON_UNESCAPED_SLASHES 运行json_decode 也会产生一个字符串

Array
(
    [0] => foo
    [1] => bar
    [2] => info
    [3] => Array
        (
            [data] => {"parts":[{"id":1,"serial":"19777","type":"NONE","key":""}]}
            [vendor] => Test
            [message] => Hello world
        )

)

但预期的输出是

Array
(
    [0] => foo
    [1] => bar
    [2] => info
    [3] => Array
        (
            [data] => Array
                (
                    [parts] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 1
                                    [serial] => 19777
                                    [type] => NONE
                                    [key] => 
                                )

                        )

                )

            [vendor] => Test
            [message] => Hellow world
        )

)

由于我不能指望他们很快发布固件更新,我是否可以在整个 JSON 上运行任何函数来识别字符串化 JSON 并在保存到 MySQL 之前重新编码请求,但不会影响其他消息没有类似的bug?

【问题讨论】:

    标签: php json backslash


    【解决方案1】:

    更新:将$json 内的任何嵌套 json 数据转换为关联数组:

    使用函数recurse()通过数组$arr递归,找到任何带有json数据和json_decode()的元素,以达到您的预期输出:

    <?php
    $arr = json_decode($json, true);
    recurse($arr); // json_decode() any json inside $arr
    
    function recurse(array &$arr)
    {
        foreach ($arr as $key => &$value) {
            if (is_array($value)) {
                recurse($value);
            } else {
                if (is_object(json_decode($value))) {
                    $value = json_decode($value, true); // turn json into assoc array
                }
            }
        }
    }
    

    工作demo

    【讨论】:

    • 这个问题是不是每条记录都有data 字段。我可以检查isset,但我还需要确定字符串是否包含\"
    【解决方案2】:

    如果主要关注的是“数据”字段,这应该可以工作。

    $json = '[
      "foo",
      "bar",
      "info",
      {
        "data": "{\"parts\":[{\"id\":1,\"serial\":\"19777\",\"type\":\"NONE\",\"key\":\"\"}]}",
        "vendor": "Test",
        "message": "Hello world"
      },
      {
        "data": {"parts":[{"id":1,"serial":"19777","type":"NONE","key":""}]},
        "vendor": "Test",
        "message": "Hello world"
      }
      ]';
    
    $arr = json_decode($json, true);
    $out = array();
    foreach($arr as $a)
    {
        if(is_array($a))
        {
            if(!is_array($a['data']))
            {
                $a['data'] = json_decode($a['data'], true);
            }
        }
        $out [] = $a;
    }
    
    print_r($out);
    

    【讨论】:

      【解决方案3】:

      快速解决方案:

      $full_array = array_map('json_decode', $array);
      

      如果不是所有参数都是 JSON,并且您想要实际的数组而不是 stdClass 对象,您可能必须这样做:

      function json_decode_array($input) { 
        $from_json =  json_decode($input, true);  
        return $from_json ? $from_json : $input; 
      }
      $full_array = array_map('json_decode_array', $array);
      

      主要答案:https://stackoverflow.com/a/10458008/3398171

      谷歌:php json_decode 递归

      【讨论】:

        猜你喜欢
        • 2019-08-30
        • 2020-06-11
        • 1970-01-01
        • 1970-01-01
        • 2016-03-02
        • 1970-01-01
        • 1970-01-01
        • 2020-02-16
        • 2016-04-19
        相关资源
        最近更新 更多