PHP Fputcsv header not showing - php

I am trying to create a csv in php with products from magento but my header doesn't show up in the csv file, just the products.
If i put the fputcsv for the headings inside the foreach it display the header then one product then the header again and another product and so on...
##### Print product data ####################################################
$headings = ['category', 'manufacturer', 'productid', 'identifier', 'name', 'description', 'product_url', 'image_url', 'price','show_product', 'availability', 'delivery_cost'];
$fh = fopen('php://output', 'w');
ob_start();
fputcsv($fh, $headings);
foreach($ALL_PRODS as $productId) {
// If we've sent this one, skip the rest - this is to ensure that we do not get duplicate products
if (#$already_sent[$productId] == 1) continue;
$PRODUCT = array();
$PRODUCT = smfeed_get_product_details($productId);
if ($PRODUCT['show_product'] == 1 ) {
fputcsv($fh, $PRODUCT);
$string = ob_get_clean();
$filename = 'csv_' . date('Ymd') . '_' . date('His');
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$filename.csv\";");
header("Content-Transfer-Encoding: binary");
$prod_count ++;
// Debuging
if (isset($_GET['debug'])) {
$cnt_prod ++;
if (#$_GET['stats'] == "off") {
}
else {
echo $cnt_prod . ".";
echo "\t" . number_format(microtime(true) - $time, 3) . "s \n";
$time = microtime(true);
echo "\t" . number_format(memory_get_usage()/1048576, 3) . "Mb\n";
}
}
// Limit displayed products
if ($limit > 0 && $prod_count >= $limit && !isset($_GET['pg'])) {
// Debuging
if (isset($_GET['debug'])) {
echo "\n" . $cnt_prod . "products displayed \n";
echo "\npage loaded in " . number_format(microtime(true) - $time_start, 3) . "s \n";
echo number_format(memory_get_usage()/1048576, 3) . "Mb\n";
}
exit;
}
}
$already_sent[$productId] = 1;
}
exit($string);

ob_start(); starts output buffering.
Buffer contains the header line.
After the first product output is done, output buffering is ended by ob_get_clean();
Since $string = ob_get_clean(); assignment is called in the loop, its content being rewritten by false value (since the buffering was ended before) therefore final exit($string); does not output anything.
There are many other issues in your code. For example, HTTP headers will be set over again and again for each item in the loop.

Related

Getting warning while opening Excel file after writing a table to it using PHP

I have the following code which writes a table to Excel file. Once The file gets downloaded but while opening it, getting warning
The file format and Extension of file.xls do not match. The file could
be corrected or unsafe. Unless you trust its source don't open it.
How to resolve this issue?
header('Content-type: application/vnd.ms-excel');
header("Content-Disposition: attachment; filename=$file_name".date("d_m_Y_H_i_s").".xls");
header("Cache-Control: no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Expires: 0");
ob_clean();
// $res in next line will have a table which I get after processing.
$row = $res->getRowAssoc();
$heading = false;
while ($row != null)
{
if(!$heading) {
for ($ii = 0; $ii < $res->getColumnCount(); $ii++)
{
$field_name = $res->getColumnName($ii);
$field_names[$ii] = $util->get_mls_text($field_name);
}
echo implode("\t", $field_names) . "\r\n";
}
$heading = true;
echo implode("\t", $row) . "\r\n";
$row = $res->getRowAssoc();
}

Wordpress - export a mysql table to csv with column headers

I am able to download a file in csv format for my table , but how to add column headers to the same file .
The current code is following -
// load wpdb
$path = $_SERVER['DOCUMENT_ROOT'];
include_once $path . '/wp-load.php';
global $wpdb;
$table = $_POST["table_name"];// table name
$file = 'database_csv'; // csv file name
$results = $wpdb->get_results("SELECT * FROM $wpdb->prefix$table",ARRAY_A );
if(count($results) > 0){
foreach($results as $result){
$result = array_values($result);
$result = implode(", ", $result);
$csv_output .= $result."\n";
}
}
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
header("Pragma: no-cache");
header("Expires: 0");
print $csv_output;
exit;
I was able to do it by first getting column names and then assigning it to final output :
$table_name = $wpdb->prefix.$_POST["table_name"];// table name
$file = 'database_csv'; // csv file name
$results = $wpdb->get_results("SELECT * FROM $table_name",ARRAY_A );
// get column names
$query = "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA`='".$wpdb->dbname."' AND `TABLE_NAME`='".$table_name."'";
$columnNamesList = $wpdb->get_results($query);
foreach ( $columnNamesList as $column_name ) {
$csv_output.=$column_name->COLUMN_NAME.",";
}
// remove last additional comma
$csv_output = substr($csv_output,0,strlen($csv_output)-1);
// start dumping csv rows in new line
$csv_output.="\n";
if(count($results) > 0){
foreach($results as $result){
$result = array_values($result);
$result = implode(", ", $result);
$csv_output .= $result."\n";
}
}
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
header("Pragma: no-cache");
header("Expires: 0");
print $csv_output;
exit;

File download does not start with JQuery

I'm trying to start the download of a file using JQuery. The file is created by a .php function.
The download DOES NOT start. It starts only if i open the .php file MANUALLY (commenting the isset and writing the data manually into the file).
This is the JQuery code:
$("#experimenter_dataset").click(function() {
var imei = $("#select_download_experimenters option:selected").text();
$.post("download_imei_activities.php", { imei:imei }).done(function( data ) {
});
});
This is the php code
if(isset($_POST["imei"])) {
$imei = $_POST["imei"];
$stmt = $pdo->prepare("SELECT * FROM performedactivity WHERE experimenter=:imei");
$stmt->bindParam(":imei", $imei, PDO::PARAM_STR);
//$output = $imei . ".txt";
$output = "";
if ($stmt->execute()) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$activity = $row["activity"];
$timestamp_start = $row["timestampstart"];
$timestamp_stop = $row["timestampstop"];
$date_hour_start = explode(" ", $timestamp_start);
$date_hour_stop = explode(" ", $timestamp_stop);
//$current = "";
$output .= $date_hour_start[0] . "\t" . $date_hour_start[1] . "\t" . $activity . "\t" . "START" . "\r\n";
$output .= $date_hour_stop[0] . "\t" . $date_hour_stop[1] . "\t" . $activity . "\t" . "END" . "\r\n";
//file_put_contents($output, $current, FILE_APPEND | LOCK_EX);
}
} else {
//echo json_encode($pdo->errorInfo());
}
// We'll be outputting a text file
header("Cache-Control: public");
header("Content-Description: File Transfer");
header('Content-type: text/plain');
header('Content-Disposition: attachment; filename='.$imei . ".txt");
header("Content-Transfer-Encoding: binary");
print($output);
//echo $output;
/*header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= " . $output);
header("Content-Transfer-Encoding: binary");
readfile($output);*/
} else {
//echo "imei parameter is missing";
}

CSV export without MYSQL FILE functions

i'd like to make an export into CSV format, but the mutualised host i use has deactivate the FILE functions in mysql.
I did a simple SELECT and then a fopen and fwrite with PHP.
The problem is that in fields there is carriage returns or double quotes.
How to keep them and build a correct csv file?
Thanks a lot.
To build a best CSV. you can do following way.
$filename ='data.csv';
$csv_terminated = "\n";
$csv_separator = ",";
$csv_enclosed = '"';
$csv_escaped = "\\";
$results = array('1','2','3');// value
$schema_insert = '';
$header = array('a','b','c');// header
for ($i = 0; $i< count($header); $i++)
{
$l = $csv_enclosed . str_replace($csv_enclosed, $csv_escaped . $csv_enclosed,
stripslashes($header[$i])) . $csv_enclosed;
$schema_insert .= $l;
$schema_insert .= $csv_separator;
} // end for
$out = trim(substr($schema_insert, 0, -1));
$out .= $csv_terminated;
// Format the data
for($i=0;$i<count($results);$i++)
{
$row = $results[$i];
$schema_insert = '';
for ($j = 0; $j < count($header); $j++)
{
if ($row[$j] == '0' || $row[$j] != '')
{
if ($csv_enclosed == '')
{
$schema_insert .= $row[$j];
} else
{
$schema_insert .= $csv_enclosed .
str_replace($csv_enclosed, $csv_escaped . $csv_enclosed, $row[$j]) . $csv_enclosed;
}
} else
{
$schema_insert .= 'NULL';
}
if ($j < count($header) - 1)
{
$schema_insert .= $csv_separator;
}
} // end for
$out .= $schema_insert;
$out .= $csv_terminated;
} // end while
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Length: " . strlen($out));
// Output to browser with appropriate mime type, you choose <img src="http://thetechnofreak.com/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley">
header("Content-type: text/x-csv");
//header("Content-type: text/csv");
//header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=$filename");
echo $out;
Notice that,
+ when you make enclosed for description which has html code , you should use double quote.
+ Empty value --> Change to Null text or Zero value
They will make your CSV better.
You can download file.csv by use header()
Output everything you want (base on csv format) after header function, for example:
$filename = "output";
header('Content-Type: text/csv');
header('Content-disposition: attachment;'.$filename.'=.csv');
$separate = ","; //or ;
$endline = "\r\n";
foreach($data as $key => $item)
{
echo $key.$separate.$value.$endline;
}
protected function getCsv( $fileName, array $data )
{
// alot of headers here, make force download work on IE8 over SSL
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename="'.$fileName.'"');
header("Content-Transfer-Encoding: binary");
// Joe Green says:
// based on http://www.php.net/manual/en/function.fputcsv.php#100033
$outStream = fopen("php://output", "r+");
function __getCsv( &$vals, $key, $filehandler ) {
fputcsv( $filehandler, $vals, ',', '"');
}
array_walk( $data, '__getCsv', $outStream );
fclose($outStream);
}
fputcsv is your friend. Also, I had to refine this function to get it to this point. Some of those headers are required by IE to force the csv to open as a csv, particularly over SSL. I seem to recall it had something to do with IE8 not recognising the 'text/csv' content type in the first instance and some security features around SSL downloads in the second.

Form downloads same ZIP over and over

Thanks to the users community on this forum, I wrote a very simple web form that allows my user to view text files from within their Internet browser.
I have now two functions whereby the text files returned by the search are compressed into a ZIP. Here's my code
function getFilesFromSite() {
$result = null;
$ZIPresult = null;
if (empty($_POST['DBSite'])) { return null; }
$mydir = MYDIR;
$dir = opendir($mydir);
$DBSite = $_POST['DBSite'];
$getfilename = mysql_query("select filename from search_table where site='" . $DBSite . "'") or die(mysql_error());
while ($row = mysql_fetch_array($getfilename)) {
$filename = $row['filename'];
$result .= '<tr><td>' . $filename . '</td></tr>';
$ZIPresult .= basename($mydir) . '/' . $filename.' ';
}
if ($result) {
$result = "<table><tbody><tr><td>Search Results.</td></tr> $result</table>";
shell_exec("/bin/rm -f SearchResult.zip;/usr/bin/zip -9 SearchResult.zip ". $ZIPresult ." > /dev/null ");
//header for forced download
header("Pragma: public");
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
$fileName = 'SearchResult.zip';
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Transfer-Encoding: binary");
header('Content-type: application/zip');
header("Content-length: " . filesize($fileName));
header('Content-Disposition: attachment; filename="' . $fileName . '"');
ob_start(); // Starts output buffering.
readfile($fileName); // "Outputs" the file.
$content = ob_get_flush(); // Grabs the output and assigns it to a variable.
print base64_encode($content);
}
function getFilesFromError() {
//Just a copy paste from above with different input parameter...
}
The problem is that the ZIP file with the contents from whatever search was done first gets downloaded over and over again. For instance, the results from getFilesFromSite() will always get downloaded even though I did a search with getFilesFromError() afterwards.
I suspect my headers are incorrectly set but I am not sure where.
PS: The new ZipArchive() library/class is not available on our production environment so I chose to use the Unix utility ZIP instead.
Using Base64 was actually not working for reasons well stated here. Instead, I turned zlib compression off and reverted back to using binary as output format. Finally, I set Content-Type to application/octet-stream in my header. Everything is working fine now ; here's my code:
function getFiles() {
ini_set('zlib.output_compression', 'Off');
$result = null;
$ZIPresult = null;
$cleanup = null;
$output = null;
$fileName = null;
//remove old zip if any
$cleanup = shell_exec("/bin/rm -f SearchResult.zip");
error_log("SHELL OUTPUT=>" . $cleanup, 0);
//test
if (empty($_POST['DBRIDs'])) { return null; }
$mydir = MYDIR; // set from the CONSTANT
$dir = opendir($mydir);
$DBRIDs = $_POST['DBRIDs'];
$getfilename = mysql_query("select /*! SQL_CACHE */ filename from automation where rid in (" . $DBRIDs . ")") or die(mysql_error());
while ($row = mysql_fetch_array($getfilename)) {
$filename = $row['filename'];
$result .= '<tr><td>' . $filename . '</td></tr>';
$ZIPresult .= basename($mydir) . '/' . $filename.' ';
}
if ($result) {
$result = "<table><tbody><tr><td>Search Results.</td></tr> $result</table>";
$output = shell_exec("/usr/bin/zip SearchResult.zip ". $ZIPresult ." ");
error_log("SHELL OUTPUT=>" . $output, 0);
$fileName = 'SearchResult.zip';
error_log("ZIP FILENAME=>" . $fileName, 0);
if (file_exists($fileName)) {
//header for forced download
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($fileName));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($fileName));
ob_clean();
flush();
readfile($fileName);
exit;
}
}
return $result;
}
Thanks to all for taking the time!!

Categories