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\" );
Related
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);
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);
}
?>
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();
I can't get the browser to prompt for download. The output gets displayed on the screen instead. I've tried so many other threads regarding this topic on this site but to no avail. I could change the fopen("php://output","w") to fopen("export.csv","w") but that will save a copy of the export.csv file on the server, which I don't want. I want the file to be downloaded on the client without it being saved on the server. Here's my code:
$sql = mysql_query($_SESSION["export-query"]);
$fields = mysql_num_fields($sql);
$header = array();
for ($i = 0; $i < $fields; $i++) {
$header[] = mysql_field_name($sql, $i);
}
$f = fopen("php://output","w");
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate');
fputcsv($f, $header);
while ($row = mysql_fetch_row($sql)) {
fputcsv($f, $row);
}
fclose($f);
Please help! Much appreciated.
Your code is really close to mine, but I have this
header("Content-type: application/vnd.ms-excel");
for the content type. I think this works because browsers know how to handle text/csv but they don't know how to handle excel. It will prompt to download because it doesn't open this type of file itself.
I also don't have "must-revalidate," but I don't think that makes a difference.
EDIT:
Here are my full headers, which have worked 100% of the time. There are minor differences from yours, so maybe one of them is the reason.
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: attachment; filename=".$filename.".csv");
header("Pragma: no-cache");
header("Expires: 0");
EDIT 2:
Judging from your comment on your answer, you are putting all of this code as an ajax call inside a div. The reason that doesn't work is that you can only set headers on the initial call to a page. Setting headers on an ajax call will be ignored.
Here is how my system handles csv generation. Because I needed specific information that could vary between different csv files, I put the name of the generator file into the "action" of a form and provided a submit button:
<form action="thegeneratorpage.php" method="get"><fieldset>
<p>Download [...] in .csv (Excel) form. You can narrow by [...].</p>
<!-- code here that allows users to narrow down what is in the csv -->
<input type="submit" value="Download" />
</fieldset></form>
If the information doesn't vary, you can just do this:
Download CSV
All the code we have been discussing would be on thegeneratorpage.php.
Rather than using the fputcsv function, I would suggest just echoing the rows of the CSV file like so (note that the headers I use are slightly different from yours):
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");
while ($row = mysql_fetch_row($sql)) {
// optionally enclose data if necessary
foreach ($row as $k => $v) {
if (strpos($v, ',') !== false) {
$row[$k] = '"' . $v . '"';
}
}
echo implode(',', array_values($row));
}
I have done a script in PHP to export a MySQL table into a CVS file when clicking a button. It's working fine but now I need to export 1 table per CSV file, all this in a ZIP (or RAR) file when clicking a button.
Basically it should be:
Export table:
mytable.csv
Export all tables:
export.ZIP containing:
--mytable1.csv
--mytable2.csv
--mytable3.csv
I could loop the export function for each table but that will not put everyting into the ZIP:
/* EXPORT ALL TABLES */
if (isset($_POST['export_all_tables'])){
$Qlist_table = $pdo->prepare('SHOW TABLES');
$Qlist_table->execute(array(''));
foreach ($Qlist_table as $Alist_table)
export_table($Alist_table[0]);
}
function export_table($table_to_export){
$Qselect = $pdo->prepare('SELECT * FROM '.$table_to_export.'');
$Qselect->execute(array(''));
$results = $Qselect->fetchAll(PDO::FETCH_ASSOC);
...
...
...
header("Content-disposition: attachment; filename=".$fileName);
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/vnd.ms-excel\n");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");
echo $outputCsv;
exit();
}
I don't think you need all the code of the export function, if yes let me know.
Thanks!
Actually I found the solution thanks to addFile(). Here is the code:
if (isset($_POST['export_all_tables'])){
// Name of the file to export
$date = date('Y_m_j_H\hi');
$fileName = 'Export_all_'.$date.'.zip';
// Headers to create the ZIP file
header("Content-disposition: attachment; filename=".$fileName);
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/zip;\n");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");
// We create the ZIP file
$zip = new ZipArchive;
$result_zip = $zip->open($fileName, ZipArchive::CREATE); // We open the file
if ($result_zip === TRUE) {
$Qlist_table = $pdo->prepare('SHOW TABLES');
$Qlist_table->execute(array(''));
// For each table
foreach ($Qlist_table as $Alist_table) {
$content = export_table($Alist_table[0]);
$fileName = $Alist_table[0].'_'.$date.'.csv';
$zip->addFile($fileName, $fileName); // We add the CSV file from the server
}
$zip->close();
}
else {
echo 'Failed, code:' . $result_zip;
}
readfile("Export_all.zip"); // To download the ZIP file
exit();
}
and the exporttable function ends like that to write the file on the server:
$fh = fopen($fileName, 'w') or die("Can't open file");
$stringData = $outputCsv; // outputCsv is the content of the table
fwrite($fh, $stringData);
fclose($fh);