alkhader
alkhader

Reputation: 998

Export to CSV file using PHP

I am using this code to export selected data from MySQL to CSV using PHP, I am facing a little problem that when data exported to the csv file it looks like below:

First line in its correct place, but starting from the second row data shifts to the right one space, if I open the csv file in Excel, I can see the most left cell after the first row is empty.

parts   destination 
===================     
1   9.71504E+11 
1   9.71504E+11
1   96656587662
1   9.71504E+11

This is my code :

$values =mysql_query( "SELECT parts,destination from log");

$rown = 0;
$row = array();
$row[] = 'parts';
$row[] = 'destination'."\n";
$data .= join(',', $row)."\n";

while( $row_select = mysql_fetch_assoc($values) ) {
  if($rown++==0)
    $row = array();

  $row[] = $row_select['parts'];
  $row[] = $row_select['destination']."\n";
}
$data .= join(',', $row)."\n";

$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: text/csv");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
print $data;
exit();

Would you please help?

Regards,

Upvotes: 1

Views: 2393

Answers (3)

ChrisPatrick
ChrisPatrick

Reputation: 984

The problem is in the following line

$data .= join(',', $row)."\n";

You're concatenating all the elements in $row with commas. So the destination of one row is concatenated with the parts of the next row with a comma in between, so you get something like this:

$data = $row_select['parts'] . ',' . $row_select['destination']."\n" . ',' . $row_select['parts'] etc...

The comma after the newline creates an empty cell at the beginning of the row.

UPDATE It should work with the following

while( $row_select = mysql_fetch_assoc($values)){
$row = array();
$row[] = $row_select['parts'];
$row[] = $row_select['destination']."\n";
$data .= join(',', $row);
}

Upvotes: 1

h00ligan
h00ligan

Reputation: 1481

Like @ChrisPatrick points out, the line

$data .= join(',', $row)."\n";

is causing the problem, you should move this to inside the while loop and then you'll get rid of the cell skipping.

Upvotes: 2

Berry Langerak
Berry Langerak

Reputation: 18859

First line in its correct place, but starting from the second row data shifts to the right one space, if I open the csv file in Excel, I can see the most left cell after the first row is empty.

I've found out the hard way that writing CSV is more complex than one would imagine. Take, for example, escaping the values so that the delimiter is properly escaped inside values. I've created a simple class that utilises fwritecsv( ) instead of trying to render CSV myself:

EDIT: I've changed the example to your usage scenario.

<?php
/**
 * Simple class to write CSV files with.
 * 
 * @author Berry Langerak <[email protected]>
 */
class CsvWriter {
    /**
     * The delimiter used. Default is semi-colon, because Microsoft Excel is an asshole.
     * 
     * @var string
     */
    protected $delimiter = ";";

    /**
     * Enclose values in the following character, if necessary.
     * 
     * @var string
     */
    protected $enclosure = '"';

    /**
     * Constructs the CsvWriter.
     */
    public function __construct( ) {
        $this->buffer = fopen( 'php://temp', 'w+' );
    }

    /**
     * Writes the values of $line to the CSV file.
     * 
     * @param array $line 
     * @return CsvWriter $this
     */
    public function write( array $line ) {
        fputcsv( $this->buffer, $line, $this->delimiter, $this->enclosure );
        return $this;
    }

    /**
     * Returns the parsed CSV.
     * 
     * @return string
     */
    public function output( ) {
        rewind( $this->buffer );
        $output = $this->readBuffer( );
        fclose( $this->buffer );

        return $output;
    }

    /**
     * Reads the buffer.
     * @return type 
     */
    protected function readBuffer( ) {
        $output = '';
        while( ( $line = fgets( $this->buffer ) ) !== false ) {
            $output .= $line;
        }
        return $output;
    }
}


/**
 * Example usage, in your scenario:
 */
$values = mysql_query( "SELECT parts,destination from log" );

$csv = new CsvWriter( );
$csv->write( array( 'parts', 'destination' ) ); // write header.

while( $line = mysql_fetch_assoc( $values ) ) {
    $csv->write( $line );
}

$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: text/csv");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");

print $csv->output( );

exit();

Upvotes: 3

Related Questions