Append JSON Data to JSON File Located on Server with PHP - php

I have a JSON file stored on my server that I need to add data to. I have successfully retrieved the file into memory and have parsed it successfully. I am just having a hard time placing the new JSON data in the correct spot.
Here is the format of my JSON file:
{
"emails": [
{
"group": "1st Group",
"list": [
{
"id": 1,
"subject": "Testing 1"
},
{
"id": 2,
"subject": "Testing 2"
}
] // End list array
}, // End 1st Group
{
"group": "2nd Group",
"list": [
{
"id": 3,
"subject": "Testing 3"
},
{
"id": 4,
"subject": "Testing 4"
}
] // End list array
} // End 2nd Group
/* NEED TO INSERT NEW DATA HERE */
] // End emails array
}
I am trying to append a new group list after the last group list. In this example, that would be after this line: } // End 2nd Group.
Here is my PHP code which gets the JSON file from my server and parses it:
$getJSON = file_get_contents('emails.json');
$tempArray = json_decode($getJSON, true);
$numberOfGroups = count($tempArray['emails'][0]);
And here is my php code that creates the format/layout of my JSON file:
$groupArray = array();
$json = array( 'emails' => array() );
foreach ($contextIORequest->getData() as $message) {
$newTZ = new DateTimeZone("America/Chicago");
$currentTime = new DateTime();
$currentTime = DateTime::createFromFormat('U', $message['date_received']);
$currentTime->setTimezone($newTZ);
$formattedDateReceived = $currentTime->format('F j, Y');
if (!in_array($formattedDateReceived, $groupArray)) {
array_push( $json['emails'],
array(
'group' => $formattedDateReceived,
'list' => array()
)
);
$groupArray[] = $formattedDateReceived;
}
$body = str_replace(array("\r\n","\n"),"", $message['body'][0]['content']);
$newBody = preg_replace('!\s+!', ' ', $body);
array_push($json['emails'][array_search($formattedDateReceived,$groupArray)]['list'],
array(
'id' => $message['message_id'],
'subject'=> addslashes($message['subject']),
'to' => array("Me"),
'body' => $newBody,
'time' => $formattedDateReceived,
'datetime' => $formattedDateReceived,
'from' => $message['addresses']['from']['name'],
'dp' => "assets/img/profiles/avatar.jpg",
'dpRetina' => "assets/img/profiles/avatar2x.jpg"
)
);
} // end foreach loop
// Output the JSON
header('Content-Type: application/json');
echo json_encode($json);
So how would I go about appending a new group list after the last group list? And this needs to be done without actually included the emails array used to create the JSON.

After running json_decode on the serialized data (with the second param passed as true like you've done), you'll have, in PHP, an associative array which has one element at a key named emails. That element is an array and holds the group lists to which you want to add another. So it's a matter of:
$data = json_decode($getJSON, true);
$data['emails'][] = $TheNewGroupList;
Don't let the fact that it started as serialized data in JSON format get you frazzled. Once you've run json_decode it's just a PHP data structure (object or array), and operations on it are just like any other PHP data.

Related

How to fetch JSON array in Retrofit?

I have a JSON array inside which there are JSON Objects like this:
[
{
"id": "63",
"userprofile": "userprofile.jpg",
"username": "James",
"content": "test.",
"address": "1111 Parker St",
"Post_date": "2022-05-25 02:41:15",
"images": [
"20220525_0241291.jpg",
"20220525_0241290.jpg"
]
}
]
I would like to have the string elements in the images array as objects instead. Can anyone suggest me how to make this type of JSON?
[
{
"id": "63",
"userprofile": "userprofile.jpg",
"username": "James",
"content": "test.",
"address": "1111 Parker St",
"Post_date": "2022-05-25 02:41:15",
"images": [
{"image": "20220525_0241291.jpg"},
{"image": "20220525_0241290.jpg"}
]
}
]
Here is my PHP code
<?php
header("Content-Type:application/json");
include '../db_con.php';
$query = "SELECT Board.* ,
GROUP_CONCAT(Board_images.imagepath separator ',') AS multiimages
FROM Board
LEFT JOIN Board_images ON Board.index = Board_images.boardindex
GROUP BY Board.index
ORDER BY Board.index";
$result = mysqli_query($conn, $query);
$response = array();
while ($row = mysqli_fetch_assoc($result)) {
array_push(
$response,
array(
'id' => $row['index'],
'userprofile' => $row['userprofile'],
'username' => $row['username'],
'content' => $row['content'],
'address' => $row['address'],
'Post_date' => $row['Post_date'],
'images' => explode(',',$row['multiimages'])
)
);
}
echo json_encode($response);
?>
explode returns a simple array of strings. All you have to do is go over it and put each of those strings into an array. You can do this in a loop or using an array function like array_map() which will do the same thing, applying a callback to each item.
You also don't need a loop to populate your response array, instead use mysqli_result::fetch_all(). You could use a loop to add the extra images element, but again I prefer using the array_walk() function as a matter of personal opinion.
(The difference between array_map and array_walk is that array_map returns a new array based on what the callback returns. array_walk only modifies the existing array.)
<?php
include '../db_con.php';
$query = "SELECT Board.* , GROUP_CONCAT(Board_images.imagepath separator ',') AS multiimages FROM Board
LEFT JOIN Board_images ON Board.index = Board_images.boardindex GROUP BY Board.index ORDER BY Board.index";
$result = $con->query($query);
// fetch all the records at once
$response = $result->fetch_all(\MYSQLI_ASSOC);
// this performs similar function to a foreach loop
array_walk(
$response,
function (&$v, $k) {
// explode the comma-separated list into an indexed array
$images = explode(",", $v["multiimages"]);
// now turn it into a bunch of associative arrays
$images = array_map(fn ($im) => ["image" => $im], $images);
// and then add it to the original $response array
$v["images"] = $images;
}
);
header("Content-Type:application/json");
echo json_encode($response);

auto-incrementing ID on my JSON array

I've been trying to do this for a while now and I just can't seem to get it right. One post got me very close but not quite there because my of JSON's hierarchy. (it's an assignment and this hierarchy is mandatory.)
What I do right now is submit info from one page, POST it to my php on another page, save it in an array there, json_encode that array and write that to my JSON file.
Here is my watered-down code, hopefully getting rid of most unnecessary code:
<?php
$filename = "json/exercises.json";
$filesize = filesize($filename);
$fp = fopen($filename, "r+");
#Accept the submitted form
$exLanguage = $_POST['exLanguage'];
$exTitle = $_POST['exTitle'];
$exStuff = $_POST['exStuff'];
#write to JSON with an incrementing ID
if (file_get_contents($filename) == "") {
$exercise = array (
"id" => 1,
"lang" => $exLanguage,
"title" => $exTitle,
"main_object" =>
[
"exStuff" => $exStuff
]
);
$exercise_json = json_encode($exercise, JSON_PRETTY_PRINT);
file_put_contents($filename, $exercise_json, FILE_APPEND);
} else {
#Get the last set ID
$jsonid = json_decode(fread($fp, $filesize), true);
$last = end($jsonid);
$title = prev($jsonid);
$lang = prev($jsonid);
$id = prev($jsonid);
$exercise = array (
"id" => ++$id,
"lang" => $exLanguage,
"title" => $exTitle,
"main_object" =>
[
"exStuff" => $exStuff
]
);
$exercise_json = json_encode($exercise, JSON_PRETTY_PRINT);
file_put_contents($filename, $exercise_json, FILE_APPEND);
}
?>
now what this does is if my json is empty it adds the first array correctly with the ID at 1. Then if I try to add to my json again it adds it correctly with the ID at 2. But any more attempted writes to the JSON will give me these errors:
Warning: end() expects parameter 1 to be array, null given
Warning: prev() expects parameter 1 to be array, null given
Warning: prev() expects parameter 1 to be array, null given
Warning: prev() expects parameter 1 to be array, null given
I tried doing a
$reset = reset($jsonid);
after writing to file but that didn't work, just gave me another error on the 3rd write for the reset being given a null too.
Can anyone please tell me how to get this too work? Or if there is a much easier way of getting this done?
Understand JSON format first. Its a collection of Objects which means attribute: value pair wrapped in {} and separated by comma , and then again wrapped in {} OR [] at top level.
Your JSON structure is incomplete or corrupted. What you are doing currently will create JSON in following format in your JSON file:
{ "id": 1, "lang": "as", "title": "asdsad" }
{ "id": 2, "lang": "as", "title": "asdsad" }
{ "id": 3, "lang": "as", "title": "asdsad" }
{ "id": 4, "lang": "as", "title": "asdsad" }
So json_decode will return null in this case because of invalid JSON format.
You need to keep appending your new JSON in existing JSON such that above format will become like this:
[
{ "id": 1, "lang": "as", "title": "asdsad" },
{ "id": 2, "lang": "as", "title": "asdsad" },
{ "id": 3, "lang": "as", "title": "asdsad" },
{ "id": 4, "lang": "as", "title": "asdsad" }
]
Which means your else block is incorrect. Use following code in else block:
$jsonid = json_decode(file_get_contents($filename), true);
$last = end($jsonid);
$id = $last['id'];
$jsonid[] = array (
"id" => ++$id,
"lang" => $exLanguage,
"title" => $exTitle,
"main_object" => array("exStuff" => $exStuff)
);
$exercise_json = json_encode($jsonid, JSON_PRETTY_PRINT);
file_put_contents($filename, $exercise_json, FILE_APPEND);
I hope you are not bound to use that incorrect/corrupted JSON format. That will not work with json_decode() in any case.

PHP - compare the structure of two JSON objects

I have two JSON objects and I would like to compare their structure. How can I do it?
Those object are being generated on-the-fly and depending on dynamic content.
Which means that the objects are always different but most of the time have the same structure. I want to be able to catch the changes once they occur.
Example: These two objects should be considered as equal, because both have the same structure: index var and tags array.
{
"index": 0,
"tags": [
"abc"
]
}
{
"index": 1,
"tags": [
"xyz"
]
}
Thoughts?
## You can use this library TreeWalker php .##
TreeWalker is a simple and smal API in php
(I developed this library, i hope it helps you)
It offers two methods
1- Get json difference
2- Edit json value (Recursively)
this method will return the diference between json1 and json2
$struct1 = array("casa"=>1, "b"=>"5", "cafeina"=>array("ss"=>"ddd"), "oi"=>5);
$struct2 = array("casa"=>2, "cafeina"=>array("ss"=>"dddd"), "oi2"=>5);
//P.s
print_r($treeWalker->getdiff($struct1, $struct2))
{
new: {
b: "5",
oi: 5
},
removed: {
oi2: 5
},
edited: {
casa: {
oldvalue: 2,
newvalue: 1
},
cafeina/ss: {
oldvalue: "dddd",
newvalue: "ddd"
}
},
time: 0
}
It's a bit rough, but you get the picture;
$json = '[
{
"index": 0,
"tags": [
"abc"
]
},
{
"index": 1,
"tags": [
"xyz"
]
},
{
"foo": 2,
"bar": [
"xyz"
]
}]';
$array = json_decode($json, true);
$default = array_keys($array[0]);
$error = false;
$errors = array();
foreach ($array as $index => $result):
foreach ($default as $search):
if (!isset($result[$search])):
$error = true;
$errors[] = "Property '{$search}' at entry '{$index}' not found. ";
endif;
endforeach;
endforeach;
if ($error):
echo 'Objects are not the same. ';
foreach ($errors as $message):
echo $message;
endforeach;
endif;
returns:
Objects are not the same. Property 'index' at entry '2' not found. Property 'tags' at entry '2' not found.
You can try to use package https://github.com/coduo/php-matcher
Example: These two objects should be considered as equal, because both have the same structure: index var and tags array.
You can create a "php-matcher pattern" like this:
{
"index": "#integer#",
"tags": "#array#.repeat(\"#string#\")"
}
Then you match your JSONs against this pattern. If you have 2 JSONs and both match this pattern then it means that they are "equal" according to your definition of equality above.
Please see results in "php-matcher sandbox" for the example JSONs you gave:
Example 1 in sandbox
Example 2 in sandbox
Additionally you can use package https://github.com/sebastianbergmann/diff (which you should already have if you have phpunit) to generate a diff when the pattern doesnt match the value.
For example:
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
...
$valueToCheck = '{
"foo": 0,
"bar": {"one": 1, "two": "2"}
}';
$expectedValuePattern = '{
"foo": "#integer#",
"bar": {"one": 1, "two": 2}
}';
if (!$matcher->match($valueToCheck, $expectedValuePattern)) {
$differ = new Differ(
new UnifiedDiffOutputBuilder(
"Json value is not matching expected format:\n",
true
)
);
$diffOutput = $differ->diff(
\json_encode(\json_decode($expectedValuePattern, true), JSON_PRETTY_PRINT),
\json_encode(\json_decode($valueToCheck, true), JSON_PRETTY_PRINT)
);
var_dump(
$diffOutput
. "\n".$matcher->getError()."\n"
);
} else {
var_dump('OK');
}
it will print:
Json value is not matching expected format:
## -1,7 +1,7 ##
{
- "foo": "#integer#",
+ "foo": 0,
"bar": {
"one": 1,
- "two": 2
+ "two": "2"
}
}
That message with diff is especially helpfull for bigger JSON's to quickly see which element is not matching.
See more ways of usage in README of that package - especially:
https://github.com/coduo/php-matcher#json-matching
https://github.com/coduo/php-matcher#json-matching-with-unbounded-arrays-and-objects
This package is very good to use in automatic tests (for example: phpunit) to assert if JSON from API responses is correct etc - considering that in integration tests there are often many id's, uuid's, datetime's etc which change on each test execution - like database generated id's etc.
I hope it helps :)
You mean by structure, like model array like:
array ( 'index' => int, 'tags' => array() )
If that's what you are trying to get, try this...
$arr1 = array (
array (
'index' => 0,
'tags' => ['abc']
),
array (
'index' => 1,
'tags' => ['xyz']
),
array (
'index' => 2,
'tags' => ['xyz'],
'boom' => 'granade'
),
array (
'index' => 3,
'tags' => 'xyz'
)
);
$holder = array();
$model = array ('index' => 0, 'tags' => array());
for ($i = 0;$i < count($arr1); $i++)
{
$holder = array_diff(array_merge_recursive($arr1[$i], $model), $model);
if (!empty($holder))
{
echo "different structure<br>";
}
else
{
echo "same structure<br>";
// for further validation
/*
$keys = array_keys($model);
if (is_int($arr1[$i][$keys[0]]) && is_array($arr1[$i][$keys[1]]))
echo "same structure<br>";
else
echo "different structure<br>";
*/
}
}
Sample output:
same structure
same structure
different structure
different structure
You can convert the json string to a php array then use the array_diff($arr1,$arr2) function to compare the newly created array with another array
the result is an array containing the elements of the first array that doesn't exist in the other array
example :
<?php
$array1 = '{"name":"myname","age":"40"}';
//convert the obtained stdclass object to an array
$array1 = (array) json_decode($array1);
$array2 = array("name"=>"myname123","age"=>10);
print_r($array2);
$result_array = array_diff($array1,$array2);
if(empty($result_array[0])){
echo "they have the same structure ";
}
?>

PHP & JSON: Inserting an array in a nested array

I am creating a JSON structure to be passed back to Ajax. I would like to insert 'para' => "Hello" into "content" like this:
{
"sections": {
"content": [{
"para": "Hello"
}]
}
}
I tried using this code:
$array = array('sections' => array());
array_push($array["sections"], array("content" => array())); // content must be initialized as empty
array_push($array["sections"][0], array("para" => "Hello"));
But I received this instead:
{
"sections": [{
"content": [],
"0": {
"para": "Hello"
}
}]
}
If I try array_push($array["sections"]["content"], array("para" => "Hello")), I get an error instead. How do I insert an array into "content"? What am I doing wrong?
If I understood your intentions correctly, here's the array structure you're aiming for:
array("sections" => array(
"content" => array("para" => "Hello"),
));
However, in Javascript [] represents an array and {} represents an object. If you're trying to create an object with a property of "0", that's not possible in PHP. Variable names have to start with a letter or underscore.
Here's an array of content objects:
$content = new stdClass();
$content->para = 'hello';
array("sections" => array(
"content" => array($content),
));
To add arrays of contents:
array("sections" => array(
"content" => array(
array("para" => "Hello"),
array("para" => "Hello"),
array("para" => "Hello"),
),
));
You can also construct your own contents array first if you're iterating over an index and then json_encode it. Basic example:
$content = array();
for (i=0; i <3; i++) {
$content[] = array('para' => 'hello');
}
json_encode(array("sections" => array(
"content" => array($content),
)));
To convert that to JSON, put your array inside a json_encode() call.
$array['sections'] = array("content" => array(array("para" => "Hello")));
echo json_encode($array);
will give the result in desired format

PHP json_encode() results showing JSONLint errors

I am having issues with validating the output of my json_encode() function.
I am pulling in an XML feed with cURL, converting it into an array, and converting that array into JSON with json_endode(). Ill spare you the cURL stuff:
foreach ($xmlObjects->articleResult as $articleResult) {
$article = array(
"articleResult" =>
array(
'articleId' => (string)$articleResult->articleId,
'title' => (string)$articleResult->title,
'subhead' => (string)$articleResult->subhead,
'tweet' => (string)$articleResult->tweet,
'publishedDate' => (string)$articleResult->publishedDate,
'image' => (string)$articleResult->image
),
);
$json = str_replace('\/','/',json_encode($article));
echo $json;
}
Which is giving me a JSON readout of:
{
"articleResult": {
"articleId": "0001",
"title": "Some title",
"subhead": "Some engaging subhead",
"tweet": "Check out this tweet",
"publishedDate": "January 1st, 1970",
"image": "http://www.domain.com/some_image.jpg"
}
}
{
"articleResult": {
"articleId": "0002",
"title": "Some title",
"subhead": "Some engaging subhead",
"tweet": "Check out this tweet",
"publishedDate": "January 1st, 1970",
"image": "http://www.domain.com/some_image.jpg"
}
}
This will give me a JSONLint error saying:
Parse error on line 10:
..._120x80.jpg" }}{ "articleResult
---------------------^
Expecting 'EOF', '}', ',', ']'
So naturally I will add in the comma, which gives me an End of File expectation:
Parse error on line 10:
..._120x80.jpg" }},{ "articleResu
---------------------^
Expecting 'EOF'
I am new to JSON, but I have checked the website and a few resources for proper JSON formatting and structure, and from what I can see my readout is following the guidelines. Any pointers?
Resources I've checked:
JSON.org naturally
Wikipedia has well documented page
W3Resource Had a good explanation of structure.
JSONLint
You were encoding 2+ objects into json string, you need [ ] to wrap them
the correct syntax is
[
{ /* first object */ }
, { /* second object */ }
, { /* third object */ }
]
the things you need to look out are
[ ] wrap
separate objects by comma
Solution
$json = array();
foreach ($xmlObjects->articleResult as $articleResult) {
$article = array(
"articleResult" =>
array(
'articleId' => (string)$articleResult->articleId,
'title' => (string)$articleResult->title,
'subhead' => (string)$articleResult->subhead,
'tweet' => (string)$articleResult->tweet,
'publishedDate' => (string)$articleResult->publishedDate,
'image' => (string)$articleResult->image
),
);
$json[] = $article;
}
echo json_encode($json);

Categories