3

I am trying to dynamically create a downloadable csv file from within WordPress. The data to be included is correct, and the file is created for download successfully. However, the created csv file includes the template HTML output.

How can the data be output, without the HTML from the template?

Here is the function. The arrays are correctly populated with a sql query, but the results are identical to this.

function exportAsCSV (  ) {
  $csv = '';
  $header_array = array('Header 1', 'Header 2', 'Header 3');
  $data_array = array(
    array('Row 1 A', 'Row 1 B', 'Row 1 C'),
    array('Row 2 A', 'Row 2 B', 'Row 2 C'), 
  ); 

  $csv .= implode(', ', $header_array);
  $csv .= '\n';

  foreach($data_array as $row){
    $csv .= implode(', ', $row);
    $csv .= '\n';  
  } 


    $now = gmdate('D, d M Y H:i:s') . ' GMT';

    header('Content-Type: text/csv');
    header('Expires: ' . $now);

    header('Content-Disposition: attachment; filename="data.csv"');
    header('Pragma: no-cache'); 

    echo $csv; 
    exit();
}

The function is called as so:

if(isset($_GET['export_data'])){
  ob_end_clean();   
  exportAsCSV();
} 
0

3 Answers 3

3

To make this safer, you could clear the output buffer before sending anything to it. After that, you can start sending data to the output buffer, and flush it before closing the data stream. Something like this:

    function get_csv($columns_headers, $data) {
        
        $filename = "php://output";

        ob_clean(); //empty the output buffer 
        ob_start();  //and start a new one
        
        header('Pragma: public');
        header('Expires: 0' );
        header('Cache-Control: no-cache, must-revalidate');
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="'.'data.csv"');

        $outstream = fopen($filename, 'r+')  or die("Error opening php://output");
        
        fputcsv( $outstream , $columns_headers );

        foreach($data as $item)
            fputcsv($outstream,$item);
        
        ob_flush();  //send the whole buffer
        fclose($outstream) or die("Error closing php://output");    
        //all done
        die();

    }
Sign up to request clarification or add additional context in comments.

1 Comment

This is the correct answer, to a decade old question lol
1

I figured it out. More levels of output buffering. Now, I call ob_get_level() to determine how many times to ob_end_clean(). No more extra HTML in the output.

Comments

0

I had the same issue in WordPress. This worked for me; run this near the beginning of your function:

    foreach (range(0, ob_get_level()) as $i)
    {
        ob_end_clean();
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.