使用Laravel将表格下载为CSV格式

时间:2014-10-01 17:06:52

标签: php csv laravel laravel-4 download

我正在尝试使用Laravel作为csv文件导出数据库表。我希望用户能够选择Export as CSV按钮并将表格下载为csv文件。目前我已经得到了这个代码,但它无法正常工作:

我的按钮:

<a href="/all-tweets-csv" class="btn btn-primary">Export as CSV</a>

我的路线:

Route::get('/all-tweets-csv', function(){

    $table = Tweet::all();
    $filename = "tweets.csv";
    $handle = fopen($filename, 'w+');
    fputcsv($handle, array('tweet text', 'screen name', 'name', 'created at'));

    foreach($table as $row) {
        fputcsv($handle, array($row['tweet_text'], $row['screen_name'], $row['name'], $row['created_at']));
    }

    fclose($handle);

    $headers = array(
        'Content-Type' => 'text/csv',
    );

    return Response::download($handle, 'tweets.csv', $headers);
});

它返回给我这个错误:

 The file "Resource id #154" does not exist

我已经收集到了,因为它正在尝试下载不存在的文件。有没有其他方法可以修改我的代码,以便下载为csv

9 个答案:

答案 0 :(得分:59)

我在这里偶然发现,试图看看Laravel是否默认内置了一些东西 - 这个问题的答案让我有点担心。我同意@andré-daniel说正确的方法是不先写一个文件,但是他的实现是手动将值组合在一起,如果任何值包含引号,空格等,则会失败。

这是一个更强大的解决方案,使用Laravel的Response::stream和php的fputcsv来正确格式化每一行(将转义引号,并引用必要的字符串。有关详细信息,请参阅http://php.net/manual/en/function.fputcsv.php

<?php

public function download()
{
    $headers = [
            'Cache-Control'       => 'must-revalidate, post-check=0, pre-check=0'
        ,   'Content-type'        => 'text/csv'
        ,   'Content-Disposition' => 'attachment; filename=galleries.csv'
        ,   'Expires'             => '0'
        ,   'Pragma'              => 'public'
    ];

    $list = User::all()->toArray();

    # add headers for each column in the CSV download
    array_unshift($list, array_keys($list[0]));

   $callback = function() use ($list) 
    {
        $FH = fopen('php://output', 'w');
        foreach ($list as $row) { 
            fputcsv($FH, $row);
        }
        fclose($FH);
    };

    return Response::stream($callback, 200, $headers);
}

答案 1 :(得分:25)

除了这一行,几乎一切都很好:

return Response::download($handle, 'tweets.csv', $headers);

您应该将此行更改为:

return Response::download($filename, 'tweets.csv', $headers);

答案 2 :(得分:16)

编辑:请参阅this answer以获得更好的解决方案;我将在下面保留我的答案,但请注意,如果生成大文件,它会出现诸如无法转义值和使用不合理的内存量等问题。

您不必要地在磁盘上创建文件;如果两个人在同一时间请求该URL,则会导致磁盘IO并导致问题(框架的两个实例将写入同一个文件,并且会发生诸如服务损坏的文件或因异常而崩溃的错误)。< / p>

请改用:

Route::get('/all-tweets-csv', function() {
    $tweets = Tweets::all();

    // the csv file with the first row
    $output = implode(",", array('tweet text', 'screen name', 'name', 'created at'));

    foreach ($tweets as $row) {
        // iterate over each tweet and add it to the csv
        $output .=  implode(",", array($row['tweet_text'], $row['screen_name'], $row['name'], $row['created_at'])); // append each row
    }

    // headers used to make the file "downloadable", we set them manually
    // since we can't use Laravel's Response::download() function
    $headers = array(
        'Content-Type' => 'text/csv',
        'Content-Disposition' => 'attachment; filename="tweets.csv"',
        );

    // our response, this will be equivalent to your download() but
    // without using a local file
    return Response::make(rtrim($output, "\n"), 200, $headers);
});

答案 3 :(得分:2)

考虑到the current highest ranked answer这是Laravel 5.7 CSV写入,请注意return的更改。

<?php

public function download()
{
    $headers = [
            'Cache-Control'       => 'must-revalidate, post-check=0, pre-check=0'
        ,   'Content-type'        => 'text/csv'
        ,   'Content-Disposition' => 'attachment; filename=galleries.csv'
        ,   'Expires'             => '0'
        ,   'Pragma'              => 'public'
    ];

    $list = User::all()->toArray();

    # add headers for each column in the CSV download
    array_unshift($list, array_keys($list[0]));

   $callback = function() use ($list) {
        $FH = fopen('php://output', 'w');
        foreach ($list as $row) { 
            fputcsv($FH, $row);
        }
        fclose($FH);
    };

    return (new StreamedResponse($callback, 200, $headers))->sendContent();
}

答案 4 :(得分:1)

除了这一行,一切看起来都很好:

return Response::download($handle, 'tweets.csv', $headers);

$handle未指向正确的文件路径。它应该是tweets.csv的完整路径,例如:

return Response::download($file, 'tweets.csv', $headers);

$file应该是$file = '/path/to/download/tweets.csv'

答案 5 :(得分:1)

以下是下载CSV的完整代码

 $headers = array(
        'Content-Type' => 'application/vnd.ms-excel; charset=utf-8',
        'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
        'Content-Disposition' => 'attachment; filename=abc.csv',
        'Expires' => '0',
        'Pragma' => 'public',
    );

$filename = "doenload.csv";
$handle = fopen($filename, 'w');
fputcsv($handle, [
    "id",
    "name"
]);

DB::table("tablename")->chunk(100, function ($data) use ($handle) {
    foreach ($data as $row) {
        // Add a new row with data
        fputcsv($handle, [
            $row->id,
            $row->name
        ]);
    }
});

fclose($handle);

return Response::download($filename, "download.csv", $headers);

答案 6 :(得分:0)

我跟随着这些示例,但没有一个为我的代码工作。我将附加为项目编写的代码作为示例。仅作为示例指南,这不涉及OP。我的数据是对象数组的形式

public function Export($data) {
    $headers = array(
        "Content-type" => "text/csv",
        "Content-Disposition" => "attachment; filename=summary.csv",
        "Pragma" => "no-cache",
        "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
        "Expires" => "0"
    );
    $columns = array('Period', 'RevenueArea', 'Subs');

    $callback = function() use ($data, $columns)
    {
        $file = fopen('php://output', 'w');
        fputcsv($file, $columns);

        foreach($data as $items) {
            fputcsv($file, array($items->PERIOD, $items->REVENUE_AREA, $items->SUBS));

        }
        fclose($file);
    };
return Response::stream($callback, 200, $headers)->send();
}

如果您在我的return语句中注意到,我包括-> send(),它会生成csv文件并初始化下载。哪里-> sendContent();只是将日期转储到屏幕上。如果您偶然遇到与我没有下载文件相同的问题,请确保签出官方文档。

https://api.symfony.com/2.3/Symfony/Component/HttpFoundation/StreamedResponse.html

答案 7 :(得分:0)

尝试一下

public function exportCsv(Request $request)
{
   $fileName = 'tasks.csv';
   $tasks = Task::all();
$headers = array(
            "Content-type"        => "text/csv",
            "Content-Disposition" => "attachment; filename=$fileName",
            "Pragma"              => "no-cache",
            "Cache-Control"       => "must-revalidate, post-check=0, pre-check=0",
            "Expires"             => "0"
        );

        $columns = array('Title', 'Assign', 'Description', 'Start Date', 'Due Date');

        $callback = function() use($tasks, $columns) {
            $file = fopen('php://output', 'w');
            fputcsv($file, $columns);

            foreach ($tasks as $task) {
                $row['Title']  = $task->title;
                $row['Assign']    = $task->assign->name;
                $row['Description']    = $task->description;
                $row['Start Date']  = $task->start_at;
                $row['Due Date']  = $task->end_at;

                fputcsv($file, array($row['Title'], $row['Assign'], $row['Description'], $row['Start Date'], $row['Due Date']));
            }

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

答案 8 :(得分:-1)

试试这个

 $file_name = "abc";
    $postStudent = Input::all();
    $ck = DB::table('loan_tags')->select('LAN')->where('liabilitiesId', $postStudent['id'])->get();
    $i = 0;
    foreach ($ck as $row) { 

                  $apps[$i]['LAN'] = $row->LAN;
                $apps[$i]['Account_number'] =   $postStudent['account_number'];
                $apps[$i]['Bank_Name'] =  $postStudent['bank_name'];
                $i++;
    }

    ob_end_clean();
    ob_start();
    Excel::create($file_name, function($excel) use($apps){
            $excel->sheet('Sheetname', function($sheet) use($apps){

               $sheet->row(1, array(
                     'LAN', 'Account number' , 'Bank Name'
                ));
                $k = 2;
                 foreach ($apps as $deta) {
                     $sheet->row($k, array($deta['LAN'],   $deta['Account_number'], $deta['Bank_Name']
                    ));
                    $k++;
                 }
            });
        })->download('xlsx');