Downloading csv file in firefox bug - php

There is a download in CSV feature in my current CodeIgniter project. When a user click the link, it will download a file in CSV. The downloaded CSV file's filename is incorrect once the provided filename in the code has a question mark character. To make things clear, below is the code.
public function download($role = NULL, $id = 0, $eid = 0) {
$this->load->helper('download');
$list = $this->respondent->get_respondents($eid);
$questions = $this->respondent->get_all_questions($eid);
$fp = fopen('php://output', 'w');
$fields = array(
'Timestamp',
'First Name',
'Middle Name',
'Last Name',
);
$fields = array_merge($fields, $questions);
fputcsv($fp, $fields);
foreach ($list as $respondent) {
$respondent_data = array(
$respondent->since,
$respondent->first_name,
$respondent->middle_name,
$respondent->last_name,
);
$query = $this->respondent->get_responses($respondent->rid);
foreach($query as $response) {
array_push($respondent_data, $response->answer, $response->duration);
}
fputcsv($fp, $respondent_data);
}
$data = file_get_contents('php://output');
$name = $this->respondent->get_experiment($respondent->eid)->title.'.csv';
// Build the headers to push out the file properly.
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private',false);
header('Content-Disposition: attachment; filename="'.basename($name).'"');
header('Content-Transfer-Encoding: binary');
header('Connection: close');
exit();
force_download($name, $data);
fclose($fp);
}
In the line header('Content-Disposition: attachment; filename="'.basename($name).'"');, once the $name has a question mark character, downloading the file in Firefox or Chrome browser can't interpret it correctly. Rather than a question mark character, the generated character is an underscore or hyphen, respectively. However, when Safari is used to download, the filename is just fine. Is the problem in the code or the browsers?

What I meant in my comment is this.
str_replace('?', '_', $name); //when saving file on the server
This way there is no limit for users simply every question mark is replaced with _, I guess no big deal.
The part about FF and GCH I can not answer.

Related

PHP_XLSXWriter and Code Igniter Corrupted Output Excel File

I'm trying to integrate [PHP_XLSXWriter] (https://github.com/mk-j/PHP_XLSXWriter) with Code Igniter
Here's my controller source code
public function ToExcel(){
include_once APPPATH.'/third_party/xlsxwriter.class.php';
$filename = "report-".date('d-m-Y-H-i-s').".xlsx";
header('Content-disposition: attachment; filename="'.XLSXWriter::sanitize_filename($filename).'"');
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
$styles = array('widths'=>[3,20,30,40], 'font'=>'Arial','font-size'=>10,'font-style'=>'bold', 'fill'=>'#eee', 'halign'=>'center', 'border'=>'left,right,top,bottom');
$styles2 = array( ['font'=>'Arial','font-size'=>10,'font-style'=>'bold', 'fill'=>'#eee', 'halign'=>'left', 'border'=>'left,right,top,bottom','fill'=>'#ffc'],['fill'=>'#fcf'],['fill'=>'#ccf'],['fill'=>'#cff'],);
$header = array(
'No 1'=>'string',
'No 2'=>'string',
'No 3'=>'string',
'No 4'=>'string',
);
$writer = new XLSXWriter();
$writer->setAuthor('Human');
$writer->writeSheetHeader('Sheet1', $header, $styles);
for($no=1;$no<=10;$no++){
$writer->writeSheetRow('Sheet1', [$no, $no, $no, $no], $styles2);
}
$writer->writeToStdOut();
}
The Excel file are generated and downloaded successfully, but when I try to open it using Ms Excel, it says that the file was corrupted. The problem is, it turned out that there's empty single line at the source of the generated Excel file
When I delete that empty line, it can be opened without any problem
And also, if I copy that controller code to single php file (without Code Igniter involved), the script and generated Excel file worked like a charm
How do I get rid of that first empty line?
Many thanks for the help
Если вы делали AJAX запрос:
$filename = "example.xlsx";
header('Content-disposition: attachment; filename="'.XLSXWriter::sanitize_filename($filename).'"');
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
$rows = array(
array('2003','1','-50.5','2010-01-01 23:00:00','2012-12-31 23:00:00'),
array('2003','=B1', '23.5','2010-01-01 00:00:00','2012-12-31 00:00:00'),
);
$writer = new XLSXWriter();
$writer->setAuthor('Some Author');
//$writer->writeToFile('example.xlsx');
//echo $writer->writeToString();
// создаём файл
ob_start();
foreach($rows as $row)
$writer->writeSheetRow('Sheet1', $row);
$writer->writeToStdOut();
$xlsData = ob_get_contents();
ob_end_clean();
$response = array(
'status' => TRUE,
'file' => "data:application/vnd.ms-excel;base64,".base64_encode($xlsData)
);
die(json_encode($response));

Issues with exporting a csv file

I'm creating a function that, when you click on a button, submits datas to a this function and in return, creates a .csv file and makes the browser download it. I followed the huge amount of tutorials that can be found online, but maybe I'm mixing up things:
header("Content-Type: application/x-excel");
header("Content-disposition: attachment; filename=export".date('d-m-Y') .".csv");
header('Expires : 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
$list = array
(
"Peter,Griffin,Oslo,Norway",
"Glenn,Quagmire,Oslo,Norway",
);
$file = fopen("contacts.csv","w");
foreach ($list as $line) {
fputcsv($file,explode(',',$line));
}
die($file);
readfile($file);
Just keep in mind that these aren't my real datas, I just want to set everything up before continuing, because I have 50 lines of an array to handle.
With this code, If I keep die($file), the file gets downloaded but is empty. If I remove it, my browser tells me that the website is unavailable.
What am I missing?
try this
header('Content-Type: application/excel');
header('Content-Disposition: attachment; filename="sample.csv"');
$data = array(
"Peter,Griffin,Oslo,Norway",
"Glenn,Quagmire,Oslo,Norway",
);
$fp = fopen('php://output', 'w');
foreach ( $data as $line ) {
$val = explode(",", $line);
fputcsv($fp, $val);
}
fclose($fp);

Forcing PHP to download file via browser

I'm currently trying to make a file download in the user's browser but have so far been unable to make it happen.
I've looked at other answers on stackoverflow.com and so far haven't found anything that has solved my problem.
My process is as follows:
I create the filename and filepath, then set headers:
$date = new DateTime();
$currentDateTime = $date->format("Y-m-d H:i:s");
$filename = "{$name}_{$currentDateTime}.csv";
$filepath = $rootfull . "/{$filename}";
// Set headers
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="' . $filepath . '"');
header('Content-Length: ' . filesize($filepath));
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
I then create the file and start writing to it:
// Write header
fputcsv($output, $header);
fputcsv($output, array()); // Empty line
// Write column names
$column_headers = array_keys(array_flip($columns));
foreach ($data as $row)
{
fputcsv($output, $row);
}
echo readfile($filepath);
die();
The file gets generated and written to the specified location (in this case /var/www/<project>/<filename>.csv without any indication to the user that anything has happened. No download dialog, nothing.
If anyone can spot a problem with my code or my process, please point it out and preferably suggest a better/alternative way of doing it, any help at all is welcome at this point.
If no benefit (poor mans cache) to writing to disk then maybe something like this writing to buffer:
<?php
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="dump_' . date('Ymd') . '.csv"');
header("Pragma: no-cache");
header("Expires: 0");
$this->outputCSV($results);
exit(); //->
public function outputCSV($data, $useKeysForHeaderRow = true)
{
if ($useKeysForHeaderRow) {
array_unshift($data, array_keys(reset($data)));
}
$outputBuffer = fopen("php://output", 'w');
foreach($data as $v) {
fputcsv($outputBuffer, $v);
}
fclose($outputBuffer);
}
?>

php export mysql chinese character to csv, but the character becomes garbage code

I am trying to export data from mysql to csv which contains some chinese character, however it always become garbage code. I googled and find suggestion to add BOM at the heading.But it seems still not work, here is my code. please suggest.
<?php
if(isset($_POST["Export"]))
{
mysql_connect('localhost','test','abc');
mysql_select_db('test');
header('Content-Encoding: UTF-8');
header('Content-Type: text/csv; charset=utf-8' );
header(sprintf( 'Content-Disposition: attachment; filename=my-csv-%s.csv', date( 'dmY-His' ) ) );
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
$data = fopen( 'php://output', 'w' );
//This line is important:
fputs( $data, "\xEF\xBB\xBF");
fputcsv($data,array('student_id','student_chiName','student_engName',' student_title','student_gender','news_receive'));
//Retrieve the data from database
$rows = mysql_query('SELECT * FROM student');
//Loop through the data to store them inside CSV
while($row = mysql_fetch_assoc($rows)){
fputcsv($data, $row);
}
}
?>
Here is my Hex view, seems chinese character are only one byte, one byte is missing. It seems PHP does not ouput the character in 4 bytes.
Try this:
$data = fopen($filepath, 'w');
$rows = mysql_query('SELECT * FROM student');
fprintf($df, chr(0xEF).chr(0xBB).chr(0xBF));
while($row = mysql_fetch_assoc($rows)){
fputcsv($data, $row);
}
the line fprintf($df, chr(0xEF).chr(0xBB).chr(0xBF)); writes file header for correct encoding.

Laravel 3 create Text (CSV) file

Hello I am trying to grab all the emails from the database, then output them into a text (comma separated) file. Here is what I have done but does not work:
public function get_textfile() {
$emails = Staff::get('email');
header("Content-type: text/csv");
header("Cache-Control: no-store, no-cache");
header('Content-Disposition: attachment; filename="filename.txt"');
$stream = fopen("php://output", 'w');
foreach($emails as $email) {
fputcsv($stream, $email, ',');
}
fclose($outstream);
}
return (something)?
getting this: Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.
This is my route:
Route::get('textfile', array('as' => 'textfile','uses' => 'admin#textfile'));
try file_put_contents($filename, implode(',', Staff::get('email')));
Collect all of your data into a string and then output it like this:
$data = '';
foreach ($emails as $email)
{
// If you want 1 email per line
$data .= '"'.$email.'"'.PHP_EOL;
// If you want all emails on 1 line
$data .= '"'.$email.'",';
}
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename=My Cool File.csv');
header('Pragma: no-cache');
header('Expires: 0');
echo $data;

Categories