I am trying to export results to a csv file using the following code. The export appears to work, but when I open the file, it contains the html code from the page. Any help is appreciated.

global $wpdb;
$domain = $_SERVER['SERVER_NAME'];
$table = $wpdb->prefix . "qi_project_requests";
$filename = "export.csv";
$sql = $wpdb->get_results("select * from $table");

$header_row = array(
    'Date Submitted',
    'Requestor Name'

$data_rows = array();

foreach ($sql as $data) {
    $row = array(
    $data_rows[] = $row;

$fh = @fopen( 'php://output', 'w' ); 
fprintf( $fh, chr(0xEF) . chr(0xBB) . chr(0xBF) ); 
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' ); 
header( 'Content-Description: File Transfer' ); 
header( 'Content-type: text/csv' ); 
header( "Content-Disposition: attachment; filename=$filename" ); 
header( 'Expires: 0' ); 
header( 'Pragma: public' ); 
fputcsv( $fh, $header_row ); 
foreach ( $data_rows as $data_row ) { 
    fputcsv( $fh, $data_row ); 
fclose( $fh ); 



I have a similar process to output all email addresses from the database into a downloadable txt file. It looks like this:

$xoutput =  show_subscriber_list();
$xfile = fopen('xsubscriber.txt' , "w") or die("Unable to open file!");;

$filename = 'xsubscriber.txt'; // of course find the exact filename....        
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false); // required for certain browsers 
header('Content-Type: application/pdf');

header('Content-Disposition: attachment; filename="'. basename($filename) . '";');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($filename));



The show_subscriber_list function does the SQL query of the data, getting all the data in a loop through the rows that are returned from the query. That function returns that data as a string, which is used as the content of the $filename (as in return $text_data; ).

The $filename is stored in the current folder. Then that $filename is used in the $header stuff, which gives you the file as a download/open dialog.

The important part is to 'build' the contents of the file before you do the header stuff. You could just as easily 'build' the data into a string, then do the header stuff.


Here is a function that returns the database contents as text. Called with

    $data = mysqli_query($conn, $sql);
    $output = display_data($data); // text output used in the above function

    function display_data($data) {
        $output = "";
        foreach($data as $row) {
            $output .= $row["email"] . PHP_EOL ;

    return $output;

And note, as mentioned in comment from OP, that you need to set the proper Content-Type needed for your file contents; I have it set as a PDF.

  • 1
    Thanks for the response. I tried your example, changing it to write to a csv file, but had the same issue with the html being written to the file. I also tried your example to write to a text file (had to change content type to text, you had it set to pdf for some reason), but had the same issue. For the heck of it, I commented out the code that would write the data to the files, but the html was still being written to the file somehow. Any thoughts? – Darth Mikey D May 9 '19 at 12:42
  • Forgot about the content-type set to PDF. So, that needs to be set to "Content-Type: text/html; charset=utf-8". And if HTML is still there, then output the results surrounded by a <pre></pre> so you can see exactly what you are outputting. I added to my answer to include the output loop - you can see that I am just outputting field contents in a 'for' loop. The $data parameter in the function is the output from the mysqli_query() query. – Rick Hellewell May 9 '19 at 16:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.