katie hudson
katie hudson

Reputation: 2893

Stream response to download CSV file

I am trying to stream a large CSV from the server. I load a JSON file, convert it to an array, and then process it as a CSV. From the frontend, I am calling the following on a button click

downloadCSVData() {
    axios({
        url: '/downloadCSVData',
        method: 'GET'
    }).then((response) => {
        console.log(response)
    });
}

And then this function does the following

public function downloadCSVData()
{
    //load JSON file
    $data = file_get_contents($file_path, true);

    //Convert file to array
    $array = json_decode($data, true);

    $headers = [
        'Cache-Control'       => 'must-revalidate, post-check=0, pre-check=0'
        ,   'Content-type'        => 'text/csv'
        ,   'Content-Disposition' => 'attachment; filename=galleries.csv'
        ,   'Expires'             => '0'
        ,   'Pragma'              => 'public'
    ];

    $response = new StreamedResponse(function() use($array){
        // Open output stream
        $handle = fopen('php://output', 'w');

        // Add CSV headers
        fputcsv($handle, array_keys($array['element'][0]), ',');

        foreach ($array['element'] as $key => $row) {
            fputcsv($handle, $row);
        }

        // Close the output stream
        fclose($handle);
    }, 200, $headers);

    return $response->send();
}

Now on the frontend, within the console, I can see the reponse being printed the way it needs to be. From my understanding however, the backend should trigger the file to be downloaded which is not happening.

Am I missing something here, how can I get this downloaded on the frontend as a physical file?

Thanks

Upvotes: 0

Views: 2018

Answers (1)

matticustard
matticustard

Reputation: 5149

If you visited the URL directly, your PHP settings should work to force a download. But you are already in a fully loaded HTML page, so you need to use the <iframe> trick to get the file to download. This will allow the browser to receive the incoming data as if you've opened a new browser window.

Try changing your download function to this:

downloadCSVData() {
    $('<iframe />')
        .attr('src', '/downloadCSVData')
        .hide()
        .appendTo('body');
}

Upvotes: 1

Related Questions