php Laravel 5 控制器中的 CSV 导出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32441327/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CSV export in laravel 5 controller
提问by Matthew Smart
So I have made a little ajax request to my reviewsController@export
.
所以我向我的reviewsController@export
.
Now when I console.log()
the data in my success method, the ajax response shows the correct data. However my CSV has not downloaded. So I have all the right info and have created the csv essentially.
现在,当我console.log()
在我的成功方法中输入数据时,ajax 响应显示正确的数据。但是我的 CSV 还没有下载。所以我拥有所有正确的信息,并且基本上已经创建了 csv。
I think this has possibly to do with setting the headers maybe?
我认为这可能与设置标题有关吗?
public function export()
{
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");
$reviews = Reviews::getReviewExport($this->hw->healthwatchID)->get();
$columns = array('ReviewID', 'Provider', 'Title', 'Review', 'Location', 'Created', 'Anonymous', 'Escalate', 'Rating', 'Name');
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach($reviews as $review) {
fputcsv($file, array($review->reviewID,$review->provider,$review->title,$review->review,$review->location,$review->review_created,$review->anon,$review->escalate,$review->rating,$review->name));
}
exit();
}
Is there anything I am doing wrong here, or does Laravel have something to cater for this?
我在这里做错了什么,或者 Laravel 有什么可以满足这一点的吗?
回答by Nerdwood
Try this version out - this should allow you to get a nice output using Response::stream()
.
试试这个版本 - 这应该允许你使用Response::stream()
.
public function export()
{
$headers = array(
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=file.csv",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
);
$reviews = Reviews::getReviewExport($this->hw->healthwatchID)->get();
$columns = array('ReviewID', 'Provider', 'Title', 'Review', 'Location', 'Created', 'Anonymous', 'Escalate', 'Rating', 'Name');
$callback = function() use ($reviews, $columns)
{
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach($reviews as $review) {
fputcsv($file, array($review->reviewID, $review->provider, $review->title, $review->review, $review->location, $review->review_created, $review->anon, $review->escalate, $review->rating, $review->name));
}
fclose($file);
};
return Response::stream($callback, 200, $headers);
}
(Adapted from this SO answer: Use Laravel to Download table as CSV)
(改编自这个 SO 答案:Use Laravel to Download table as CSV)
Try using a regular link with target="_blank"
rather than using JavaScript/AJAX. Because it's a file download opening in a new tab, the user experience shouldn't be too clunky.
尝试使用常规链接target="_blank"
而不是使用 JavaScript/AJAX。因为它是在新选项卡中打开的文件下载,所以用户体验不应该太笨拙。
回答by Ryan
My approach in Laravel 5.7
我在 Laravel 5.7 中的方法
/**
* @param array $columnNames
* @param array $rows
* @param string $fileName
* @return \Symfony\Component\HttpFoundation\StreamedResponse
*/
public static function getCsv($columnNames, $rows, $fileName = 'file.csv') {
$headers = [
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=" . $fileName,
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
];
$callback = function() use ($columnNames, $rows ) {
$file = fopen('php://output', 'w');
fputcsv($file, $columnNames);
foreach ($rows as $row) {
fputcsv($file, $row);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
public function someOtherControllerFunction() {
$rows = [['a','b','c'],[1,2,3]];//replace this with your own array of arrays
$columnNames = ['blah', 'yada', 'hmm'];//replace this with your own array of string column headers
return self::getCsv($columnNames, $rows);
}
回答by Rob
This may not answer your question directly, but I'm using a package called 'thephpleague/csv' for this purpose...
这可能无法直接回答您的问题,但我为此使用了一个名为“ thephpleague/csv”的包...
To use this package:
要使用这个包:
- composer require league/csv
Put the following 'use' statements in your controller:
use Illuminate\Database\Eloquent\Collection; use League\Csv\Writer; use Schema; use SplTempFileObject;
and any model classes you plan on using.
Abstract CSV creating code to a function (in your controller), e.g:
/** * A function to generate a CSV for a given model collection. * * @param Collection $modelCollection * @param $tableName */ private function createCsv(Collection $modelCollection, $tableName){ $csv = Writer::createFromFileObject(new SplTempFileObject()); // This creates header columns in the CSV file - probably not needed in some cases. $csv->insertOne(Schema::getColumnListing($tableName)); foreach ($modelCollection as $data){ $csv->insertOne($data->toArray()); } $csv->output($tableName . '.csv'); }
In your controller, create get function to retrieve/download CSV (replace 'MainMeta' with your own model class):
public function getMainMetaData(){ $mainMeta = MainMeta::all(); // Note: $mainMeta is a Collection object //(returning a 'collection' of data from using 'all()' function), //so can be passed in below. $this->createCsv($mainMeta, 'main_meta'); }
When you create a route to call this function, it will download a CSV file in your browser, of your chosen Model collection/data.
Create a route in App\Http\routes.php like the following:
Route::get( '/data/download/main_meta', [ 'as' => 'data/download/main_meta', 'uses' => 'YourController@getMainMetaData' ] );
(Optional) In a blade view file (e.g. data.blade.php), include a link or button so you can easily access the download url/route:
<p><a href="{{ URL::route('data/download/main_meta') }}" class="btn btn-lg btn-primary pull-left">Download Main Meta Data</a></p>
When you click on the link, the CSV file will be downloaded in your browser. In an application I have coded, you will stay on the page you click this link.
- 作曲家需要联盟/ csv
将以下“使用”语句放入您的控制器中:
use Illuminate\Database\Eloquent\Collection; use League\Csv\Writer; use Schema; use SplTempFileObject;
以及您计划使用的任何模型类。
将 CSV 创建代码抽象为函数(在您的控制器中),例如:
/** * A function to generate a CSV for a given model collection. * * @param Collection $modelCollection * @param $tableName */ private function createCsv(Collection $modelCollection, $tableName){ $csv = Writer::createFromFileObject(new SplTempFileObject()); // This creates header columns in the CSV file - probably not needed in some cases. $csv->insertOne(Schema::getColumnListing($tableName)); foreach ($modelCollection as $data){ $csv->insertOne($data->toArray()); } $csv->output($tableName . '.csv'); }
在您的控制器中,创建 get 函数来检索/下载 CSV(用您自己的模型类替换“MainMeta”):
public function getMainMetaData(){ $mainMeta = MainMeta::all(); // Note: $mainMeta is a Collection object //(returning a 'collection' of data from using 'all()' function), //so can be passed in below. $this->createCsv($mainMeta, 'main_meta'); }
当您创建调用此函数的路由时,它将在您的浏览器中下载您选择的模型集合/数据的 CSV 文件。
在 App\Http\routes.php 中创建一个路由,如下所示:
Route::get( '/data/download/main_meta', [ 'as' => 'data/download/main_meta', 'uses' => 'YourController@getMainMetaData' ] );
(可选)在刀片视图文件(例如 data.blade.php)中,包含一个链接或按钮,以便您可以轻松访问下载 url/route:
<p><a href="{{ URL::route('data/download/main_meta') }}" class="btn btn-lg btn-primary pull-left">Download Main Meta Data</a></p>
当您单击该链接时,CSV 文件将下载到您的浏览器中。在我编写的应用程序中,您将停留在单击此链接的页面上。
Of course, this will differ depending on your own application. There is so much more you can do with this package (full documentation is at http://csv.thephpleague.com/). The project I am using this in is at https://github.com/rattfieldnz/bitcoin-faucet-rotator- I have just started coding on it again after a few months away, so still have a bit of refactoring/testing/tidying up to do :).
当然,这将根据您自己的应用程序而有所不同。你可以用这个包做更多的事情(完整的文档在http://csv.thephpleague.com/)。我正在使用它的项目是在https://github.com/rattfieldnz/bitcoin-faucet-rotator- 几个月后我刚刚开始重新编码,所以仍然有一些重构/测试/整理最多做:)。
回答by Luca C.
Try this:
尝试这个:
<?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); //use Illuminate\Support\Facades\Response;
}
Note: Works only if you don't load relationships, otherwise it will give exception
注意:仅当您不加载关系时才有效,否则会出现异常
回答by Yevgeniy Afanasyev
I have made a little package LaravelCsvGenerator
我做了一个小包LaravelCsvGenerator
and placed it on packagist
并将其放在packagist 上
Installation
安装
$ composer require eugene-melbourne/laravel-csv-generator
example of use in your controller
在您的控制器中使用的示例
class MyController extends Controller
{
public function getCsv(): \Symfony\Component\HttpFoundation\StreamedResponse
{
$data = [
[1, 2.1],
[3, "hi, there"],
];
$headers = ['one', 'two'];
$data = array_merge([$headers], $data);
return (new \LaravelCsvGenerator\LaravelCsvGenerator())
->setData($data)
->renderStream();
}
Please, do not hesitate to comment your ideas below this answer.
请不要犹豫,在此答案下方评论您的想法。
回答by dmitri
The simples way
最简单的方法
$headers = [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0'
, 'Content-type' => 'text/csv'
, 'Content-Disposition' => 'attachment; filename=leads.csv'
, 'Expires' => '0'
, 'Pragma' => 'public'
];
$leads = []
return response(view('exports.leads.csv', [ 'leads' => $leads ]))
->withHeaders($headers);