I must get some data via API using curl and save it to a CSV file. Example JSON data set I'm getting when connected via API:
{
"id": 24598942,
"created_at": "2021-08-16T15:59:25.345+01:00",
"success": true,
"payment_amount": 90,
"invoice_ids": [
1646569091
],
"ref_num": "2858",
"payment_method": "BACS"
}
My PHP code:
$url = 'https://example.com/?page='.$x;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $auth_key_here));
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$query = curl_exec($curl);
curl_close($curl);
$decoded = json_decode($data, true);
if ($x == 1) {
$fp = fopen($csv, 'w');
fputcsv($fp, array_keys($decoded[0]));
fclose($fp);
}
$fp2 = fopen($csv, 'a');
foreach ($decoded as $fields) {
fputcsv($fp2, array_flatten($fields));
$row_count++;
}
fclose($fp2);
function array_flatten($nonFlat) {
$flat = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($nonFlat)) as $k=>$v) {
$flat[$k] = $v;
}
return $flat;
}
This gives me "invoice_ids" array flatten so I can see actual data in CSV file rather than "Array" word. But some records contain multiple invoice ids in array:
{
"id": 21016112,
"created_at": "2020-08-17T16:00:55.552+01:00",
"success": true,
"payment_amount": 90,
"invoice_ids": [
1646540900,
1646277088
],
"ref_num": "ZN905TNVCNGQY",
"payment_method": "Credit Card"
}
This messes up CSV file by moving some data into the wrong columns, as depicted here: csv file
How to alter the PHP code so the flat array with multiple invoice ids fit to a single column in CSV file?
In this case you don't want to flatten each row because it has a fixed number of keys that match the number of columns in the CSV. Instead, if any of the CSV field values are an array, you want to flatten those into a string, otherwise, preserve it as is.
Here's code to do that using array_walk()
that will change any column values that are arrays to a comma separated string:
foreach ($decoded as $fields) {
array_walk($fields, function(&$value, $key) {
if (is_array($value)) {
$value = join(',', $value);
}
});
fputcsv($fp2, $fields);
$row_count++;
}
fclose($fp2);
In the case of your example, after running it through array_walk
, it will become:
array(7) {
["id"]=>
int(21016112)
["created_at"]=>
string(29) "2020-08-17T16:00:55.552+01:00"
["success"]=>
bool(true)
["payment_amount"]=>
int(90)
["invoice_ids"]=>
string(21) "1646540900,1646277088"
["ref_num"]=>
string(13) "ZN905TNVCNGQY"
["payment_method"]=>
string(11) "Credit Card"
}