PHP: setting a number as key in associative array - php

I'm trying to recreate json from a DB, for the client side. Unfortunately some of the keys in the json are numbers, which work fine in javascript, however as a result PHP keeps treating them as numeric instead of associative arrays. each key is for a document. let me show you:
PHP:
$jsonobj;
while ($row = mysql_fetch_assoc($ms)) {
$key = strval($row["localcardid"]);
$jsonobj[$key] = json_decode($row["json"]);
}
// $jsonobj ist still a numeric array
echo json_encode($jsonobj);
the resulting json should look like this:
{
"0": {
"terd": "10",
"id": 0,
"text": "",
"pos": 1,
"type": 0,
"divs": [
{},
{}
],
"front": 1
}
"1": {
"terd": "10",
"id": 0,
"text": "",
"pos": 1,
"type": 0,
"divs": [
{},
{}
],
"front": 1
}
}
One obvious solution would be to save the whole json without splitting in up. however that doesnt seem wise in regards to the db. i wanna be able to access each document seperately. using
$jsonobj = array ($key => json_decode($row["json"]));
obviously works, but unfortunately just for one key...
EDIT: for clarification*
in php: there's a difference between
array("a", "b", "c")
and
array ("1" => "a", "2" => "b", "3" => "c").
the latter, when done like this $array["1"] = "a" results in array("a") instead of array("1" => "a")
ANSWERED HERE

Try
echo json_encode((object)$jsonobj);

I believe if you pass the JSON_FORCE_OBJECT option, it should output the object with numeric indexes like you want:
$obj = json_encode($jsonObj, JSON_FORCE_OBJECT);
Example:
$array = array();
$array[0] = array('test' => 'yes', 'div' => 'first', 'span' => 'no');
$array[1] = array('test' => 'no', 'div' => 'second', 'span' => 'no');
$array[2] = array('test' => 'maybe', 'div' => 'third', 'span' => 'yes');
$obj = json_encode($array, JSON_FORCE_OBJECT);
echo $obj;
Output:
{
"0": {
"test": "yes",
"div": "first",
"span": "no"
},
"1": {
"test": "no",
"div": "second",
"span": "no"
},
"2": {
"test": "maybe",
"div": "third",
"span": "yes"
}
}

Simply save both inside a single entry in the database: the separate field values AND the whole json structure inside a separate column. This way you can search by single fields and still get the valid json structure for easy handling.

For setting a number as key in associative array we can use following code
$arr=array(); //declare array variable
$arr[121]='Item1';//assign Value
$arr[457]='Item2';
.
.
.
print_r($arr);//print value

Related

Encode multidimensional array using while loop

I have a multidimensional array and I want it printed like these by using PHP, but there is no comma separating the curly braces }{ and it should be like },{. Can you guys help me?
{"user_activity": [{
"log_number": "1",
"log_user_1": "w120511891",
"log_activity_id": "A0002DOC",
"log_user_2": "",
"log_document_id": "DSX00012",
"log_material_id": "",
"log_timestamp": "2021-10-23 13:52:35",
"log_rand_key": "127",
"log_hash_key": "09c7e3bb5d6f74c257aa4b4cdae388a69177c7dc",
"log_project_id": "1520002",
"log_number_reference": "",
"log_close": "1"
}{
"log_number": "9",
"log_user_1": "W201005911",
"log_activity_id": "A0004DOC",
"log_user_2": "",
"log_document_id": "DSX00012",
"log_material_id": "",
"log_timestamp": "2021-10-25 10:35:29",
"log_rand_key": "127",
"log_hash_key": "d04e8d1ef5c9f8b85a3f7556b92d6a7fcdc11639",
"log_project_id": "1520002",
"log_number_reference": "1",
"log_close": "1"
}]}
This is my PHP Code
echo "{\"user_activity\": [";
while($rsel_userAct_p = mysqli_fetch_array($xsel_userAct_p, MYSQLI_ASSOC)) {
print_r(json_encode($rsel_userAct_p), JSON_PRETTY_PRINT);
}
echo "]}";
You're doing it wrong. Just create an array, append data from MySQL into it and json_encode the array itself:
$array = [];
while ($rsel_userAct_p = mysqli_fetch_array($xsel_userAct_p, MYSQLI_ASSOC)) {
$array["user_activity"][] = $rsel_userAct_p;
}
echo json_encode($array, JSON_PRETTY_PRINT);
Or even better:
$array = [
"user_activity" => mysqli_fetch_all($xsel_userAct_p, MYSQLI_ASSOC)
];
echo json_encode($array, JSON_PRETTY_PRINT);
Your issue is that you are using print_r in the first place. print_r is meant to print out a very specific format which helps with array structures but has nothing to do with json.
Taken from the print_r documentation
<pre>
<?php
$a = array ('a' => 'apple', 'b' => 'banana', 'c' => array ('x', 'y', 'z'));
print_r ($a);
?>
</pre>
will result in
Array
(
[a] => apple
[b] => banana
[c] => Array
(
[0] => x
1 => y
[2] => z
)
)
What you actually want (at least guessing from your code example) is you want to print out a single json object that consists of multiple results from your database, based upon the array result you got before.
So instead of using your current code, you create a proper array structure in the first place and then you print it out with the given json function.
$activities = [
'user_activity' => []
];
while($rsel_userAct_p = mysqli_fetch_array($xsel_userAct_p, MYSQLI_ASSOC)) {
$activities['user_activity'][] = $rsel_userAct_p;
}
echo json_encode($activities, JSON_PRETTY_PRINT);
The actual result should look exactly like you intend the result to be, and even works regardless of the amount of entries in your database.
This will make your JSON in correct format:
$json='{"user_activity": [{
"log_number": "1",
"log_user_1": "w120511891",
"log_activity_id": "A0002DOC",
"log_user_2": "",
"log_document_id": "DSX00012",
"log_material_id": "",
"log_timestamp": "2021-10-23 13:52:35",
"log_rand_key": "127",
"log_hash_key": "09c7e3bb5d6f74c257aa4b4cdae388a69177c7dc",
"log_project_id": "1520002",
"log_number_reference": "",
"log_close": "1"
}{
"log_number": "9",
"log_user_1": "W201005911",
"log_activity_id": "A0004DOC",
"log_user_2": "",
"log_document_id": "DSX00012",
"log_material_id": "",
"log_timestamp": "2021-10-25 10:35:29",
"log_rand_key": "127",
"log_hash_key": "d04e8d1ef5c9f8b85a3f7556b92d6a7fcdc11639",
"log_project_id": "1520002",
"log_number_reference": "1",
"log_close": "1"
}]}';
$json=str_replace("}{","},{",$json);
Then you can use :
echo "<pre>";
print_R(json_decode($json,true));
to convert JSON to PHP array.
You can use in while like:
$json = [];
while ($rsel_userAct_p = mysqli_fetch_array($xsel_userAct_p, MYSQLI_ASSOC)) {
$json["user_activity"][] = $rsel_userAct_p;
}
echo json_encode($json, JSON_PRETTY_PRINT);

Array_Diff is deleting only the key/value from the array of objects but not the whole object

I have a script that ultimately produces a JSON array. Producing the JSON array works fine, with the exception that I can't seem to delete an entire object from an array of objects when searching for a specific keys value.
Producing the Array:
$sql="SELECT * FROM `emails` WHERE `subject` LIKE '%5678%' order by `id` DESC LIMIT 50";
$result = mysqli_query($DatabasePointer2,$sql) or die(mysqli_error($DatabasePointer2));
$row_cnt = mysqli_num_rows($result);
if($row_cnt>0) {
$array = array();
$i=0;
while($row = mysqli_fetch_array($result)) {
$i++;
$a1 = explode('-', $row['body']);
$a1[0] = str_replace("","",$a1[0]);
$a1[1] = str_replace("TF: ","",$a1[1]);
$a1[1] = str_replace("minutes","M",$a1[1]);
$a = array(
"p" => "test",
"id" => $row['id'],
"thekey" => $a1[1],
"time" => $dt->format('Y-m-d H:i:s'),
"utctime" => strtotime($dt->format('Y-m-d H:i:s')),
"utc2" => $two->format('Y-m-d H:i:s'),
"utc3" => $three->format('Y-m-d H:i:s')
);
$a1 = array_diff($a, ["keytoexclude1", "keytoexclude2", "keytoexclude3"]);
$array[] = $a1;
}
}
echo json_encode($array, JSON_UNESCAPED_SLASHES);
Note that value of thekey is not static.
The code above, produces this:
[{
"p": "test",
"id": "198645",
"time": "2020-05-06 23:00:49",
"utctime": 1588806049,
"utc2": "2020-05-07 01:00:49",
"utc3": "2020-05-07 02:00:49"
}, {
"p": "test",
"id": "198605",
"time": "2020-05-06 22:00:55",
"utctime": 1588802455,
"utc2": "2020-05-07 00:00:55",
"utc3": "2020-05-07 01:00:55",
"thekey": "123456"
}, {
"p": "test",
"id": "198604",
"time": "2020-05-06 22:00:54",
"utctime": 1588802454,
"utc2": "2020-05-07 00:00:54",
"utc3": "2020-05-07 01:00:54"
}]
What I'm trying to accomplish is to search for any key that matches a list of exclusions, and then remove the whole object if it finds a key in the list of exclusions.
List of Exclusions/Code to remove...
$a1 = array_diff($a, ["keytoexclude1", "keytoexclude2", "keytoexclude3"]);
Whats happening, is that it just removes the key/value itself, but keeps the rest of the object.
If you look in the array above, you'll see that if an exclusion was found, it only removes "thekey" and its value from the object, but leaves the rest of the keys in the objects.
Can somebody please assist in how to remove the whole object?
**Updated to show mistake where the value for "thekey" isn't supposed to come from the mysql database, but the exploded array.
Use an if statement to check if the value is in the list of exclusions, and skip the row.
while($row = mysqli_fetch_array($result)) {
if (in_array($row['thevalue'], ["keytoexclude1", "keytoexclude2", "keytoexclude3"])) {
continue;
}
$a = array(
"p" => "test",
"id" => $row['id'],
"thekey" => $row['thevalue'],
"time" => $dt->format('Y-m-d H:i:s'),
"utctime" => strtotime($dt->format('Y-m-d H:i:s')),
"utc2" => $two->format('Y-m-d H:i:s'),
"utc3" => $three->format('Y-m-d H:i:s')
);
$array[] = $a1;
}

PHP - Find an object by key in an array of objects, update its value

I have an array of objects, and want to update an attribute of one of the objects.
$objs = [
['value' => 2, 'key' => 'a'],
['value' => 3, 'key' => 'b'] ,
];
Let's say I want to set the 'value' of the object with 'key'=>'a' to 5.
Aside from iterating over the array searching for the key, is there any quicker/efficient way of doing this?
Thanks.
EDIT: There is debate as to why I can't use an associative array. It is because this array is obtained from a JSON value.
If my JSON object is this:
"obj": {
"a": {
"key": "a",
"value": 2
},
"b": {
"key": "b",
"value": 3
}
}
There is no guarantee that the order of the objects will be retained, which is required.
Hence I need an index in each object to be able to sort it using usort(). So my JSON needs to be:
"obj": {
"a": {
"key": "a",
"value": 2,
"index": 1
},
"b": {
"key": "b",
"value": 3,
"index": 2
}
}
But I cannot use usort() on an object, only on arrays. So my JSON needs to be
"obj": [
{
"key": "a",
"value": 2,
"index": 1
}, {
"key": "b",
"value": 3,
"index":2
}
]
Which brings us to the original question.
By using array_column(), you can pull all the values with the index key in the arrays. Then you can find the first occurrence of the value a by using array_search(). This will only return the first index where it finds a value. Then you can simply replace that value, as you now have the index of that value.
$keys = array_column($objs, 'key');
$index = array_search('a', $keys);
if ($index !== false) {
$objs[$index]['value'] = 5;
}
See this live demo.
http://php.net/array_search
http://php.net/array_column
You can make the array associative with array column. That way you can directly assign the value.
$objs = [ ['value'=>2, 'key'=>'a'], ['value'=>3, 'key'=>'b'] ];
$objs = array_column($objs, null, "key");
$objs['a']['value'] = 5;
https://3v4l.org/7tJl0
I want to recommend you reorginize your array lake that:
$objs = [
'a' => ['value'=>2, 'key'=>'a'],
'b' => ['value'=>3, 'key'=>'b']
];
And now
if( array_key_exists( 'a', $objs )) {
$objs ['a'] ['value'] = 5;
}
I had it like that initially. But I need for the objects to have an
index value in them, so I can run usort() on the main array. This is
because the array comes from JSON where the original order isn't
respected
Then create an index array:
// When fill `$objs` array
$objs = [];
$arrIndex = [];
$idx = 0;
foreach( $json as $item ) {
$arrIndex [ $item ['key']] = $idx;
$objs [$idx ++] = $item;
}
// And your task:
if( array_key_exists( 'a', $arrIndex )) {
$objs [ $arrIndex ['a']] ['value'] = 5;
}
Aside from iterating over the array searching for the key, is there
any quicker/efficient way of doing this?
You have to pay the price of iteration either way.
You can search your collection for the interesting object (takes linear time), or you form some kind of dictionary data structure, e.g. hash table (takes linear time) and then find the interesting object in constant time.
No free lunches here.

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 ";
}
?>

Categories