json_encode changing array with one value to object - php

I"m creating a PHP script that handles JSON input (via a $_POST variable). It"s extracts data from the JSON and uploads it to an SQL database. I want the JSON in a particular format:
$object = json_decode('{
"key_a":[{"value_a":10,"value_b":7},{"value_a":10,"value_b":7},{"value_a":10,"value_b":7}],
"key_b":[{"value_a":10,"value_b":7}],
"key_c":[{"value_a":10,"value_b":7},{"value_a":10,"value_b":7}]
}',true);
Basically, an object with keys in, each of which should hold an array (no matter what size it is). I use json_decode(json,true) to convert it to an associative array (as opposed to object). I"ve had to add lots of checks in for each of the keys, checking if they"re objects or arrays (as the ASP.net page that the extract comes from converts arrays with single objects in, to objects - removing the array that holds them). The checks then convert them back to arrays, if there"s an object where I"d like an array holding an object:
if(is_object($object["key_b"]))
{
$a = array();
$a[] = $object["key"];
$object["key"] = $a;
}
I then iterate through the array, adding the values to rows in an SQL database. This all works fine, but when converting back to JSON with json_encode, any keys that hold arrays with only one object in, remove the array, and leave just the object under that key:
echo(json_encode($object));
// RETURNED JSON
'{
"key_a":[{"value_a":10,"value_b":7},{"value_a":10,"value_b":7},{"value_a":10,"value_b":7}],
"key_b":{"value_a":10,"value_b":7},
"key_c":[{"value_a":10,"value_b":7},{"value_a":10,"value_b":7}]
}'
You see, key_b no longer holds an array, but an object! This is really annoying, as I plan to create a JavaScript script that iterates through the arrays, adding one DOM element (div) for each of the objects.
Why does this happen? Is there any way to keep them as arrays, even if there"s only one object in the array?
I"ve tried:
if(is_object($object["key_b"]))
{
$a = array();
$a[] = array_values($object["key"]);
$object["key"] = $a;
}
and
if(is_object($object["key_b"]))
{
$a = array();
$a[0] = array_values($object["key"]);
$object["key"] = $a;
}
But it seems like nothing prevents json_encode from affecting the JSON in this way.
It"s not hard to get around this - but it means adding one check per key (checking whether it"s an array or value), which is particularly time consuming as the data extract that comes through is really big.
Any advice would be greatly appreciated.
EDIT: changed ' to " in JSON - though, this is only an example I just wrote to show the structure.
EDIT: I'm using references to cut my coding time down, if this changes anything?:
$t =& $object["key_b"];
if(is_object($t))
{
$a = array();
$a[] = $t;
$t = $a;
}

It appears using is_object() on a key of an associative array will not return true. I just knocked up this example, to prove this:
$json = json_decode('{"job_details":{"a":[{"x":5},{"y":23},{"z":18}],"b":{"x":19},"c":[{"x":64},{"y":132}]}}',true);
echo(json_encode($json)."<br><br>");
$t =& $json["job_details"]["b"];
if(is_object($t))
{
$a = array();
$a[] = $t;
$t = $a;
echo("IS OBJECT<br><br>");
}
echo(json_encode($json));
I will find another means of checking what value is held within an associative arrays key.
I was actually trying to find whether the value in the key is an associative array or not (not an object) - I just didn't realise they were different in PHP.
I must just use this custom function:
function is_assoc($array)
{
return (bool)count(array_filter(array_keys($array), 'is_string'));
}
From: How to check if PHP array is associative or sequential?
Which returns true if the value is an associative array.

Related

PHP JSON Arrays within an Array

I have a script that loops through and retrieves some specified values and adds them to a php array. I then have it return the value to this script:
//Returns the php array to loop through
$test_list= $db->DatabaseRequest($testing);
//Loops through the $test_list array and retrieves a row for each value
foreach ($test_list as $id => $test) {
$getList = $db->getTest($test['id']);
$id_export[] = $getList ;
}
print(json_encode($id_export));
This returns a JSON value of:
[[{"id":1,"amount":2,"type":"0"}], [{"id":2,"amount":25,"type":"0"}]]
This is causing problems when I try to parse the data onto my android App. The result needs to be something like this:
[{"id":1,"amount":2,"type":"0"}, {"id":2,"amount":25,"type":"0"}]
I realize that the loop is adding the array into another array. My question is how can I loop through a php array and put or keep all of those values into an array and output them in the JSON format above?
of course I think $getList contains an array you database's columns,
use
$id_export[] = $getList[0]
Maybe can do some checks to verify if your $getList array is effectively 1 size
$db->getTest() seems to be returning an array of a single object, maybe more, which you are then adding to a new array. Try one of the following:
If there will only ever be one row, just get the 0 index (the simplest):
$id_export[] = $db->getTest($test['id'])[0];
Or get the current array item:
$getList = $db->getTest($test['id']);
$id_export[] = current($getList); //optionally reset()
If there may be more than one row, merge them (probably a better and safer idea regardless):
$getList = $db->getTest($test['id']);
$id_export = array_merge((array)$id_export, $getList);

Create JSON using PHP with data which contains JSON

How can I create JSON using PHP with data which contains JSON without including a bunch of escape characters in the JSON, and without converting JSON first to an array or object, and then back to JSON?
<?php
/*
GIVEN: Data from DB contained in array $a.
I know that sometimes JSON shouldn't be stored in a DB, but please assume this is a good case for doing so.
*/
$a[0]=json_encode(['a'=>5,'b'=>'hello']);
$a[1]=json_encode(['a'=>2,'b'=>'how are you']);
$a[2]=json_encode(['a'=>7,'b'=>'goodby']);
$o=[
['x'=>321,'y'=>$a[0]],
['x'=>123,'y'=>$a[1]],
['x'=>111,'y'=>$a[2]],
];
echo('<pre>'.print_r($o,1).'</pre>');
echo(json_encode($o));
/*
Undesired result containing a bunch of escape characters. Granted, they are benign, however, will increase network trafic.
[{"x":321,"y":"{\"a\":5,\"b\":\"hello\"}"},{"x":123,"y":"{\"a\":2,\"b\":\"how are you\"}"},{"x":111,"y":"{\"a\":7,\"b\":\"goodby\"}"}]
*/
$o=[
['x'=>321,'y'=>json_decode($a[0])],
['x'=>123,'y'=>json_decode($a[1])],
['x'=>111,'y'=>json_decode($a[2])],
];
echo('<pre>'.print_r($o,1).'</pre>');
echo(json_encode($o));
/*
Desired result, however, is there a more efficient way to do this?
[{"x":321,"y":{"a":5,"b":"hello"}},{"x":123,"y":{"a":2,"b":"how are you"}},{"x":111,"y":{"a":7,"b":"goodby"}}]
*/
No, there is no faster way then to decode, mutate and encode again.
You could however combine the decoding code closely with your database queries. If you have a data model class, you would do the decoding there, so that the code that calls this service will never see the JSON, but always the decoded data.
Then, again, in the data model, where you write to the database, you would perform the JSON encoding at the last moment.
This way you hide the JSON factor behind the walls of the data layer, and the rest of the application will not have to be aware of that.
Manipulating JSON directly
Another solution consists of writing a library that can juggle with JSON, giving possibilities to set values inside JSON without the caller having to decode/encode. This option requires much more code (or you could find an existing library), and so it is not really my first recommendation. But here is a naive example of a function that could exist in that library:
function json_set($json, $path, $value) {
$arr = json_decode($json, true);
$ref =& $arr;
$props = explode("/", $path);
$finalProp = array_pop($props);
foreach ($props as $key) {
if (!isset($ref[$key])) $ref[$key] = [];
$ref =& $ref[$key];
}
$obj = json_decode($value);
$ref[$finalProp] = $obj ? $obj : $value;
return json_encode($arr);
}
This allows you to provide an existing JSON string, a path pointing to a certain spot inside that JSON, and a value that should be put there. That value could itself also be JSON.
Here is how you would use it in your case, given the JSON values in $a which you got from the database:
$o=json_encode([
['x'=>321],
['x'=>123],
['x'=>111],
]);
$o = json_set($o, '0/y', $a[0]);
$o = json_set($o, '1/y', $a[1]);
$o = json_set($o, '2/y', $a[2]);
echo $o;
Output:
[{"x":321,"y":{"a":5,"b":"hello"}},
{"x":123,"y":{"a":2,"b":"how are you"}},
{"x":111,"y":{"a":7,"b":"goodby"}}]

php change the name to construct an associative array

Is it possible in php to change the name used to create an associative array? I am using mongo in php but it's getting confusing using array() in both cases of indexed arrays and associative arrays. I know you can do it in javascript by stealing the Array.prototype methods but can it be done in php my extending the native object? it would be much easier if it was array() and assoc() they would both create the same thing though.
EDIT -------
following Tristan's lead, I made this simple function to easily
write in json in php. It will even take on variable from within
your php as the whole thing is enclosed in quotes.
$one = 'newOne';
$json = "{
'$one': 1,
'two': 2
}";
// doesn't work as json_decode expects quotes.
print_r(json_decode($json));
// this does work as it replaces all the single quotes before
// using json decode.
print_r(jsonToArray($json));
function jsonToArray($str){
return json_decode(preg_replace('/\'/', '"', $str), true);
}
In PHP there is no "name used to create an associative array" or "name used to create an indexed array". PHP Arrays are ordered maps like in many other scripting languages.
This means that you can use an array whichever way you please.
If you wanted an indexed array..
$indexedArray = array();
$indexedArray[] = 4; // Append a value to the array.
echo $indexedArray[0]; // Access the value at the 0th index.
Or even..
$indexedArray = [0, 10, 12, 8];
echo $indexedArray[3]; // Outputs 8.
If you want to use non integer keys with your array, you simply specify them.
$assocArray = ['foo' => 'bar'];
echo $assocArray['foo']; // Outputs bar.

PHP/JSON Array - From iTunes

I've just started out learning PHP/JSON and I've kind of worked out how to output an array from an json file. My aim is to output all the album titles in <li>'s (in this case they are called collectionName in the json file). I think I maybe going about it the wrong way though.
$artistId = '644708';
$otherAlbumsURL = 'http://itunes.apple.com/lookup?id='. $artistId .'&entity=album';
$a = (array)json_decode(file_get_contents($otherAlbumsURL));
var_dump($a);
If you want an array, just use:
$a = json_decode(file_get_contents($otherAlbumsURL), true);
var_dump($a);
Setting the second parameter in json_decode to TRUE will give you an associative array instead of an object.
Judging from the response of the URL, you'll need to loop through the result like this in order to get any available collection names (the first array element doesn't contain a collection name because it is information about the artist. i.e. it isn't an album):
$artistInfo = $a['results'][0]; //Assign artist info to its own variable.
unset($a['results'][0]); //Delete artist info from the array.
//Loop through the results
foreach($a['results'] as $result){
//$result['collectionName'] has the collection name.
echo $result['collectionName'] . '<br>';
}

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