PHP: PDO + CSV export not downloading (headers issue?) - php

I'm having a hard time making my CSV export function work.
I've found around plenty of examples using mysqli_* functions, but I'm actually using PDOs so I had to adapt some questions/answers to my needs.
From what I can see, I'm properly parsing and writing data to the *.csv file, but at the end I don't simply get any "Download" modal from the browser.
Again, looking around, I've understood I may have some kind of problem with my headers, so I'm asking for your help.
This is my PHP function snippet:
function downloadAsCSV($dsn, $dbUser, $dbPsw, $options) {
// New PDO connection.
$pdo = pdoConnect($dsn, $dbUser, $dbPsw, $options);
$query = ... // Not going to write it down.
// Let's query the database, ...
$stmt = $pdo->prepare($query);
// Setting up the query variables here...
[...]
// Executing the statement...
$stmt->execute();
// Headers.
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header("Content-Type: text/csv");
header("Content-Disposition: attachment; filename='export.csv'");
header("Pragma: no-cache");
header("Expires: 0");
// Let's open tbe "*.csv" file where we'll save the results.
$fp = fopen("php://output", "w");
if ($fp) {
$first_row = $stmt->fetch(PDO::FETCH_ASSOC);
$headers = array_keys($first_row);
fputcsv($fp, array_values($first_row));
fputcsv($fp, $headers);
// ... fetch the results...
$workpiecesArray = $stmt->fetchAll();
// ... and, finally, export them.
foreach ($workpiecesArray as $workpiece) {
fputcsv($fp, array_values($workpiece));
}
}
fclose($fp);
// Closing the connection.
$stmt = null;
$pdo = null;
}
function mysqli_field_name($result, $field_offset) {
$properties = mysqli_fetch_field_direct($result, $field_offset);
return is_object($properties) ? $properties->name : null;
}
I've taken inspiration to write the table column titles from this answer.

What you need to do is to print the file, which you're not doing right now.
See this example using readfile:
http://php.net/manual/en/function.header.php#example-5554
Simply put:
1.Replace
$fp = fopen("php://output", "w");
with
$tmpfname = tempnam("/", "");
$fp = fopen($tmpfname, "w");
2.Replace
fclose($fp);
with
fclose($fp);
readfile($tmpfname);
unlink($tmpfname);
and this will work

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="export.csv"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('export.csv'));
readfile($csvFile);
exit;
`put this after` fclose($fp);

Related

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);
}
?>

Wordpress converting array to csv for download

I have the following function that takes an array of results from a database query. I populate the array as I loop through the query results. At the same time I create an html table. After outputting the html table I call the function download_csv($csvArray) but no downloading of the CSV happens, It just displays the contents of the the array as if I did a var_dump on the array. I can confirm that the contents of the array are correct.
Note: this is being done on an external web page not from the admin area.
Is there some wordpress function that needs to be called to allow the download or am I missing something?
function download_csv($csvArray) {
$file_name = 'report.csv';
//output headers so that the file is downloaded rather than displayed
header("Content-Type: text/csv");
header("Content-Disposition: attachment; filename=$file_name");
//Disable caching - HTTP 1.1
header("Cache-Control: no-cache, no-store, must-revalidate");
//Disable caching - HTTP 1.0
header("Pragma: no-cache");
//Disable caching - Proxies
header("Expires: 0");
//Start the ouput
$output = fopen("php://output", "w");
//Then loop through the rows
foreach ($csvArray as $fields) {
fputcsv($output, $fields);
}
//Close the stream off
fclose($output);
die();
}
Following Code will help you to convert Array to CSV and Make it to automatically download Change the die(); function to exit(); And Use Implode function. It will work.
header('Content-Type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename=sample.csv');
header('Pragma: no-cache');
header('Expires: 0');
$fp = fopen('php://output', 'w');
//ex: $list={...};
foreach ($list as $fields)
{
fputcsv($fp,implode($fields, ','));
}
fclose($fp);
exit();

Read and write using fgetcsv and fputcsv

I have a 3rd party source from where I am getting "csv" file. I wrote it inside a quote because it says it's a csv file but basically it's not.
So I am taking that main source file then reading and putting the data in a "PROPER" csv file.
The read and write is fine but the problem is when it saves the properly quoted data is writing on the script file itself.For example if the my php file name is "fixcsv.php" then I am getting the downloadable file as "fixcsv.php".
My code
$headings = array('HID');
$handle = fopen("MonC1.csv", "r");
$data = fgetcsv($handle, 0, ";",'"');
$fh = fopen('php://output', 'w');
ob_start();
fputcsv($fh, $headings);
// Loop over the * to export
if (! empty($data)) {
foreach ($data as $item) {
// echo $item;
fputcsv($fh, array($item));
}
}
$string = ob_get_clean();
$filename = 'csv_' . date('Ymd') .'_' . date('His');
// Output CSV-specific headers
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");
exit($string);
Any help is highly appreciated. Thanks in advance.
Your Content-Disposition has a semi-colon in the wrong place (per the spec). Should be:
header("Content-Disposition: attachment; filename=\"$filename.csv\" );

Export csv to any other program user has on his system

I want to export my db data to CSV or asking user "Open with his local supporting program".
Exporting to csv I could understand using this code:
<?php
header("Content-type: text/csv; charset=UTF-8");
header('Content-Disposition: attachment; filename=Export.csv');
//connection
$con = mysql_connect('localhost', 'root', '');
if(!$con){
echo "Error connection";
}
//select db
$select_db = mysql_select_db('country', $con);
if(!$select_db){
echo "Error to select database";
}
mysql_set_charset("utf8", $con);
//Mysql query to get records from datanbase
$user_query = mysql_query('SELECT * FROM countries');
//While loop to fetch the records
$contents = "ccode,country\n";
while($row = mysql_fetch_array($user_query))
{
$contents.=$row['ccode'].",";
$contents.=$row['country']."\n";
}
$contents_final = chr(255).chr(254).mb_convert_encoding($contents, "UTF-16LE","UTF-8");
print $contents_final;
?>
How 2nd part could be managed? Showing option to open with local installed program?
Above code is correct?
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/csv');
header('Content-Disposition: attachment; filename="your_file_name.csv"');
header('Content-Transfer-Encoding: binary');
This will cause the browser to display the dialog box to Save / Open the file.
You should also consider a) switching to mysqli_ or PDO and b) using PHP's built-in csv functions, e.g.
ob_start();
$f = fopen('php://output', 'w');
// $results comes from mysqli_ functions
foreach ( $results as $k => $v ) {
fputcsv($f, $v);
}
$output = ob_get_contents();
ob_end_clean();
echo $output;

allow download using fputcsv but leaving out extra html code in outputted file?

In my code I am creating a file with fgetcsv. I download it and open the file but all the html from my page is included with the csv file. Is there anyway I can just have the data I want to output from the file and not the extra html. my function for creating the csv is below
function makefile()
{
header('Content-type: text/csv');
header("Cache-Control: no-store, no-cache");
header("Content-Disposition: attachment;filename=file.csv");
$this->filepointer = fopen('php://output', 'a');
for($count=0;$count < count($this->alldata);$count++)
{
fputcsv($this->filepointer, $this->alldata[$count]);
}
fclose($this->filepointer);
}
also I was wondering if i use $this->filepointer = fopen('file.csv', 'w') will the file still be populated with the html. as I dont have to have the file downloading I was just using it to check if the file was being created in the correct format. thanks again
You can try the below code. You need to add read_file at the end after setting some header as below.
<?php
if(isset($_GET['link']))
{
$var_1 = $_GET['link'];
$file = $var_1;
if (file_exists($file))
{
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
} //- the missing closing brace
?>
use ob_end_clean() ; before writing the file

Categories