PHPスクリプトからcsvファイルを作成してダウンロードする方法は?


89

私は初心者プログラマーであり、私の質問について多くのことを検索しましたが、これに関する有用な解決策やチュートリアルを見つけることができませんでした。

私の目標は、PHP配列があり、配列要素がページのリストに表示されていることです。

オプションを追加したいので、ユーザーが必要に応じて、配列要素を含むCSVファイルを作成してダウンロードできます。

これを行う方法がわかりません。私もたくさん検索しました。しかし、まだ役立つリソースを見つけることができません。

自分で実装するためのチュートリアル、ソリューション、アドバイスを教えてください。私は初心者なので、実装が簡単なソリューションを提供してください。

私の配列は次のようになります:

Array
(
    [0] => Array
        (
            [fs_id] => 4c524d8abfc6ef3b201f489c
            [name] => restaurant
            [lat] => 40.702692
            [lng] => -74.012869
            [address] => new york
            [postalCode] => 
            [city] => NEW YORK
            [state] => ny
            [business_type] => BBQ Joint
            [url] => 
        )

)

2
CSVファイルのphpExcelは少し多すぎます。php.net/ manual / en / function.fputcsv.php
Damien Pirsy 2013

配列構造を表示すると、要素をcsvに変換するためのコードが提供されます
半速

@ half-fast投稿に配列構造を追加しました
user2302780 2013

2
csvファイルに列タイトルを追加するにはどうすればよいですか?
user2302780 2013

回答:


200

配列に組み込まれているfputcsv()を使用して、配列から正しいcsv行を生成できるため、次のようにループして行を収集する必要があります。

$f = fopen("tmp.csv", "w");
foreach ($array as $line) {
    fputcsv($f, $line);
}

ブラウザに[名前を付けて保存]ダイアログを表示させるには、次のようなHTTPヘッダーを送信する必要があります(rfcでこのヘッダーの詳細を参照してください)。

header('Content-Disposition: attachment; filename="filename.csv";');

すべてを一緒に入れて:

function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
    // open raw memory as file so no temp files needed, you might run out of memory though
    $f = fopen('php://memory', 'w'); 
    // loop over the input array
    foreach ($array as $line) { 
        // generate csv lines from the inner arrays
        fputcsv($f, $line, $delimiter); 
    }
    // reset the file pointer to the start of the file
    fseek($f, 0);
    // tell the browser it's going to be a csv file
    header('Content-Type: application/csv');
    // tell the browser we want to save it instead of displaying it
    header('Content-Disposition: attachment; filename="'.$filename.'";');
    // make php send the generated csv lines to the browser
    fpassthru($f);
}

そして、あなたはそれをこのように使うことができます:

array_to_csv_download(array(
  array(1,2,3,4), // this array is going to be the first row
  array(1,2,3,4)), // this array is going to be the second row
  "numbers.csv"
);

Update:
Instead of the php://memory you can also use the php://output for the file descriptor and do away with the seeking and such:

function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$filename.'";');

    // open the "output" stream
    // see http://www.php.net/manual/en/wrappers.php.php#refsect2-wrappers.php-unknown-unknown-unknown-descriptioq
    $f = fopen('php://output', 'w');

    foreach ($array as $line) {
        fputcsv($f, $line, $delimiter);
    }
}   

2
why not echo the generated CSV lines directly in the loop?
Alex Shesterov

1
@AlexShesterov, the main reason is that fputcsv() doesn't return the generated line, it will need a file descriptor to write to. You could rewind, write, clear the buffer on every iteration though if you are memory constrained. Or just use a real temporary file instead.
complex857

@complex857 how can I add column title for the csv ?
user2302780

@user2302780: You just prefix your data with a row of column names. You can use the keys from the data-arrays with something like $data = array_merge(array(array_keys($data[0])), $data);
complex857

1
@JoseRojas that is to be expected since once you put something over the wire (that what outputting things with php means conceptually) you can't go back on that. To use php://output see the second updated code sample.
complex857

18

I don't have enough reputation to reply to @complex857 solution. It works great, but I had to add ; at the end of the Content-Disposition header. Without it the browser adds two dashes at the end of the filename (e.g. instead of "export.csv" the file gets saved as "export.csv--"). Probably it tries to sanitize \r\n at the end of the header line.

Correct line should look like this:

header('Content-Disposition: attachment;filename="'.$filename.'";');

In case when CSV has UTF-8 chars in it, you have to change the encoding to UTF-8 by changing the Content-Type line:

header('Content-Type: application/csv; charset=UTF-8');

Also, I find it more elegant to use rewind() instead of fseek():

rewind($f);

Thanks for your solution!


2
I've never experienced the -- at the end of the filenames myself, however I've updated the answer (why not just submit an edit?)
complex857

14

Try... csv download.

<?php 
mysql_connect('hostname', 'username', 'password');
mysql_select_db('dbname');
$qry = mysql_query("SELECT * FROM tablename");
$data = "";
while($row = mysql_fetch_array($qry)) {
  $data .= $row['field1'].",".$row['field2'].",".$row['field3'].",".$row['field4']."\n";
}

header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="filename.csv"');
echo $data; exit();
?>

will break if a field value contains , that's why i prefer tsv (tab is more rare than , and we can replace it or something)
oriadam

14

That is the function that I used for my project, and it works as expected.

function array_csv_download( $array, $filename = "export.csv", $delimiter=";" )
{
    header( 'Content-Type: application/csv' );
    header( 'Content-Disposition: attachment; filename="' . $filename . '";' );

    // clean output buffer
    ob_end_clean();

    $handle = fopen( 'php://output', 'w' );

    // use keys as column titles
    fputcsv( $handle, array_keys( $array['0'] ) );

    foreach ( $array as $value ) {
        fputcsv( $handle, $value , $delimiter );
    }

    fclose( $handle );

    // flush buffer
    ob_flush();

    // use exit to get rid of unexpected output afterward
    exit();
}

1
I had a hard time trying to implement it in wordpress send_headers hook, cos every time it add all current page html to the end of csv file. These answer halp me a lot, but I use it without buffer operations.
Oleg Apanovich

clean output buffer solved for me the problem that before the usage of these code rows in the beginning and at the end of the formed file were empty rows.
Sharunas Bielskis

8

Use the below code to convert a php array to CSV

<?php
   $ROW=db_export_data();//Will return a php array
   header("Content-type: application/csv");
   header("Content-Disposition: attachment; filename=test.csv");
   $fp = fopen('php://output', 'w');

   foreach ($ROW as $row) {
        fputcsv($fp, $row);
   }
   fclose($fp);

3

If you're array structure will always be multi-dimensional in that exact fashion, then we can iterate through the elements like such:

$fh = fopen('somefile.csv', 'w') or die('Cannot open the file');

for( $i=0; $i<count($arr); $i++ ){
    $str = implode( ',', $arr[$i] );
    fwrite( $fh, $str );
    fwrite( $fh, "\n" );
}
fclose($fh);

That's one way to do it ... you could do it manually but this way is quicker and easier to understand and read.

Then you would manage your headers something what complex857 is doing to spit out the file. You could then delete the file using unlink() if you no longer needed it, or you could leave it on the server if you wished.


-2

Use the following,

echo "<script type='text/javascript'> window.location.href = '$file_name'; </script>";
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.