简体   繁体   中英

Associative array to CSV where columns are dynamic

Given an array such as this:

[
    [
        'first_name' => 'Bill',
        'last_name' => 'Johnson',
        'telephone' => '123-456-7890'
    ],
    [
        'first_name' => 'Kurtis',
        'last_name' => 'Wild',
        'telephone' => '321-654-0987'
    ],
    [
        'first_name' => 'Jane',
        'last_name' => 'Doe',
        'email' => 'janedoe@gmail.com'
    ]
]

I need to be able to write a CSV like so:

+------------+-----------+--------------+-------------------+
| first_name | last_name |  telephone   |       email       |
+------------+-----------+--------------+-------------------+
| Bill       | Johnson   | 123-456-7890 |                   |
| Kurtis     | Wild      | 321-654-0987 |                   |
| Jane       | Doe       |              | janedoe@gmail.com |
+------------+-----------+--------------+-------------------+

The difficult part is that the telephone and email columns are dynamic. They exist for some rows but not others, and there can be any number of these fields that exist only on a subset of rows. All of the rows that do share a certain field need to have that field in the same column positioning. The rows that do not have this field should just have empty cells.

I guess what I'm looking for is a generic way to take an associative array as shown above and dump out a string representing a CSV that uses the array keys as headers, keeping in mind they will not match across rows.

I have already tried passing such an array into fgetcsv() , and also tried the league/csv package, but neither of these support this. Does anybody know a library that can do this, or perhaps even just a function that can take this type of array and spit out a correct CSV?

A bunch of foreach loops will work if you want to keep it dynamic:

# Create a key storage array
$cols   =   [];
foreach($arr as $row) {
    foreach($row as $k => $v) {
        if(!in_array($k, $cols))
            $cols[$k] =   '';
    }
}
# Loop the main array again and merge the storage array
foreach($arr as $k => $row) {
    $arr[$k]    =   array_merge($cols, $row);
}

Gives you:

Array
(
    [0] => Array
        (
            [first_name] => Bill
            [last_name] => Johnson
            [telephone] => 123-456-7890
            [email] => 
        )

    [1] => Array
        (
            [first_name] => Kurtis
            [last_name] => Wild
            [telephone] => 321-654-0987
            [email] => 
        )

    [2] => Array
        (
            [first_name] => Jane
            [last_name] => Doe
            [telephone] => 
            [email] => janedoe@gmail.com
        )

)

If you want to just manually create the reference array, you can easily merge a blank array with the populated array and get a mixed array:

$cols   =   [
    'first_name' => '',
    'last_name' => '',
    'email' => '',
    'telephone' => ''
];

foreach($arr as $k => $row) {
    $arr[$k]    =   array_merge($cols, $row);
}

Gives you:

Array
(
    [0] => Array
        (
            [first_name] => Bill
            [last_name] => Johnson
            [email] => 
            [telephone] => 123-456-7890
        )

    [1] => Array
        (
            [first_name] => Kurtis
            [last_name] => Wild
            [email] => 
            [telephone] => 321-654-0987
        )

    [2] => Array
        (
            [first_name] => Jane
            [last_name] => Doe
            [email] => janedoe@gmail.com
            [telephone] => 
        )
)

EDIT:

I am not sure if you needed an array to CSV function, but here's just a quick one:

function downloadCSV($rows)
{
    ob_start();
    $fp = fopen('php://output', 'w');
    foreach ($rows as $fields) {
        fputcsv($fp, $fields);
    }
    fclose($fp);
    $str    =   ob_get_contents();
    ob_end_clean();
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.date('YmdHis').'file.csv"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: '.strlen($str));
    echo $str;
    exit;
}

So after you have your array from one of the above-mentioned methods, just run this function before any other browser output:

# $arr being your array of course
downloadCSV($arr);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM