Use Laravel to Download table as CSV

梦想与她 提交于 2019-12-17 17:39:21

问题


I am trying to export a database table using Laravel as a csv file. I would like the user to be able to select the Export as CSV button and download the table as a csv file. Currently I've gotten this code but It is not working:

my button:

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

my route:

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

It returns me this error:

 The file "Resource id #154" does not exist

And I've gathered that it is because it is trying to download a file that does not exist. Is there an alternative way I can go about modifying my code in order to download as a csv.


回答1:


Almost everything is fine except this line:

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

You should change this line into:

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



回答2:


I stumbled in here trying to see if Laravel had something built in by default - the answers for this question worry me a bit. I agree with @andré-daniel that the proper method is to not write a file first, but his implementation is manually putting together the values, which would fail if any value contained quotes, spaces, etc.

This is a more robust solution, using Laravel's Response::stream and php's fputcsv to format each line properly (will escape quotes, and quote necessary strings. see http://php.net/manual/en/function.fputcsv.php for details)

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



回答3:


EDIT: see this answer for a better solution; I'll keep my answer below but note that it has issues like not escaping values and using unreasonable amounts of memory if generating large files.

You're unnecessarily creating a file on the disk; that induces disk IO and will cause issues if two people request that URL at the exact same time (two instances of the framework will write to that same file and bad stuff will happen such as serving a corrupted file or crashing with an exception).

Use this instead :

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



回答4:


Considering the current highest ranked answer this is the Laravel 5.7 CSV write, note the return changes.

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



回答5:


Everything looks good except this line:

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

$handle does not point to the correct file path. It should be the full path to tweets.csv, for example:

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

where $file should be something like $file = '/path/to/download/tweets.csv'




回答6:


Here is the complete code to download 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);



回答7:


I was following along with these examples and none of them were working for my for my code. I am attaching the code I wrote for my project as an example. This does not address the OP, just as an example guide. My data is in the form of an array of objects

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

If you noticed on my return statement I am including ->send() which generates the csv file and initializes the download. Where as ->sendContent(); just dumps the date to the screen. If you stumble across this post with the same problem I was having of the file not downloading, make sure to checkout the official documentation.

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




回答8:


try this

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


来源:https://stackoverflow.com/questions/26146719/use-laravel-to-download-table-as-csv

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!