185

Let's say I have a database.... is there a way I can export what I have from the database to a CSV file (and text file [if possible]) via PHP?

test
  • 17,706
  • 64
  • 171
  • 244

10 Answers10

365

I personally use this function to create CSV content from any array.

function array2csv(array &$array)
{
   if (count($array) == 0) {
     return null;
   }
   ob_start();
   $df = fopen("php://output", 'w');
   fputcsv($df, array_keys(reset($array)));
   foreach ($array as $row) {
      fputcsv($df, $row);
   }
   fclose($df);
   return ob_get_clean();
}

Then you can make your user download that file using something like:

function download_send_headers($filename) {
    // disable caching
    $now = gmdate("D, d M Y H:i:s");
    header("Expires: Tue, 03 Jul 2001 06:00:00 GMT");
    header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
    header("Last-Modified: {$now} GMT");

    // force download  
    header("Content-Type: application/force-download");
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");

    // disposition / encoding on response body
    header("Content-Disposition: attachment;filename={$filename}");
    header("Content-Transfer-Encoding: binary");
}

Usage example:

download_send_headers("data_export_" . date("Y-m-d") . ".csv");
echo array2csv($array);
die();
Ryan Griggs
  • 2,457
  • 2
  • 35
  • 58
Alain Tiemblo
  • 36,099
  • 17
  • 121
  • 153
  • 2
    on local server it's working, but in distant one it display a new page with content and no download window (sorry for my english) – khaled_webdev Dec 28 '12 at 08:27
  • 3
    There may be several reasons for errors, the simplest way to find them is to look at your apache error.log file. – Alain Tiemblo Dec 28 '12 at 18:01
  • I'm attempting to use this example and what I'm getting in the CSV is my full page source HTML instead of the results of the array2csv() function? – Ben Sullins Jun 06 '13 at 16:49
  • 10
    You need to put a `die();` call just after `echo array2csv();`, will edit my answer. Be sure to generate your csv before outputting something in your page. – Alain Tiemblo Jun 06 '13 at 17:29
  • Ah, I missed where this had to be on a page all it's own. That makes sense now, thanks! – Ben Sullins Jun 06 '13 at 19:20
  • Am trying it with WordPress and getting warning: `Cannot modify header information - headers already sent`. Any suggestion appreciated. – Frank Sep 17 '13 at 13:09
  • 2
    @ring0 I guess putting the past date in header disables the page caching, look at 2nd example http://php.net/manual/en/function.header.php – Abhishek Madhani Oct 22 '14 at 13:50
  • Out of another (rather technical) curiosity - what exactly does the `download_send_headers` function do? Just with some simple words? – Milkncookiez Oct 07 '15 at 13:55
  • 3
    Gives mime types to your browser so you'll get a download modal instead of the csv rendered in the current window. – Alain Tiemblo Oct 07 '15 at 14:15
  • @AlainTiemblo Let's say you wanted to grab all the emails in your database and put them in a CSV. How would you start up a query to grab the emails and turn them into an array so you can use this "array2csv" function? – Snowball_ Jan 28 '16 at 19:58
  • @AlainTiemblo Script is also adding some HTML data in csv file, can you kindly guide me how can i remove it. – Ayaz Ali Shah May 16 '16 at 10:43
  • 1
    To me had enough to set these headers: *header('Content-type: application/csv');* *header('Content-Disposition: attachment; filename=out.csv');* – outdead Oct 27 '16 at 12:53
37

You can export the date using this command.

<?php

$list = array (
    array('aaa', 'bbb', 'ccc', 'dddd'),
    array('123', '456', '789'),
    array('"aaa"', '"bbb"')
);

$fp = fopen('file.csv', 'w');

foreach ($list as $fields) {
    fputcsv($fp, $fields);
}

fclose($fp);
?>

First you must load the data from the mysql server in to a array

ynh
  • 2,919
  • 1
  • 19
  • 18
  • 11
    Or, you can do the fputcsv() inside a standard fetch assoc loop and plop it down straight out of the returned results. – DampeS8N Nov 22 '10 at 19:38
  • 12
    @DampeS8N, +1 for the use of "plop it down straight out" in a sentence. – AnchovyLegend Dec 31 '13 at 19:31
  • 2
    this is copied without attribution from the PHP manual for [fputcsv](https://www.php.net/manual/en/function.fputcsv.php) – BenK Jul 11 '19 at 17:54
15

Just for the record, concatenation is waaaaaay faster (I mean it) than fputcsv or even implode; And the file size is smaller:

// The data from Eternal Oblivion is an object, always
$values = (array) fetchDataFromEternalOblivion($userId, $limit = 1000);

// ----- fputcsv (slow)
// The code of @Alain Tiemblo is the best implementation
ob_start();
$csv = fopen("php://output", 'w');
fputcsv($csv, array_keys(reset($values)));
foreach ($values as $row) {
    fputcsv($csv, $row);
}
fclose($csv);
return ob_get_clean();

// ----- implode (slow, but file size is smaller)
$csv = implode(",", array_keys(reset($values))) . PHP_EOL;
foreach ($values as $row) {
    $csv .= '"' . implode('","', $row) . '"' . PHP_EOL;
}
return $csv;
// ----- concatenation (fast, file size is smaller)
// We can use one implode for the headers =D
$csv = implode(",", array_keys(reset($values))) . PHP_EOL;
$i = 1;
// This is less flexible, but we have more control over the formatting
foreach ($values as $row) {
    $csv .= '"' . $row['id'] . '",';
    $csv .= '"' . $row['name'] . '",';
    $csv .= '"' . date('d-m-Y', strtotime($row['date'])) . '",';
    $csv .= '"' . ($row['pet_name'] ?: '-' ) . '",';
    $csv .= PHP_EOL;
}
return $csv;

This is the conclusion of the optimization of several reports, from ten to thousands rows. The three examples worked fine under 1000 rows, but fails when the data was bigger.

Axel A. García
  • 683
  • 9
  • 21
11

Works with over 100 lines, if you specify the size of the file in the headers simple call the get() method in your own class

function setHeader($filename, $filesize)
{
    // disable caching
    $now = gmdate("D, d M Y H:i:s");
    header("Expires: Tue, 01 Jan 2001 00:00:01 GMT");
    header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
    header("Last-Modified: {$now} GMT");

    // force download  
    header("Content-Type: application/force-download");
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");
    header('Content-Type: text/x-csv');

    // disposition / encoding on response body
    if (isset($filename) && strlen($filename) > 0)
        header("Content-Disposition: attachment;filename={$filename}");
    if (isset($filesize))
        header("Content-Length: ".$filesize);
    header("Content-Transfer-Encoding: binary");
    header("Connection: close");
}

function getSql()
{
    // return you own sql
    $sql = "SELECT id, date, params, value FROM sometable ORDER BY date;";
    return $sql;
}

function getExportData()
{
    $values = array();

    $sql = $this->getSql();
    if (strlen($sql) > 0)
    {
        $result = dbquery($sql); // opens the database and executes the sql ... make your own ;-) 
        $fromDb = mysql_fetch_assoc($result);
        if ($fromDb !== false)
        {
            while ($fromDb)
            {
                $values[] = $fromDb;
                $fromDb = mysql_fetch_assoc($result);
            }
        }
    }
    return $values;
}

function get()
{
    $values = $this->getExportData(); // values as array 
    $csv = tmpfile();

    $bFirstRowHeader = true;
    foreach ($values as $row) 
    {
        if ($bFirstRowHeader)
        {
            fputcsv($csv, array_keys($row));
            $bFirstRowHeader = false;
        }

        fputcsv($csv, array_values($row));
    }

    rewind($csv);

    $filename = "export_".date("Y-m-d").".csv";

    $fstat = fstat($csv);
    $this->setHeader($filename, $fstat['size']);

    fpassthru($csv);
    fclose($csv);
}
9

I recommend parsecsv-for-php to get around a number any issues with nested newlines and quotes.

Franz Holzinger
  • 913
  • 10
  • 20
StigM
  • 711
  • 6
  • 12
6

Just like @Dampes8N said:

$result = mysql_query($sql,$conecction);
$fp = fopen('file.csv', 'w');
while($row = mysql_fetch_assoc($result)){
    fputcsv($fp, $row);
}
fclose($fp);

Hope this helps.

James S
  • 3,355
  • 23
  • 25
roots
  • 61
  • 1
  • 2
6

pre-made code attached here. you can use it by just copying and pasting in your code:

https://gist.github.com/umairidrees/8952054#file-php-save-db-table-as-csv

Umair Idrees
  • 1,380
  • 1
  • 10
  • 6
5
<?php 
      
          // Database Connection
          include "includes/db/db.php";
           
          
              $query = mysqli_query($connection,"SELECT * FROM team_attendance JOIN team_login ON   
   team_attendance.attendance_user_id=team_login.user_id where   
   attendance_activity_name='Checked-In' order by   
   team_attendance.attendance_id ASC"); // Get data from Database from  
   demo table
           
           
              $delimiter = ",";
              $filename = "attendance" . date('Ymd') . ".csv"; // Create file name
               
              //create a file pointer
              $f = fopen('php://memory', 'w'); 
               
              //set column headers
              $fields = array('ID', 'Employee Name', 'Check In Time', 'Check Out Time', 'Date');
              fputcsv($f, $fields, $delimiter);
               
              //output each row of the data, format line as csv and write to file pointer
              while($row = $query->fetch_assoc()){
                   $date=date('d-m-Y',$row['attendance_date']);
                  $lineData = array($row['attendance_id'], $row['user_name'], $row['attendance_time'],   
   $row['check_out_time'],$date);
                  fputcsv($f, $lineData, $delimiter);
              }
               
              //move back to beginning of file
              fseek($f, 0);
               
              //set headers to download file rather than displayed
              header('Content-Type: text/csv');
              header('Content-Disposition: attachment; filename="' . $filename . '";');
               
              //output all remaining data on a file pointer
              fpassthru($f);
              ?>
Anupam Verma
  • 49
  • 1
  • 3
0
        $data .= "Your Data";

        if ($data == ""):
            $data = "\nNo Records Found!\n";
            $file="call_sign_records.txt";

        header("Content-type: application/octet-stream"); 
        header("Content-Disposition: attachment; filename=$file"); 
        header("Pragma: no-cache"); 
        header("Expires: 0"); 
        print "$data";
endif;
Snuriya
  • 1
  • 1
  • Welcome to SO! Please don't post code-only answers but add a little textual explanation about how and why your approach works and what makes it different from the other answers given. You can find out more at our ["How to write a good answer"](https://stackoverflow.com/help/how-to-answer) page. – ahuemmer Dec 23 '22 at 08:57
0

You can use the native PHP function "fputcsv". With CSV it's easy.

<?php

// Connect to the database
$conn = new PDO('mysql:host=localhost;dbname=mydatabase', $username, $password);

// Query the database to get the data
$result = $conn->query('SELECT * FROM table');

// Open a file for writing
$fp = fopen('table.csv', 'w');

// Loop through the result set
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
    // Write the data to the file
    fputcsv($fp, $row);
}

// Close the file
fclose($fp);

With txt format it's more complicated because you didn't say what and how you wanna see it. So you have to do introduce your transformer.

A simple example here. It will write rows as lines in the file.

<?php

// Connect to the database
$conn = new PDO('mysql:host=localhost;dbname=mydatabase', $username, $password);

// Query the database to get the data
$result = $conn->query('SELECT * FROM table');

// Open a file for writing
$fp = fopen('table.txt', 'w');

// Loop through the result set
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
    // Transform it here as you want
    // Write the data to the file
    fwrite($fp, implode(',', $row) . "\n");
}

// Close the file
fclose($fp);
madlopt
  • 415
  • 4
  • 7