如何从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

Answers:


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"
);

更新:
代替,php://memory您还可以将php://output用作文件描述符,并取消查找等:

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
为什么不echo直接在循环中生成CSV行?
Alex Shesterov

1
@AlexShesterov,主要原因是fputcsv()不返回生成的行,它需要一个文件描述符来写入。即使内存受限,您也可以在每次迭代时倒带,写入,清除缓冲区。或者只是使用一个真正的临时文件。
complex857

@ complex857如何为csv添加列标题?
user2302780

@ user2302780:您只需在数据前添加一行列名即可。您可以将数据数组中的键用于类似的东西$data = array_merge(array(array_keys($data[0])), $data);
complex857

1
@JoseRojas是可以预期的,因为一旦您将某些东西放在电线上(用php输出的东西在概念上意味着意思),您将无法再继续讨论了。要使用,php://output请参阅第二个更新的代码示例。
complex857

18

我没有足够的声誉来回复@ complex857解决方案。它很棒,但是我不得不补充;在Content-Disposition标头的末尾。如果没有它,浏览器将在文件名的末尾添加两个破折号(例如,文件不是“ export.csv”,而是另存为“ export.csv--”)。可能会尝试在标题行的末尾清理\ r \ n。

正确的行应如下所示:

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

如果CSV中包含UTF-8字符,则必须通过更改Content-Type行将编码更改为UTF-8:

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

另外,我发现使用rewind()代替fseek()更为优雅:

rewind($f);

感谢您的解决方案!


2
我本人从未体验过--文件名结尾处的结尾,但是我已经更新了答案(为什么不提交编辑?)
complex857 2014年

14

尝试... csv下载。

<?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();
?>

如果字段值包含,将中断,这就是为什么我更喜欢tsv(tab比少见,我们可以替换它或其他东西)
Oriadam

13

那就是我在项目中使用的功能,它可以按预期工作。

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
我很难尝试在wordpress send_headers挂钩中实现它,因为每次将所有当前页面html添加到csv文件的末尾时都需要cos。这些答案使我感到震惊,但是我没有缓冲操作就使用它。
Oleg Apanovich

干净的输出缓冲区为我解决了以下问题:在使用这些代码之前,在形成的文件的开头和结尾处的行都是空行。
Sharunas Bielskis

8

使用以下代码将php数组转换为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

如果您使用的是精确的数组结构,那么我们可以遍历以下元素:

$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);

那是做到这一点的一种方法……您可以手动完成,但是这种方法更快,更容易理解和阅读。

然后,您可以对header进行管理,complex857会执行这些操作以吐出文件。然后,如果不再需要它,可以使用unlink()删除该文件,也可以根据需要将其保留在服务器上。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.