This question already has answers here:
Ajax call to download file returned from RESTful service
(3 answers)
Export to CSV via PHP
(10 answers)
Closed 1 year ago.
I want to export CSV file in Laravel but it returns only text.
$(document).on("click","#csvIcon",function(){
$('#mask').css('display','block');
var fId=$(this).attr('data-formId');
$.get('/clientarea/form/responses/csv/export',
{'formId':fId},
function (data,status,xhr) {
$('#mask').css('display','none');
}
)
});
route:
Route::get('/clientarea/form/responses/csv/export',[ResponsesController::class,'exportCsv']);
My controller:
In the controller I have to array $data and $questions that fetched from database to create my csv content.
public function exportCsv(Rrequest $request)
...
$data=['a','b','c','d'];
$questions=['s1','s2','s3','s4'];
function cleanData(&$str)
{
if(preg_match("/^0/", $str) || preg_match("/^\+?\d{8,}$/", $str) || preg_match("/^\d{4}.\d{1,2}.\d{1,2}/", $str)) {
$str = "'$str";
}
if(strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
}
$fileName = "form_data_" . date('Ymd') . ".csv";
$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"
);
$callback = function() use($data, $questions) {
$file = fopen('php://output', 'w');
array_walk($questions, __NAMESPACE__ . '\cleanData');
fputcsv($file, $questions,',', '"');
foreach ($data as $row)
{
array_walk($row, __NAMESPACE__ . '\cleanData');
fputcsv($file, $row,',', '"');
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
It returns for example:
s1,s2,s3,s4
a,b,c,d
instead of the csv file to download
It is because of Ajax I'm using to export CSV file .
I replaced JavaScript with:
$(document).on("click","#csvIcon",function(){
let formId=$(this).attr('data-formId');
window.location.href='/clientarea/form/'+formId+'/responses/csv/export'
});
It works properly.
Related
I am generating a very small CSV-File with only 4 columns and it works fine. When I press the designated button it downloads and I can open it and all the wanted data is present.
However the layout is very weird and it doesn't look good. Here is how it looks:
https://i.stack.imgur.com/klXcw.png
In the upper row are the column names and in the row below is the data.
Here is my code that generates the file:
public function exportData(Bewerbungen $bewerbung) {
$query = Portal::query()->where('email', '=', $bewerbung->bewerber_email)->get();
$headers = [
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=bewerberdaten.csv",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0",
];
$columns = ['id', 'email', 'vorname', 'nachname', 'telefon'];
$callback = function () use ($query, $columns) {
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach ($query as $res) {
fputcsv($file, [$res->id, $res->email, $res->vorname, $res->nachname, $res->telefon]);
}
fclose($file);
};
return Response::stream($callback, 200, $headers);
}
I tried to play around with content encoding, but it is my first time working with csv and file exporting so I have no clue if it is the right direction.
Edit: Better screenshot
https://i.stack.imgur.com/8HvhA.png
The solution was to install this:
https://docs.laravel-excel.com/3.1/getting-started/installation.html
And then changing the variable 'excel_compatibility' => false to true
It is inside the config/excel.php file
This question already has answers here:
How to create and download a csv file from php script?
(8 answers)
Closed 3 years ago.
I am trying to download a query as CSV and face currently two issues:
A file is created in the public folder. It contains the query data. That is really bad, because it should not exist in the public folder.
A file is also downloaded, but the downloaded file is empty.
Here is the function:
public function get_chatmessages(Request $data) {
try {
if ($data->chat_to_user) {
$result = DB::connection('mysql_live')->table('user_chatmessages')
->where(function($query) use($data) {
$query->where('from_user', $data->chat_from_user)->where('to_user', $data->chat_to_user);
})->orWhere(function($query) use($data) {
$query->where('to_user', $data->chat_from_user)->where('from_user', $data->chat_to_user);
})->orderBy('date_added', 'asc')->get();
} else {
$result = DB::connection('mysql_live')->table('user_chatmessages')
->where('from_user', $data->chat_from_user)
->orWhere('to_user', $data->chat_from_user)
->orderBy('date_added', 'asc')
->get();
}
//\Log::info($data);
//\Log::info($result);
$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"
);
$columns = array('from_user', 'to_user', 'message', 'date_added');
$callback = function() use ($result, $columns) {
$file = fopen('output_chat.csv', 'w');
fputcsv($file, $columns);
foreach($result as $res) {
fputcsv($file, array($res->from_user, $res->to_user, $res->message, $res->date_added));
}
fclose($file);
};
//return response()->download('output_chat.csv', 'DL_output_chat.csv', $headers);
//return response()->make($callback, 200, $headers);
return response()->stream($callback, 200, $headers);
} catch (\Exception $e) {
return redirect('home')->with('error', $e->getMessage());
}
return redirect('home')->with('error', 'Etwas ist schief gelaufen');
}
I made little changes in your snippet regarding php://output
$headers = [
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=output_chat.csv", // <- name of file
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0",
];
$columns = ['from_user', 'to_user', 'message', 'date_added'];
$callback = function () use ($result, $columns) {
$file = fopen('php://output', 'w'); //<-here. name of file is written in headers
fputcsv($file, $columns);
foreach ($result as $res) {
fputcsv($file, [$res->from_user, $res->to_user, $res->message, $res->date_added]);
}
fclose($file);
};
For Laravel, there are many packages which provide us such implementations.
And for you to create download csv file with your database records you can use Laravel Excel package.
This package has many useful features. try to use it.
You can decide where you save files - you can do this using Laravel's Storage facade.
private function pathToPrivateStorage()
{
return '/private/CSVs';
}
Storage::put($this->pathToPrivateStorage, $YOURCSVFILE);
You can read more about storage here.
Try $file = fopen('php://output', 'w'); in place of $file = fopen('output_chat.csv', 'w');
I'm trying to create a csv file using laravel and php. The database used to create the csv contains Japanese characters which I want to appear exactly the same in the file.
Below is the code I've tried so far, but the japanese characters still appear as symbols.
$headers = array(
"Content-Encoding" => "sjis-win",
"Content-type" => "text/csv; charset=sjis-win",
"Content-Disposition" => "attachment; filename=User-List.csv",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
);
$users= $this->users->orderBy('created_at', 'desc')->get();
$columns = array('氏名', '氏名(ローマ字)');
$callback = function() use ($users, $columns)
{
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach($users as $user) {
fputcsv($file, array($user->name, $user->name_alphabet));
}
fclose($file);
};
What am I missing? What needs to be changed to make the characters appear as Japanese automatically in the csv.
It working!
// You add $bom in when fputs file.
$headerColumns = [
'name',
'birthday',
'address',
];
$fileCSV = fopen($fileName, 'w');
fputs($fileCSV, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($fileCSV, $headerColumns);
foreach ($data as $myField ){
fputcsv($fileCSV, $myField);
}
fclose($fileCSV);
// Good luck!
As the data your retrieving from the database is encoded in UTF-8, you will need to re-encode that data to match the encoding of your CSV file (SJIS-win).
You can use php's mb_convert_encoding() function to achieve this.
mb_convert_encoding($dataVariable, "SJIS-win", "UTF-8");
In your case you would use it as follows:
foreach($users as $user) {
fputcsv($file, array(
mb_convert_encoding($user->name, "SJIS-win", "UTF-8"),
mb_convert_encoding($user->name_alphabet, "SJIS-win", "UTF-8")
));
}
You may also need to re-encode the strings in your $columns = array('氏名', '氏名(ローマ字)') array too.
When I generate an excel sheet from the database it shows an error that "excel file does not match format. Do you want to open it anyway?" and it says to click on ok button to upgrade format of excel file. When I click on ok it works fine... but in mobile its not open.
i want to generate microsoft excel file with no error.
//generating Excel File
$setSql = "SELECT * from demo table";
$setRec = mysqli_query($db, $setSql);
$header_name="DATA LIST IN EXCEL";
$Event= "This is a demo";
date_default_timezone_set("Asia/Kolkata");
$date='Export Date:-'.date("l, jS \of F Y h:i:s A");
$columnHeader = '';
$columnHeader = "Name" . "\t" . "Date" . "\t". "Mode No" . "\t". "Address" . "\t". "eduction"."\t"."Organisation" . "\t". "Paid Status" . "\t";
$setData = '';
while ($rec = mysqli_fetch_row($setRec)) {
$rowData = '';
foreach ($rec as $value) {
$value = '"' . $value . '"' . "\t";
$rowData .= $value;
}
$setData .= trim($rowData) . "\n";
}
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename= file_name.xls");
header("Pragma: no-cache");
header("Expires: 0");
echo $header_name ."\t\t\t\t\t\t\t\n". $Event ."\t\t\t". $date ."\n". ucwords($columnHeader) . "\n" . $setData . "\n";
Here you have our code.
Notice
ob_clean before download
This is the tricky point. If you have some content in the output buffer (maybe for an incorrect include file) it is sent with the file. So, you have to clean it before any download command
Added BOM header to CSV file
And, if you plan to open the file with Excel, and the file is UTF8, you have to add BOM header
public function reportAsset($budgetPeriod_id)
{
$timeProcess = round(microtime(true) / 1000);
if ($budgetPeriod_id) {
$budget = \App\Models\Invoicing\BudgetPeriod::select(['description'])->find((int) $budgetPeriod_id);
$client = \App\Models\Structure\Client::select(['description'])->find($this->client_id);
$filename = date('Ymd').'_'.$budget->description . '_' . $client->description . '.csv';
$headers = [
'Content-type' => 'text/csv;charset=UTF-8',
'Content-Disposition' => 'attachment; filename=' . $filename,
'Pragma' => 'no-cache',
'Expires' => '0',
];
$output = fopen($filename, "w");
// JMA: Add BOM header
fputs($output, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
fputcsv($output, [_i('Asset_id'), _i('Asset'), _i('Client Category'), _i('Budget'), _i('Spent'), _i('Available'),_i('Spent') .' %', _i('# Invoices')], ';');
$query = \App\Models\Invoicing\AssetBudget::query();
$query->has('asset')
->has('clientCategory')
->with('asset:PROCESS_ID,Identificador_Processo', 'clientCategory:id,description')
->orderBy('asset_id', 'clientCategory_id', 'clientCategory.id')
->selectRaw('amount as total, asset_id, budgetPeriod_id, clientCategory_id')
->where('budgetPeriod_id', $budgetPeriod_id)
->chunk($this::BUDGET_CHUNK, function ($chunk_query) use ($budgetPeriod_id, $output, $timeProcess) {
foreach ((array) $chunk_query as $report) {
foreach ($report as $rep) {
$row = [];
// JMA: The amount has to be the individual amount per asset
// So. we read asset_invoices where the invoice is in the budget period and category
// TODO: Replace this piece of code with consumedBudgetByRequest function in Invoicing BudgetController
// TODO: Try with calculateBudget but is not the same structure
//$invoices = \App\Library\Invoicing\BudgetCalculator::calculateBudget($rep->budgetPeriod_id, $rep->clientCategory_id, (array)$rep->asset_id);
$invoices=AssetInvoice::whereHas('invoice' , function ($invoice) use ($rep) {
$invoice->where('budgetPeriod_id',$rep->budgetPeriod_id)
->where('clientCategory_id',$rep->clientCategory_id);
}
)
->selectRaw('count(asset_id) as nInvoices, sum(amount) as spent')
->where('asset_id',$rep->asset_id)
->first();
// Log::debug('BudgetController->reportAsset: Invoices found='.$invoices->nInvoices.' spent='.$invoices->spent);
$row['asset_id'] = $rep->asset->PROCESS_ID;
$row['Identificador_Processo'] = $rep->asset->Identificador_Processo;
$row['clientCategory'] = $rep->clientCategory->description;
$row["budget"] = floatval($rep->total);
$row["spent"] = floatval($invoices->spent);
$row["available"] = $row["budget"] - $row["spent"];
if(floatval($rep->total)==0 ){
$row["percentaje"] = '';
}else{
$row["percentaje"] = number_format((float)(floatval($invoices->spent)*100)/ floatval($rep->total), 2, '.', '');
}
$row["nInvoices"] = floatval($invoices->nInvoices);
// Uncomment this line to monitor time consumption
// $row["times"] = $timeProcess - round(microtime(true) / 1000);
fputcsv($output, $row, ';');
}
}
});
fclose($output);
// CHECK THIS: Clean output buffer before sending files (avoid initial whitespaces)
if (ob_get_contents()) {
ob_clean();
}
// Send csv file as response
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
}
Please help, I'm new in Yii. I want to generate and export CSV file from checked rows in CGridView. When I use static SQL query it works normally, but when I use implode function in WHERE clause - controller returns an error.
My button that called controller action:
$this->widget('bootstrap.widgets.TbButtonGroup', array(
'type' => 'primary',
'size'=>'mini',
'buttons' => array(
array(
'label' => 'Export',
'type' => 'success',
'buttonType'=>'ajaxLink',
'encodeLabel'=>true,
'icon'=> 'th white',
'url'=>Yii::app()->createUrl('/propertyPurchaseSale/ExportChecked'),
'ajaxOptions'=>array(
"type" => "post",
"data" => "js:{ids:$.fn.yiiGridView.getSelection('property-purchase-sale-grid')}",
"update" => '#', 'success'=>"js:function(data) {window.location.assign('/propertyPurchaseSale/ExportChecked');}"),
array( //htmlOptions
)
),
array(
...
),
),
));
My controller action:
public function actionExportchecked() {
header('Content-type: text/csv');
header('Content-type: multipart/form-data');
header('Content-Disposition: attachment; filename="Export_(' . date('H-i_d.m.Y') .').csv"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Description: File Transfer');
$fp = fopen('php://output', 'w');
if(Yii::app()->request->isAjaxRequest)
{
if(isset($_POST['ids']))
{
$idx = $_POST['ids'];
$count=Yii::app()->db->createCommand('SELECT COUNT(*) FROM property')->queryScalar();
// $sql='SELECT * FROM property WHERE id IN (981, 982, 985)'; --> when I use static values - all work
$sql="SELECT * FROM property WHERE id IN('".implode("', '",$idx)."')"; // --> when I use join or implode function - data exist in firebug, but page return error 500
$dataProvider=new CSqlDataProvider($sql, array(
'totalItemCount'=>$count,
'sort'=>array(
'attributes'=>array(
'fullname', 'address', 'phone', 'db_number', 'created_date'
),
),
'pagination'=>false,
));
fputs($fp, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
if ($fp)
{
echo PropertyPurchaseSale::model()->getAttributeLabel("id").";".
PropertyPurchaseSale::model()->getAttributeLabel("fullname").";".
PropertyPurchaseSale::model()->getAttributeLabel("address").";".
PropertyPurchaseSale::model()->getAttributeLabel("phone").";".
PropertyPurchaseSale::model()->getAttributeLabel("db_number").";".
PropertyPurchaseSale::model()->getAttributeLabel("created_date").
" \r\n";
foreach ($dataProvider->getData() as $data) {
echo $data['id'] . '; ' . $data['fullname'] . '; ' . $data['address'] . '; ' . $data['phone'] . '; ' . $data['db_number'] . '; ' . $data['created_date'] . '; ' . "\r\n";
}
}
exit;
}
}}
Please, help, what am I doing incorrectly?
My knee-jerk reaction is that there is nothing confirming that $_POST['ids'] is an array. If it is just a string, then implode will fail, the SQL will be improperly formatted, and that would lead to a 500 level error.
Perhaps this might work:
// check for empty, that way invalid entry won't go through
if(!empty($_POST['ids'])) {
// Check if it is an array
$input_idx = is_array($_POST['ids'])?
// if so, then use it as an array
$_POST['ids']:
// If not, you need to turn it into an array. I'm only guessing that this should
// be a ','. It could be a " " or some other character(s)
explode(',',$_POST['ids']);
// Remove all non-numeric items in the array.
$idx = array_filter($input_idx, 'is_numeric');
if(!$idx) {
// Do something with bad data.
}
// continue with the line $count = ...
You should also look to making sure that the data is sanitary as those IDs could include SQL injection. (Perhaps this answer)