Используйте Laravel для загрузки таблицы в формате CSV


Я пытаюсь экспортировать таблицу базы данных, используя 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.

Author: Marcin Nabiałek, 2014-10-01

7 answers

Почти все в порядке, кроме этой строки:

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

Вы должны изменить эту строку на:

return Response::download($filename, 'tweets.csv', $headers);
 19
Author: Marcin Nabiałek, 2014-10-01 17:23:01

Я наткнулся здесь, пытаясь понять, было ли что-то встроено в Laravel по умолчанию - ответы на этот вопрос меня немного беспокоят. Я согласен с @andré-daniel в том, что правильный метод заключается в том, чтобы сначала не записывать файл, но его реализация заключается в том, чтобы вручную собирать значения, что приведет к сбою, если какое-либо значение будет содержать кавычки, пробелы и т.д.

Это более надежное решение, использующее Response::stream Laravel и fputcsv php для правильного форматирования каждой строки (будут экранированы кавычки и необходимые кавычки струнные. см. 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);
}
 54
Author: Erik, 2015-05-22 18:55:51

РЕДАКТИРОВАТЬ: смотрите этот ответ для лучшего решения; Я сохраню свой ответ ниже, но обратите внимание, что в нем есть такие проблемы, как отсутствие экранирования значений и использование необоснованного объема памяти при создании больших файлов.

Вы без необходимости создаете файл на диске; это вызывает ввод-вывод на диск и вызовет проблемы, если два человека запросят этот URL-адрес одновременно (два экземпляра платформы будут записывать в один и тот же файл, и произойдет что-то плохое, например, обслуживание поврежденного файла или сбой с исключением).

Используйте это вместо:

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);
});
 14
Author: Community, 2017-05-23 12:34:37

Вот полный код для загрузки 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);
 1
Author: M Arfan, 2018-03-15 09:53:12

Все выглядит хорошо, кроме этой строки:

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

$handle не указывает на правильный путь к файлу. Это должен быть полный путь к файлу tweets.csv, например:

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

Где $file должно быть что-то вроде $file = '/path/to/download/tweets.csv'

 0
Author: virtuexru, 2014-10-01 17:14:58
   public function export()
{
    $people = Person::all();

    $csv = \League\Csv\Writer::createFromFileObject(new \SplTempFileObject());

    $csv->insertOne(\Schema::getColumnListing('people'));

    foreach ($people as $person) {
        $csv->insertOne($person->toArray());
    }

    $csv->output('people.csv');
}
 0
Author: Gowthaman, 2016-09-28 10:25:10

Попробуйте это

 $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');
 0
Author: Tejendra Pareek, 2017-01-17 06:27:19