Exporting CSV with UTF8 to Excel using PHP - php

my client asked me to build an export system that export the whole SQL database into csv file that works on excel. I found PHPexcel and it's great, but I thought I can do stuff way more easier and faster using my own functions.
After struggling with Excel encoding, I finally succeeded to export the CSV that will work on Excel using the following code:
<?php
$data = showData("price"); //Function that loads all the SQL database into an array.
function array2csv(array &$array)
{
if (count($array) == 0) {
return null;
}
ob_start();
$df = fopen("php://output", 'w');
fputcsv($df, array_keys(reset($array)));
foreach ($array as $row) {
fputcsv($df, $row);
}
fclose($df);
return ob_get_clean();
}
function download_send_headers($filename) {
// disable caching
$now = gmdate("D, d M Y H:i:s");
header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
header("Last-Modified: {$now} GMT");
header ( 'HTTP/1.1 200 OK' );
header ( 'Date: ' . date ( 'D M j G:i:s T Y' ) );
header ( 'Content-Type: application/vnd.ms-excel') ;
header ( 'Content-Disposition: attachment;filename=export.csv' );
}
download_send_headers("export.csv");
$final = array2csv($data);
print chr(255) . chr(254) . mb_convert_encoding($final, 'UTF-16LE', 'UTF-8');
die();
?>
The problem is that when I try to open the file in Excel there are no columns. Each row is a large column that contains the whole data of the specific row, separated by a comma.
I figured out that I would need to replace those commas with something that Excel can read as a "new column". But I still need to keep my CSV to work as it is.
I searched SO and Google with no luck whatsoever finding a solution that will keep my CSV intact and yet split the data into columns Excel. If there is no way to do both, I think the more important thing to my client is that the Excel version will work as it should (each row separated into columns).
This is a picture of how it looks on CSV (using numbers on Mac)
And this is a picture of how it looks on Excel 2007 on Windows

It's all in the fputcsv() function:
http://php.net/manual/en/function.fputcsv.php
Try to choose the correct $delimiter, $enclosure and $escape_char.
The default character that is used as the field-separator in excel is set by the locale settings. That means: Importing CVS files can be language dependent. Export to CSV from excel to see what it does on your system, and check that your client system has the same settings.
It's better to export to XML instead of CSV, because that will circumvent this problem:
http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats

Related

PHP 7: Query output to Text File Questions (FIeld Headers and Skipping a Comma after last column)

I've very new to PHP and trying to re-create some code I had in another language. The current version of PHP I'm working with is 7.17.
Right now, I'm trying to re-create a simple function of opening a MySQL query as a comma deliminated text file where there is no comma after the last column (just a line break). I'm trying to figure out two things right now to finish this piece of code.
How do I insert the query column headers at the top of the data output (right now only the data is output, not the column headers).
At the line "fwrite($output, $value.',');", I'm trying to figure out how to not add the comma after the last field (how to skip adding the comma after the last column of data).
PHP:
if (isset($_POST['download'])) {
header('Content-Type: text/plain');
header('Content-Disposition: attachment;filename=cars.txt');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
$output = fopen('php://output', 'w');
while ($row = getRow($result)) {
foreach ($row as $key => $value) {
fwrite($output, $value.',');
}
fwrite($output, "\r\n");
}
fclose($output);
exit;
}
Thank You!
It sounds like you are trying to create a CSV file, so why not use PHP's built in CSV handling functionality (fputcsv), like so:
$output = fopen('php://output', 'w');
while ($row = getRow($result)) {
fputcsv($output, $row);
}
fclose($output);
This way PHP does all the heavy lifting for you.
Edited based upon comment.
You could try using the answer from here to handle the encoding of the values before converting to CSV and then set the file encoding in the HTTP header to header('Content-Type: text/plain; charset=utf-8');.
Also fputcsv allows you to change the delimiter, enclosure and escape characters if they were causing you issues.
Otherwise just do:
$output = fopen('php://output', 'w');
while ($row = getRow($result)) {
$line = implode(', ', $row);
fwrite($output, $line);
}
fclose($output);

how to create another sheet while write data using fputcsv in php

I am using fputcsv for write data. It is working fine. what i need is i need to create another sheet like any name and i need to write data on that. How to do that? Please guide. I am not familiar with this.
This is my code.
$filename = date("Y-m-d").".csv";
header('Content-type: application/csv');
header('Content-Disposition: attachment; filename=' . $filename);
header("Content-Transfer-Encoding: UTF-8");
$fp = fopen('php://output', 'a');
$yetToaproveFields = array('job_no'=>'Job Number',
'revisioncycle'=> 'Revision Cycle',
'version'=>'Version',
'is_approved'=>'Approved Status'
);
fputcsv($fp, $yetToaproveFields);
$notApproveArr = array();
$notApprovedValues = self::getNotApprovedJobs($_REQUEST);
foreach ($notApprovedValues as $key=>$value) {
if ($value['is_approved'] == 1)
$value['is_approved'] = 'No';
fputcsv($fp, $value);
}
fclose($fp);
CSV doesn't support multiple sheets, it's a simple text file. To use sheets, you should use an Excel extension, such as PHPExcel.
You can't.
CSV is a very simple data file format. It doesn't support spreadsheet features like styling or multiple worksheets. If you want multiple worksheets, then you need to use a spreadsheet file format like BIFF (.xls), OfficeOpenXML (.xlsx) or OASIS (.ods)

mysqli export to xls issue

I have troble geting this work and I can't figure it out what is the issue.
I download a xls file, but it doesent opens.
I had a mysql script like this, working, and I tried to convert it into mysqli and probably something is wrong...
Thanks in advance
$sqlExp = "SELECT * FROM table";
$countQryExp = mysqli_query($link, $sqlExp );
$filename = "sampledata.xls"; // File Name
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Type: application/vnd.ms-excel");
$flag = false;
while($row=mysqli_fetch_array($countQryExp,MYSQLI_ASSOC))
{
if(!$flag) {
// display field/column names as first row
echo implode("\t", array_keys($row)) . "\r\n";
$flag = true;
}
echo implode("\t", array_values($row)) . "\r\n";
}
There's a lot more to generating an Excel file than giving it a content type of application/vnd.ms-excel. Excel is a very particular format, whereas you're generating a TSV file - tab separated values, and in a pretty breakable manner (what happens if someone puts a \t in one of your site's fields, or a new line?).
If you want to generate real Excel files, you'll want one of the various libraries for doing so. If a CSV/TSV are fine, just export a .csv/.tsv file with proper headers.

Export CSV from Mysql

I'm having a bit of trouble exporting a csv file that is created from one of my mysql tables using php.
The code I'm using prints the correct data, but I can't see how to download this data in a csv file, providing a download link to the created file. I thought the browser was supposed to automatically provide the file for download, but it doesn't. (Could it be because the below code is called using ajax?)
Any help greatly appreciated - code below, S.
include('../cofig/config.php'); //db connection settings
$query = "SELECT * FROM isregistered";
$export = mysql_query($query) or die("Sql error : " . mysql_error());
$fields = mysql_num_fields($export);
for ($i = 0; $i < $fields; $i++) {
$header .= mysql_field_name($export, $i) . "\t";
}
while ($row = mysql_fetch_row($export)) {
$line = '';
foreach ($row as $value) {
if ((!isset($value) ) || ( $value == "" )) {
$value = "\t";
} else {
$value = str_replace('"', '""', $value);
$value = '"' . $value . '"' . "\t";
}
$line .= $value;
}
$data .= trim($line) . "\n";
}
$data = str_replace("\r", "", $data);
if ($data == "") {
$data = "\n(0) Records Found!\n";
}
//header("Content-type: application/octet-stream"); //have tried all of these at sometime
//header("Content-type: text/x-csv");
header("Content-type: text/csv");
//header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=export.csv");
//header("Content-Disposition: attachment; filename=export.xls");
header("Pragma: no-cache");
header("Expires: 0");
echo 'Download Exported Data'; //want my link to go in here...
print "$header\n$data";
In essence, you can't output the CSV file and the link to it in one go. (You need to introduce the concept of a page "mode" and activate the download mode via a ...pagename.php?mode=download or similar. You could then use PHP's switch statement to switch on $_GET['mode'] in your script.)
That said, the text/csv content type header you were using is correct, although you may also want to output the Content-Length and Content-Disposition headers. After you've output the file data, also be sure to stop any additional script processing via PHP's exit function.
Additionally, it would probably be a lot less hassle (and will certainly be faster/more memory efficient) to use MySQL SELECT ... INTO OUTFILE facility (if you have the permissions) rather than use PHP to gather the data.
You can't have text and a download on the same page. You need to have a link to the download area, which could just be a GET parameter leading to a function, which then does all the processing, displays headers, and echoes the content of the CSV.
For example, you could have Click here to download CSV, then in your code have if ($_GET['action'] === 'download'), get the data from the database, format it, send the headers, and echo the data. And then die(), because that part of the script can accomplish no more.
You should not put the link in the same file that generates the csv, as the link will not be in the csv itself!
Do something like:
Download CSV
and it should work
Three things to consider:
You're sending headers indicating that the user is going to be downloading a CSV file, but then you send create a link to download it? This isn't correct, you should be linking to this page, and then only outputting the CSV data itself after the headers.
MySQL has the ability to generate CSV output, and you should definitely take advantage of this instead of trying to do it yourself. You can use SELECT INTO ... OUTFILE to do this.
If you must create the CSV using PHP, please use fputcsv to do so. This will handle all the complications of CSV such as escaping and proper formatting. Since fputcsv writes to a file, you could either write it to a temporary file and then output it after you send your headers, or use the following trick to output it directly:
Do this after sending headers:
$fp = fopen('php://output', 'w');
while( $row = mysql_fetch_row( $export ) ) {
fputcsv($fp, $row);
}
I think the mySQL => CSV is common problem which is part of each PHP forum.
I have try to solve this issue in a common way and implement an free export
lib for PHP which is very similar to the Google AppInventor philosophie.
DragDrop and hide the coding stuff.
Use the lib and create your Export via Click&Point.
Common Demos: http://www.freegroup.de/software/phpBlocks/demo.html
Link to editor: http://www.freegroup.de/test/editor/editor.php?xml=demo_sql.xml
worth a look
Greetings
Andreas

exporting php output as excel

include_once 'mysqlconn.php';
include_once "functions.php";
$filename = $_GET['par'].".xls";
header("Content-type: application/x-msexcel");
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
if ($_GET['i'] == "par1") {
func1();
} else if ($_GET['i'] == "par2") {
echo "şşşıııİİİ";
func2();
} else if ($_GET['i'] == "par3") {
echo "şşşıııİİİ";
func3();
}
this is my export2excel.php file and func1,2,3 are in functions.php file and produces table output all work well except character encoding in a strange way. I am using utf-8 encoding for all my files. 2nd else if statement above produces healthy encoded output but rest 2 are encodes my output with strange characters like "BÃœTÇE İÇİ". it is "BÜTÇE İÇİ" in turkish.
in short. same files, same encoding, same database but different results.
any idea?
Excel uses UTF-16LE + BOM as default Unicode encoding.
So you have to convert your output to UTF-16LE and prepend the UTF-16LE-BOM "\xFF\xFE".
Some further information:
Microsoft Excel mangles Diacritics in .csv files?
Exporting data to CSV and Excel in your Rails apps
Instead I would use one of the existing libraries
PHP Excel Extension PECL extension by Ilia Alshanetsky (Core PHP Developer & Release Master)
Spreadsheet_Excel_Writer PEAR Package
PHPExcel
Edit:
Some code that could help if you really not want to use an existing library
<?php
$output = <<<EOT
<table>
<tr>
<td>Foo</td>
<td>IñtërnâtiônàlizætiøöäÄn</td>
</tr>
<tr>
<td>Bar</td>
<td>Перевод русского текста в транслит</td>
</tr>
</table>
EOT;
// Convert to UTF-16LE
$output = mb_convert_encoding($output, 'UTF-16LE', 'UTF-8');
// Prepend BOM
$output = "\xFF\xFE" . $output;
header('Pragma: public');
header("Content-type: application/x-msexcel");
header('Content-Disposition: attachment; filename="utf8_bom.xls"');
echo $output;
if anyone is trying to use the excel_writer in moodle and is getting encoding issues with output - say if you're developing a report that has a url as data in a field - then in this instance to simply fix this issue I wrapped the data in quotes so it at least opened up in excel here's my example:
// Moodles using the PEAR excel_writer export
$table->setup();
$ex=new table_excel_export_format($table);
$ex->start_document( {string} );
$ex->start_table( {string} );
// heading on the spreadsheet
$title = array('Report Title'=>'Report 1');
$ex->add_data($title);
// end heading
$ex->output_headers( array_keys($table->columns) );
**foreach($data as $row){
$string="'".trim($row->resname,"'")."'";
$row->resname=$string;
$ex->add_data( $table->get_row_from_keyed($row) );
}**
$ex->finish_table();
$ex->finish_document();
Excel uses UTF-16LE as the default encoding. So you should either convert UTF-8 to UTF-16LE yourself or use one of the tried and tested Excel PHP libs instead of trying to reinvent the wheel. I would recommend using PHPExcel...

Categories