Why is json_decode($data, TRUE) converting an arra

2019-01-28 18:24发布

问题:

JavaScript Code:

$.ajax({
  type: "POST",
  url: "postTestingResult.php",
  data: {data: JSON.stringify(sendData)},
  dataType: "json",
  success: ajaxSuccess,
  error: ajaxError
});

PHP Code

$data = json_decode($_POST['data'], TRUE);

When I POST a complex data structure to the server, the outermost array is becoming a string. For example, the JavaScript object could be

var data = {"apps": [[1,2,3], [4,5,6]]}

Using JSON.stringify(data) this becomes

"{"apps": "[[1,2,3], [4,5,6]]"}" //As seen via console.log(data) in Chrome console

But after doing the json_decode($_POST['data'], TRUE) it becomes

array('apps' => '[[1,2,3], [4,5,6]]') //As seen via var_export($data, TRUE)

What's going on here? Why is the the array being converted to a string? To see the full JSON object and the full PHP object check out this pastebin with the two.

Any help is greatly appreciated, thank you.

UPDATE: Answer found I found the main culprit. I am also using Prototype.js and it was adding a toJSON method to the Object prototypes. Check out this SO question for details.

回答1:

Try this. Send your data explicitly as application/json and don't wrap your sendData:

var sendData = {'apps': [[1,2,3], [4,5,6]]};

$.ajax({
  type: 'POST',
  url: 'postTestingResult.php',
  data: JSON.stringify(sendData), // don't wrap your JSONified object 
  contentType: 'application/json' // set application/json - default is x-form-urlencoded
});

Note the headers and data: application/json:

Of course, as you highlighted, the data will not be available in the $_POST superglobal now. However this is not an issue, a very common way to get the JSON data string is to read the raw post data via php://input:

$data = array();
$json = file_get_contents('php://input'); // read JSON from raw POST data

if (!empty($json)) {
    $data = json_decode($json, true); // decode
}

print_r($data);

Yields:

Array( 
  [apps] => Array ( 
    [0] => Array ( 
      [0] => 1 
      [1] => 2 
      [2] => 3 ) 
    [1] => Array ( 
      [0] => 4 
      [1] => 5 
      [2] => 6 
   ) 
))

Hope this helps :)

EDIT

Note that the PHP documentation states:

Note: A stream opened with php://input can only be read once; the stream does not support seek operations.

However, iirc this has or will change (possibly in PHP 5.6?). Don't quote me on that though, and for now, don't forget to assign the contents of that stream if you plan to reuse it!