The question
I have a JSON string which I would like to decode. However, I only want the first level to be decoded, the rest of the JSON should stay as string values instead of nested arrays.
Using a similar technique, the generated array (with nested string values) should be parsed back to a JSON string. When using these decode and encode in succession the result should be the original JSON string.
Short and simple, right?
I would also rather not interpret the nested values of the JSON, as those may or may not be valid JSON. If there is no way around this, then so be it.
Example
Please note that all these slashes are just to keep it a valid PHP string, they are not part of the input. There are no escaped quotes in the input.
When a JSON string like this is put in:
"{
\"foo\": \"bar\",
\"nested\": {
\"nested_key\": \"nested_value\"
},
\"another_top_level_key\": \"some_useful_value\"
}"
This should be the output:
[
"foo" => "bar",
"nested" => "{ \"nested_key\": \"nested_value\" }",
"another_top_level_key" => "some_useful_value"
]
When using var_dump, it should look like this:
array(3) {
["foo"]=>
string(3) "bar"
["nested"]=>
string(32) "{ "nested_key": "nested_value" }"
["another_top_level_key"]=>
string(17) "some_useful_value"
}
Pay attention to the fact that when using var_dump, the quotes are not escaped and thus no slashes exist in the string (the nested quotes are not escaped).
When that array is run through the second function (the encoder), the original JSON string should be returned.
Things I've tried:
I tried setting the $depth of json_decode() to 1. This, however, only throws exceptions when the limit has been reached.
I tried decoding the whole string using json_decode() and then looping over the top-level key-value pairs to run json_encode() over any value that is an array (which should indicate a nested value). The end result was fine at first, but when converting back to a JSON string it escaped the double quotes with slashes. In that case, the end result isn't the same as the original, as the end result includes slashes.
Notes
Even though this question has a very similar title to this one, that one doesn't actually contain answers for its title. There is only an answer on how to transform the invalid JSON string to a valid JSON.
I'd rather not use any RegEx, as that just makes my life more complex than it needs to be ;). But if it can't be avoided, then that's life I guess.
As requested by deceze:
$jsonString = "{ \"foo\": \"bar\", \"nested\": { \"nested_key\": \"nested_value\" }, \"another_top_level_key\": \"some_useful_value\" }";
$decoded = json_decode($jsonString, true);
foreach ($decoded as $key => $value) {
if (is_array($value)) {
$decoded[$key] = json_encode($value);
}
}
$encoded = json_encode($decoded);
var_dump($encoded);
The result is this:
string(102) "{"foo":"bar","nested":"{\"nested_key\":\"nested_value\"}","another_top_level_key":"some_useful_value"}"
Which means that in the end, it did escape the quotes, which is something I cannot accept :(.
Use a function to check when you have an element as array then convert back to json:
<?php
$json = "{
\"foo\": \"bar\",
\"nested\": {
\"nested_key\": \"nested_value\"
},
\"multinested\": {
\"multinested_key\": {
\"multinested_key\": \"nested_value\"
}
},
\"another_top_level_key\": \"some_useful_value\"
}";
$array = json_decode($json, true);
foreach($array as &$item) {
if (is_array($item)) {
$item = json_encode($item);
}
}
print_r($array);
Output:
Array
(
[foo] => bar
[nested] => {"nested_key":"nested_value"}
[multinested] => {"multinested_key":{"multinested_key":"nested_value"}}
[another_top_level_key] => some_useful_value
)
The trick is to use the decode twice:
$array = json_decode(json_decode($json, true), true);
print_r($array);
Related
I have a problem when returning a row from database that has a column type TEXT(in this case, column "details") which contains an array of JSON objects. Example:
{
productid: 1
shopid: 1
title: 'Product 1'
--> details: [{"name":"Brand name","value":"Brand value"},{"name":"Color","value":"blue"}]
. . .
}
Data inserted into database in columns of type TEXT are inserted like addslashes(json_encode($array_or_object)) to safely escape before insert.
When returning data, columns of type TEXT by function json_decode() and returned with no problem. Problem occurs when someone tries using single ' and double quotes " in details. Example:
details: [{"name":"\\\"test123\\\"","value":"\\\"test\\\" \\'test\\' \\\"test \\' test \\' t\\\"est"}]
Returned value looks like:
"details": [
{
"name": "\\\"test123\\\"",
"value": "\\\"test\\\" \\'test\\' \\\"test \\' test \\' t\\\"est"
}
],
I have more than one way of storing JSON data in database (as object, array of objects, array of arrays of objects,...), and I need a way to escape these backslashes.
Using stripslashes() on the string before using json_decode() does not work, it breaks the JSON.
Creating a recursive function works, but is not as pretty as I would like it to be. Example:
function decode_json($json) {
if (empty($json)) {
return $json;
}
if (is_string($json)) {
$json = json_decode($json, true);
}
foreach ($json as $key => $value) {
if (is_array($value)) {
$json[$key] = decode_json($value);
continue;
}
$json[$key] = stripslashes($value);
}
return $json;
}
Any help is appreciated.
json_encode already escape your string, you don't need to use addslashes()
Example:
$var = ["value" => "test'\""];
print_r(json_encode($var));
Result:
{"value":"test'\""}
And will be better to use PDO with bind parameters: https://www.php.net/manual/en/pdostatement.bindparam.php
and what exactly is the point of using a database, when storing the raw JSON?
decode first, then escape the values to insert - else you'll also escape all of the JSON delimiters,
which might subsequently cripple the whole input string and render it F.U.B.A.R.
PS: PDOStatement still requires PDO::quote() to escape the input properly.
I have below json data and decode it to display on the screen. When I check the type of the value, it shows array instead of object. How to get actual type of value in PHP.
JSON is
{ "allData" : { "image" : [], "contents": {.., "box": {}, "text":[]} } }
When I decode and parse the above JSON data the "allData", "contents", "box" type are shows as array instead of object. How can I get those type as object and "image" type as array. Please help.
Thanks,
Guru
This normally occurs when you are using the true option in the json_decode function.
For eg.,
$str = '{"allData":{"image":["img1.png"],"contents":{"title":"title name","box":{"name":["sample text 1","sample text2"]},"text":[]}}}';
var_dump(json_decode($str, true));
Just try to remove the true in the json_decode function and you should get an object.
Hope this helps.
If you use json_decode with the true option, it will return the result as an array.
Maybe you can check this link.
If you get "Cannot use object of type stdClass as array" the error, you can look at this answer.
<?php
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
var_dump(json_decode($json));
var_dump(json_decode($json, true));
?>
Extract from the RFC 7159 (JSON) :
These are the six structural characters:
begin-array = ws %x5B ws ; [ left square bracket
begin-object = ws %x7B ws ; { left curly bracket
end-array = ws %x5D ws ; ] right square bracket
end-object = ws %x7D ws ; } right curly bracket
..
However: php allows you to treat the result as an array (of arrays)
so:
json_decode($json, true); // return as array
returns the result as an array.
and
json_decode($json)
gives you the result as Objects AND arrays . So given your example:
"allData" : { "image" : [], ..
returns a stdClass-Object with the field "image" of type array. The array is empty for your example.
So to retrieve all images, use something like:
$result=json_decode($json);
foreach($result->allData->image as $img) {
echo "found image: $img.";
}
I have a json string derived from MySQL query using GROUP_CONCAT (which returns STRING).
Here's JSON string as field portfolios:
[
{name:"Branch GBD_1.pdf", img_path:"1333752771.pdf"},
{name:"Doc.pdf", img_path:"2020107119.pdf"},
{name:"COK.pdf", img_path:"264860069.pdf"}
]
Now in php, I tried to decode the field and loop through it, but I am not being able to.
foreach($records as $r)
{
$varArray = json_decode($r['portfolios'], true);
foreach($varArray as $que)
{
echo $que['name'].' '.$que['img_path'];
echo '<br/>';
}
}
How do I break or convert the variable into loop-able object?
$varArray is not an array because your json string is not valid json. The keys need to be wrapped in doublequotes.
[
{"name":"Branch GBD_1.pdf", "img_path":"1333752771.pdf"},
{"name":"Doc.pdf", "img_path":"2020107119.pdf"},
{"name":"COK.pdf", "img_path":"264860069.pdf"}
]
I tried this code
$jsonlogcontents='{"buildings":"townhall","Army":{ "Paladins":{ "325648":0, "546545":4 }, "Knights":{ "325648":-2, "546545":0 } } }';
$phpArray = json_decode($jsonlogcontents, false);
echo $phpArray->buildings;
echo $phpArray->Army;
This is just a sample of my code, the JSON file is too large to include and has sensitive information. The problem I'm having is I can't get the value or print the value of
$phpArray->Army
It give's me an error. I can however print or get the value of
$phpArray->buildings
I'm thinking that when you decode a JSON file/contents in PHP, you can't get/print/store the value of a 'key' that has more set of info (more { and }) or brackets in it. You can only print/get values for keys who's value's contain only 1 value and nothing else.
If this is the case, what can I do to get the contents of the key that has more JSON codes in it. Also, how can I convert the contents of a key that has more JSON info in it into a string? the conversion is so I can display the value of that key to the page or echo it
The error is because Army is an object, and echo doesn't know how to convert it to a string for display. Use:
print_r($phpArray->Army);
or:
var_dump($phpArray->Army);
to see its contents.
P.S. $phpArray not an array but an object.
For Army however, I will need to do another json_decode() for that.
You don't. json_decode() decodes the entire structure in one call, into one large object (or array). No matter how deeply nested the data is, you call json_decode() once and you're done. That's why Army is not a JSON string any more.
When you are adding false as the second parameter to the json_encode it will updating all array to the sdClass empty objects.In this way you can the main array as the object
<?php
$json = '{
"buildings": "townhall",
"Army": {
"Paladins": {
"325648": 0,
"546545": 4
},
"Knights": {
"325648": -2,
"546545": 0
}
}
}';
$array = json_decode($json, true);
$object = (object)$array;
var_dump($object->Army);
?>
OUTPUT
array(2) {
["Paladins"]=>
array(2) {
[325648]=>
int(0)
[546545]=>
int(4)
}
["Knights"]=>
array(2) {
[325648]=>
int(-2)
[546545]=>
int(0)
}
}
Working Demo
It's because the output from your json_decode looks like this:
object(stdClass)(
'buildings' => 'townhall',
'Army' => object(stdClass)(
'Paladins' => object(stdClass)(
325648 => 0,
546545 => 4
),
'Knights' => object(stdClass)(
325648 => -2,
546545 => 0
)
)
)
Army is a standard object so it can't know how to echo it. You can however var_dump it:
var_dump($phpArray->Army);
The easiest solution is to treat it as a normal array with:
$phpArray = json_decode($jsonlogcontents, true);
{"": "attachment-2","": "attachment-1"}
I am getting this JSON-encoded string (or an oher format... let me know) from parsing a mail and I can not change it. How can I decode it?
You cannot use a JSON parser for this as it will always overwrite the first element due to the same keys. The only proper solution would be asking whoever creates that "JSON" to fix his code to either use an array or an object with unique keys.
If that's not an option the only thing you can do it rewriting the JSON to have unique keys before parsing it using json_decode()
Assuming it always gives you proper JSON and the duplicate keys are always empty you can replace "": with "random-string": - preg_replace_callback() is your friend in this case:
$lame = '{"": "attachment-2","": "attachment-1"}';
$json = preg_replace_callback('/"":/', function($m) {
return '"' . uniqid() . '":';
}, $lame);
var_dump(json_decode($json));
Output:
object(stdClass)#1 (2) {
["5076bdf9c2567"]=>
string(12) "attachment-2"
["5076bdf9c25b5"]=>
string(12) "attachment-1"
}
This JSON response is invalid as #ThiefMaster mentioned, because JSON doesn't support duplicated keys.
You should contact the service you're trying to request this response from.
In case you have a valid JSON response you can decode it using the json_decode function
which returns an object or an array (depends on the second parameter);
For example: (Object)
$json_string = '{"keyOne": "attachment-2","keyTwo": "attachment-1"}';
$decoded = json_decode($json_string);
print $obj->keyOne; //attachment-2
print $obj->keyTwo; //attachment-1
Another option is to write your own decoder function.
Decode it yourself?
$myStr = '{"": "attachment-2","": "attachment-1"}';
$vars = explode(',',$myStr);
$arr = array();
foreach($vars as $v){
list($key,$value) = explode(':',$v);
$key = substr($key,strpos($key,'"'),strpos($key,'"')-strrpos($key,'"'));
$value = substr($value,strpos($value,'"'),strpos($value,'"')-strrpos($value,'"'));
if($key=='')$arr[] = $value;
else $arr[$key] = $value;
}