Updating JSON array with PHP - php

I'm working on a PHP script to add new item in JSON array (JSON is in a file) and I've found a prob and its solution. My question is: can someone explains why the first code doesn't work?
The JSON is built on several imbricated arrays describing batiments, stairs and objects on each stair of each batiment:
"bats":[
// each batiment
{"name":"Bat A","photo":"photo-bat-0.png",
"stairs":[
// level 0
{"plan":"plan-0-0.png","note":"",
"objs":[
{"id":"obj-0-0-0","type":"MER","col":"black","left":"","top":"","cable":22,"img":""},
{"id":"obj-0-0-1","type":"SER","col":"blue","left":"","top":"","cable":12,"img":""}
],
},
// level 1
{"plan":"plan-0-1.png","note":"",
"objs":[
{"id":"obj-0-1-0","type":"TFT","col":"red","left":"","top":"","cable":8,"img":""},
{"id":"obj-0-1-1","type":"AP1","col":"green","left":"","top":"","cable":12,"img":""},
{"id":"obj-0-1-2","type":"AP2","col":"green","left":"","top":"","cable":14,"img":""}
]
}
]
},
{"name":"Bat B","photo":"photo-bat-1.png"
"stairs":[
...
Adding a new object to BAT 1 LEVEL 0:
$bat = 1;
$lev = 0;
// get existing objects
$objects = $json_data['bats'][$bat]['stairs'][$lev]['objs'];
$n = count($objects);
echo "found $n objects on level $lev of bat $bat<br>";
for($o=0; $o<count($objects); $o++){
echo $objects[$o]['id']."<br>";
}
The object to add to array
$newobject = array("id"=>"obj-".$bat."-".$lev."-".$o,"type"=>"AP","coul"=>"green","left"=>123,"top"=>155,"cable"=>5,"img"=>"image-obj-".$bat."-".$lev."-".$o);
This code doesn't work: (JSON file remains the same once reloaded)
array_push($objects,$newobject);
This one works: (JSON file updated)
array_push($json_data['bats'][$bat]['stairs'][$lev]['objs'],$newobject);
Why is it necessary to recreate the full access path to array 'objs'?

Related

How to create a blank associative array in php

My php script returns data to the web client where it is processed by javaScript.
If data is found it is stored in an associative array / object. If no data is found I would like to send a blank associative array.
The only example I have seen on line is in the manual where you create an empty class and then instantiate an object from that.
Below is my code and the results it produces on the web client side
$sql = 'select job, client, project from jobs j left join client c on c.key = j.cKey where j.key='.$this->p['reckey'];
if ( $result = $db->query($sql) )
{
if ($result->num_rows > 0)
{
$l = mysqli_fetch_all( $result, $resulttype = MYSQLI_ASSOC );
$this->res_array['info'] = $l[0];
}else{
$this->errors[] = 'No such job # '.$this->p['reckey'];
$this->res_array['info']=[];
}
}else{
$this->errors[] = 'Query failed!';
$this->res_array['info']=[];
}
$this->res_array['errors'] = $this->errors;
echo json_encode ($this->res_array);
Here are two examples of what the data looks like when it arrives at the web client before it is decoded by JSON. Note the difference in the "info" element.
response {"info":{"job":"999","client":"My Company, Inc. ","project":"This Project"},"errors":[]}
error response {"info":[ ],"errors":["No such job # 0"]}
In the successful response I have an object/associative array where I would use the
for (variable in object) {...}
In the blank response I just get the standard array [ ] square brackets where I would use the
for (step = 0; step < info.length; step++) {}
This occurs of course because I am specifying a blank array in the php code above.
My question is simple how can I change my php code so a blank associtive array is transmitted?
The only example I have seen on line is in the manual where you create an empty class and then instantiate an object from that.
Sounds like you've answered your own question!
Since in JavaScript an object and an associative array are basically the same thing all you have to do is replace this line:
$this->res_array['info']=[];
With this one:
$this->res_array["info"] = new StdClass;
Or if you want to make the change only before sending the response you could check for an empty info array and replace it with an empty class.
if(!count($this->res_array["info"]))
$this->res_array["info"] = new StdClass;
I would suggest to take the best of both worlds, and let PHP generate an array of associative arrays, even though you expect at the most one, but at least you'd use the same structure for when you have none.
So change:
$this->res_array['info'] = $l[0];
to:
$this->res_array['info'] = $l;
And then in JavaScript do:
for (var step = 0; step < info.length; step++) {
for (variable in info[step]) {
// ...
}
}
... and if you still need to, you can deal with the no-data condition separately in JavaScript. Something like:
if (errors.length) {
// deal with this case...
}

Can't parse XMLHttpRequest.response to Object or Array

I'm trying to refresh the content of my cells of an table. Therefore, I have a JavaScript which contains an AJAX request to a .php file, which creates my content that I want to insert into my table via JavaScript. The .php files last command is something like echo json_encode($result);.
Back in the JavaScript it says:
var testarray = xmlhttp.response;
alert(testarray);
But the outut from the alert looks like:
{"1":{"1":"3","2":"0","3":"2","4":"0"}}{"1":{"1":"3","2":"0","3":"2","4":"0"},"2":{"1":"2","2":"1","3":"1","4":"1"}}...
So it seems the variable testarray isn't handled as an array but as a string. I already tried var testarray = JSON.parse(xmlhttp.response), but this doesn’t work. Neither does eval() works.
I don't know what to do, so the response of my request becomes an object.
There are 2 strange things in your json:
this part is not json valid: ...}{...
two object should be separated by comas
The notation is object with string indexes not array with int indexes
it should be something like: [[1,2,3,4],[5,6,7,8]]
for the point 1. it looks like you have a loop that concatenate many json
for the point 2. the object notation can be used as an array so it doesn't matter
Some code:
//the folowing code doesn't work: }{ is not parsable
var a=JSON.parse('{"1":{"1":"3","2":"0","3":"2","4":"0"}}{"1":{"1":"3","2":"0","3":"2","4":"0"},"2":{"1":"2","2":"1","3":"1","4":"1"}}');
//the folowing code work and the object can be used as an array
var a=JSON.parse('{"1":{"1":"3","2":"0","3":"2","4":"0"},"2":{"1":"2","2":"1","3":"1","4":"1"}}');
alert(JSON.stringify(a[1]));
//the folowing code displays the real notation of a javascript array:
alert(JSON.stringify([1,2,3,4]));
I think that the problem here might be that your arrays do not have index 0.
e.g. if you output this from the server - it would produce an object:
$result = [];
for ($i = 1; $i < 5; $i++) $result[$i] = $i;
echo json_encode($result); // outputs an object
if you output this from the server - it would produce an array:
$result = [];
for ($i = 0; $i < 5; $i++) $result[$i] = $i;
echo json_encode($result); // produces an array
Anyways, even if your server outputs array as object - you should still be able to access it normally in javascript:
var resp = xmlhttp.responseText, // "responseText" - if you're using native js XHR
arr = JSON.parse(resp); // should give you an object
console.log(arr[1]); // should give you the first element of that object

How to filter JSON array into PHP array

I have a JSONArray generated in java and I post it to one of my PHP files where it's saved to a file. From there it gets read and I need to generate a chart based on this data. All I need is to convert my raw JSON which has values I don't need, into a simply php array.
[{"id":1,"timestamp":"1363135091","reward":1200,"player":"Orangeguy24","address":"108.28.239.167","service":"MC-Index"},{"id":2,"timestamp":"1363135091","reward":1200,"player":"Orangeguy24","address":"108.28.239.167","service":"MC-Index"}]
Is an example of 2 elements inside my JSON array. What I need todo is filter those values into arrays accordingly.
For example get how many votes a 'player' has, I need to add up how ever many elements are in the JSONArray, because 1 element is 1 vote (the id is primary auto-increment in my mysql DB, not located on my webserver)
I'd like the array to be to [player, votes] so when I echo the array it will be easily parsed by the google chart tools I'm using. I've spent the last 5 hours working on this and I've been stuck, thanks for any help!
To decode the JSON into a php array, you can do:
$json_array = json_decode($raw_json);
Then, to get the number of votes for each player out of the array:
$player_votes = array_reduce($json_array,
function($v, $item) {
if(!array_key_exists($item->player, $v))
$v[$item->player] = 1;
else
$v[$item->player] = 1 + $v[$item->player];
return $v;
}, array());
If I understand your question correctly, this will work.
EDIT: Updated the second code snippet
Try this :
$str = '[{"id":1,"timestamp":"1363135091","reward":1200,"player":"Orangeguy24","address":"108.28.239.167","service":"MC-Index"},{"id":2,"timestamp":"1363135091","reward":1200,"player":"Orangeguy24","address":"108.28.239.167","service":"MC-Index"}]';
$res = array();
foreach(json_decode($str,true) as $val){
if(array_key_exists($val['player'],$res)){
$res[$val['player']] = $res[$val['player']]+1;
}
else{
$res[$val['player']] = 1;
}
}
echo "<pre>";
print_r($res);
Output :
Array
(
[Orangeguy24] => 2
)

PHP - error in json_encode()

Problem: returns array, but not in json.
Result: must return array with in array. outer array has key with numbers and value is array with keys "ID" and "NAME" and there values are assigned from database.
$i = 0;
$json_values = array();
while($sctg = mysql_fetch_assoc($get_sctg)){
$json_values[$i] = array("ID" => $sctg['ID'], "NAME" => $sctg['NAME']);
$i++;
}
echo json_encode($json_values);
Your code is perfectly fine - you just misunderstood the different between arrays and objects in JavaScript.
[{"ID":"4","NAME":"asdasd"},
{"ID":"3","NAME":"LOKS"},
{"ID":"1","NAME":"LOL"}]
This is JSON containing an array with three elements. Each element is an object with the properties ID and NAME.
Let's assume that array is stored in data. You can iterate over the objects in that array with a simple for loop:
for(var i = 0; i < data.length; i++) {
var row = data[i];
// Here you can use row.ID and row.NAME
}
I guess you expected your JSON to look like this:
{
0: {"ID":"4","NAME":"asdasd"},
1: {"ID":"3","NAME":"LOKS"},
2: {"ID":"1","NAME":"LOL"}
}
This would actually be bad since objects in JavaScript are not ordered (even though they actually are in most browsers, but that's not guaranteed!). So when iterating over the rows in such an element (using for(var key in data)), you would not necessarily get the row with ID=4 first just because its key is zero.
However, if you really want an object instead of an array for some reason (you don't!), you could always cast the array to object:
echo json_encode((object)$json_values);
As a side-note, usually it's a good idea to have an object as the top-level element in JSON for security reasons (you can redefine the array constructor and then include something with a top-level array with a script tag and thus access data usually protected by the same origin policy if it was accessed by an XHR request), so I'd change the PHP code like this:
echo json_encode(array('rows' => $json_values));
No need to use $i++; directly use
while($sctg = mysql_fetch_assoc($get_sctg)){
$json_values[] = array("ID" => $sctg['ID'], "NAME" => $sctg['NAME']);
}
and it will return you the JSON

Get Value of PHP Array

I'm attempting to use the VirusTotal API to return the virus scan for a certain file. I've been able to get my current PHP code to upload the file to VirusTotal as well as get the results in an array. My question is, how would I get the [detected] value from every virus scanner under the scans object? My PHP code is below as well as a link to the output of the array.
require_once('VirusTotalApiV2.php');
/* Initialize the VirusTotalApi class. */
$api = new VirusTotalAPIV2('');
if (!isset($_GET["hash"])) {
$result = $api->scanFile('file.exe');
$scanId = $api->getScanID($result);
$api->displayResult($result);
} else {
$report = $api->getFileReport($_GET["hash"]);
$api->displayResult($report);
print($api->getSubmissionDate($report) . '<br>');
print($api->getReportPermalink($report, TRUE) . '<br>');
}
http://joshua-ferrara.com/viruscan/VirusTotalApiV2Test.php?hash=46faf763525b75b408c927866923f4ac82a953d67efe80173848921609dc7a44
You would probably have to iterate each object under scans in a for loop and either store them in yet another array or echo them out of just want to print. For example
$detectedA = {nProtect, CAT-QuickHeal, McAfee...nth};
$datContainer = array();
for ($i = 0; i < $api.length ; i++){
//Either store in an array
$api->$scans->detectedA(i)-> detected = $datContainer(i);
//Or echo it all
echo $api->$scans->detectedA(i)->detected;
return true;
}
Granted that's probably not the way you access that object but the idea still applies.
This description of stdClass demonstrates how you can not only store arbitrary tuples of data in an object without defining a class, but also how you can cast an arbitrary object as an array - which would then let you iterate over the sub-objects in your case.
Or, if I've misunderstood your question and you're actually getting an array back from the VirusTotal API and not a stdClass instance, then all you need to do is loop.
Store the scans into an array (of scans), then just loop through the array as usual.
foreach($scans as $scan) echo $scan->detected;
Or, if I'm not quite understanding the question right, is detected an array (or an object)?
Edit because of your comments -
The object returned holds an object of objects, so you need to do some casting.
foreach((array)$scans as $scanObj) {
$scan=(array)$scanObj;
foreach($scan as $anti) {
print $anti->detected; } }

Categories