Im trying to create a loop that when executed it created multiple csv files and downloads them. This is my code:
session_start();
require '../connect.php'; //connect.php has connection info for my database
// and uses the variable $connect
$sqldept = "SELECT department_name from department;";
$departments = mysqli_query($connect, $sqldept);
while ($department = mysqli_fetch_array($departments)) {
$department = $department[0];
header('Content-Type: text/csv; charset=utf-8');
header("Content-Transfer-Encoding: UTF-8");
header('Content-Disposition: attachment; filename=summary-' . $department . '.csv');
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1
header("Pragma: no-cache"); // HTTP 1.0
header("Expires: 0"); // Proxies
$date = date("Y-m-d", strtotime("-28 days" . date("Y-m-d")));
$edate = date("Y-m-d");
$startdate = "(time.dateadded BETWEEN '$date' AND '$edate') AND";
$department = " and department_name = '$department'";
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
$sql2 = "SELECT time.id as timeid, time.staff_id, SUM(time.timein), COUNT(NULLIF(time.reasonforabsence,'')) AS count_reasonforabsence, GROUP_CONCAT(CONCAT(NULLIF(time.reasonforabsence,''),' ', date_format(time.dateadded, '%d-%m-%Y'),' ')) AS reasonforabsence, time.dateadded, staff.id AS staffid, department.id AS departmentid, department.department_name, staff.staff_name, staff.department_id, SUM(staff.workhoursperday), staff.payrollnum FROM time, staff, department WHERE $startdate staff.id = time.staff_id AND staff.department_id = department.id $department $staffsearch GROUP BY staff.id ORDER BY `time`.`dateadded` ASC;";
// output headers so that the file is downloaded rather than displayed
fputcsv($output, array(
'Payroll Number',
'Name',
'Department',
'Hours Worked',
'Days Absent',
'Overtime',
'Reasons for Absence'
));
$rows = mysqli_query($connect, $sql2);
while ($rowcsv = mysqli_fetch_assoc($rows)) {
$reasonforabsence = $rowcsv['reasonforabsence'];
//$reasonforabsence = explode( ',', $rowcsv['reasonforabsence'] );
$overtime = 0;
if (empty($rowcsv['SUM(time.timein)']) == true) {
$rowcsv['SUM(time.timein)'] = 0;
}
;
if ($rowcsv['SUM(time.timein)'] > $rowcsv['SUM(staff.workhoursperday)']) {
$overtime = $rowcsv['SUM(time.timein)'] - $rowcsv['SUM(staff.workhoursperday)'];
}
;
fputcsv($output, array(
$rowcsv['payrollnum'],
$rowcsv['staff_name'],
$rowcsv['department_name'],
$rowcsv['SUM(time.timein)'],
$rowcsv['count_reasonforabsence'],
$overtime,
$reasonforabsence
));
};
readfile("php://output");
fclose($output);
};
Currently the loop created 1 CSV with a new header and the department details below it like this
I want the loop to create a new CSV for each department but its just not working for me. Any help is appreciated.
Thanks
Unfortunately you can't, 1 PHP Request results in one file, and there isn't really a way around this. You can, however, try to download them all as a ZIP file. Take a look at this question f.e.
The below are some workaround ideas, which might be useful in certain scenarios (and might be dangerous in other scenarios). Use under your own risk!
Workaround A: Loop by redirect
Output a single file normally
Do a redirect to same url that's creating the CSV file in step#1, but append a GET flag to that, like http://www.example.net/output_csv?i=1
Make sure to add a loop-breaker in step#1, like if($i==10) { exit; }
Workaround B: Loop by cronjob
Output a single file normally
Make 2nd file output be handled by a separate cronjob call.
Make sure to add a loop-breaker in step#1, like if($mycron==10) { exit; }
You can not do this by for loop.
However, You can make a php file which can do your purpose.
<a onclick="getcsv()" href="php_file_location.php?table_name=test"> Download </a>
<script>
function getcsv() {
window.open(php_file_location);
}
</script>
I was in the same problem as mentioned. But in my case I was not trying to download multiple CSVs but I was uploading it to sFTP server. While creating the file instead of using
$output = fopen('php://output', 'w');
I used
$output = fopen($path_and_name, 'w');
where $path_and_name = $path_to_sftp_folder.'/'.$file_name;
after the execution the correct file was uploaded to there respective folders correctly the way I wanted it to be. But yes the wrong file was also downloaded with same issue as sent above.
So if you are looking for uploading files on a server it can be done(even if they all have same name).
Related
I have console app made in Symfony3, where user can import CSV file (which is validate) into database. I need to put records which haven't passed validation into separate file.
I use LeagueCSV to read CSV file and I try to use it to write unvalidated records but it doesn't work.
This is my code:
$reader = Reader::createFromPath($input->getArgument('lokalizacja'));
$reader->setDelimiter(';');
$reader->setHeaderOffset(0);
$results = $reader->getRecords();
foreach ($results as $row) {
$year = $row['description'];
$isValid = false;
if ($row['qty'] > 0 && $row['price'] > 0 && !empty($row['mpn'])) {
$isValid = true;
$rok = filter_var($row['description'], FILTER_SANITIZE_NUMBER_INT);
$product = (new Produkt())
->setMpn($row['mpn'])
->setQty($row['qty'])
->setYear($year)
->setPrice($row['price']);
$this->em->persist($product); }
if ($row['qty'] == 0 || $row['price'] == 0 || empty($row['mpn'])) {
$writer = Writer::createFromPath('/path/to/saved/file.csv', 'w+');
$writer->insertOne([$row['mpn'], $row['qty'], $row['price'],
$row['description']]);
continue;
}
}
$this->em->flush();
All records which passed validation are successfully saved in the database but I have problem with others records. In new CSV file I have only first, one record which haven't passed validation and nothing more. What am I doing wrong? I tried with
$writer->insertAll($results); //using an array
Or with if...else statment but that's nothing.
Also I made ...else statement where unvalidated records are saved in other table in database and its works but I don't know how to immediately convert them into CSV file.
Don't know symfony but CSV output is pretty simple. FWIW...
Pass this an array, like a fetchall resultset.
<?php
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);
}
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="FooBarFileName_' . date('Ymd') . '.csv"');
header("Pragma: no-cache");
header("Expires: 0");
$this->outputCSV($results);
If you look at the doc page for the writer you will see a warning at the top which states
When inserting records into a CSV document using League\Csv\Writer, first insert all the data that need to be inserted before starting manipulating the CSV. If you manipulate your CSV document before insertion, you may change the file cursor position and erase your data.
Your code calls
$writer = Writer::createFromPath('/path/to/saved/file.csv', 'w+');
$writer->insertOne([$row['mpn'], $row['qty'], $row['price'], $row['description']]);
In every iteration the condition is met, this appears to be overwriting or dropping your previous insert every time. You should declare the $writer once before the loop starts in order to preserve each insert.
$writer = Writer::createFromPath('/path/to/saved/file.csv', 'w+');
foreach ($results as $row) {
// do stuff with $writer
}
I want to download a .csv file through link.For that a Download link is defined in a template file.
To generate .csv file I have written a piece of code as follows.
public function loadPartnerApplicantData() {
$inboundBo = BoFactory::getInboundHttpRequestBo();
$fileType = $inboundBo->getSanitizedGetParam('f');
$formId = $inboundBo->getSanitizedGetParam('fid');
ServiceFactory::getFormService()->loadFormDetails($formId);
$dbTable = BoFactory::getFormBo()->getFormDbTable($formId);
$formName = slugify(BoFactory::getFormBo()->getFormName());
$fileName = $formName . "." . time();
$fieldMasterSqlQuery = "SELECT field_name,field_label FROM" . FORM_FIELDS_MASTER_v2 . "where form_id='$formId' order by serial_no";
$fieldMasterSqlQueryStatus = mysql_query(mysql_fetch_assoc($fieldMasterSqlQuery));
$csvHeader = "";
$fieldNameArray = array();
foreach ($fieldMasterSqlQueryStatus as $key => $value) {
if ($value['field_name'] == 'declaration' || $value['field_name'] == 'docPicture') {
continue;
}
$csvHeader.= "\"{$value['field_label']}\";";
$fieldNameArray[] = $value['field_name'];
}
$queryString = implode(",", $fieldNameArray);
$dbTableSqlQuery = "SELECT $queryString FROM `$dbTable`";
$dbTableSqlQueryStaus = mysql_query(mysql_fetch_assoc($dbTableSqlQuery));
ef_clearBuffer();
// To generate csv
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=$fileName.csv");
header("Pragma: no-cache");
header("Expires: 0");
echo($csvHeader);
foreach ($dbTableSqlQueryStaus as $applicantData) {
echo "\n";
foreach ($fieldNameArray as $fieldName) {
echo "\"$applicantData[$fieldName]\";";
}
echo "\n";
}
}
And the required .csv is generated .
But at the end of .csv file HTML tags of the browser is getting displayed. which should not be there.
Please suggest me to remove the html content from the generated .csv file.
Thanks in advance.
Since your function handles the request till the end (i.e., delivers all data), and you don't want the framework (whichever you're using) to continue processing, add
exit(0);
as last line of your function. That will halt the processing after the content is delivered and prevent the framework/environment from sending additional data.
Maybe you already had some echo commands before the header manipulation, then the .csv file which you want to download will contains all strings you have written before.
I have problem with writing csv file using fputcsv. Its putting the page html also into the csv file. Whats wrong with my code ?
//Excel header
header("Content-Disposition: attachment; filename=\"Delivery_Reports.csv\";" );
header("Content-type: application/vnd.ms-excel");
$out = fopen("php://output", 'w');
$flag = false;
// $result = mysql_query("SELECT * FROM senderids ") or die('Query failed!');
//$sel="SELECT number as MobileNumber ,snum as Sender , msg as Subject ,crdate as Date ,status FROM savemsg WHERE userID='".$_SESSION['id']."' ".$str." ORDER BY sn DESC ";
$result = mysql_query("SELECT `count`, `dnd`, `credit`, `sender_id`, `to`, `message`, `status` FROM `reports` WHERE `unq_id` = '$dlr_id'");
while(false !== ($row = mysql_fetch_assoc($result))){
if(!$flag){
$list = array(
"Total"=>"Total",
"DND"=>"DND",
"Credits"=>"Credits",
"From"=>"From",
"To"=>"To",
"Message"=>"Message",
"Status"=>"Status"
);
// display field/column names as first row
fputcsv($out, array_keys($list), ',', '"');
$flag = true;
}
// array_walk($row, 'cleanData');
fputcsv($out, array_values($row), ',', '"');
}
fclose($out);
You can't guarantee, from within a snippet of code, that nothing else will be output. If the code before this snippet is using output buffering, you can discard the HTML using ob_end_clean. If the code after this snippet is causing the problem, you can simply call die to keep it from running at all. However, if the code before this snippet is outputting HTML directly to the browser, or the code after it outputs HTML and absolutely has to run, then you'll have to modify that code in order to solve your problem.
As Tim mentioned, print, echo and outputting to the pseudo-file php://output do exactly the same thing.
You can also use the keyword continue just before you close the file (fclose($f);). This also works lovely.
You can also use exit; after fclose($out); which stopped the output from scraping my html.
I know it's an old question but it gets found in Google so adding this.
If the HTML is being output by the CMS such as WordPress etc. before you try to create the file, it might help to add ob_clean(); and ob_start(); before you output the header.
For example:
function create_csv($records, $columns){
ob_clean();
ob_start();
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="Export.csv"');
$fp = fopen('php://output', 'w+');
// Generate the file content.
fclose($fp);
die();
}
I am trying to send email exported csv file. However, when i click the link, have a pop-up to download a CVS with the record from MySQL. how can i send an email this csv file to spesific email adress ? thanks a lot for help and ideas.
best regards.
Here is my code
header("Content-type: application/x-msdownload");
header("Content-Disposition: attachment; filename=log.csv");
header("Pragma: no-cache");
header("Expires: 0");
$resultstr = array();
foreach ($selectionlist as $result)
$resultstr[] = $result;
$ww=implode(",",$resultstr);
function escape_csv_value($value) {
$value = str_replace('"', '""', $value); // First off escape all " and make them ""
if(preg_match('/,/', $value) or preg_match("/\n/", $value) or preg_match('/"/', $value)) { // Check if I have any commas or new lines
return '"'.$value.'"'; // If I have new lines or commas escape them
} else {
return $value; // If no new lines or commas just return the value
}
}
$sql = mysql_query("SELECT * FROM article
WHERE idArticle in ($ww) ORDER BY idArticle DESC"); // Start our query of the database
$numberFields = mysql_num_fields($sql) or die('MySql Error' . mysql_error());; // Find out how many fields we are fetching
if($numberFields) { // Check if we need to output anything
for($i=0; $i<$numberFields; $i++) {
$keys[] = mysql_field_name($sql, $i); // Create array of the names for the loop of data below
$col_head[] = escape_csv_value(mysql_field_name($sql, $i)); // Create and escape the headers for each column, this is the field name in the database
}
$col_headers = join(',', $col_head)."\n"; // Make our first row in the CSV
$data = '';
while($info = mysql_fetch_object($sql)) {
foreach($keys as $fieldName) { // Loop through the array of headers as we fetch the data
$row[] = escape_csv_value($info->$fieldName);
} // End loop
$data .= join(',', $row)."\n"; // Create a new row of data and append it to the last row
$row = ''; // Clear the contents of the $row variable to start a new row
}
// Start our output of the CSV
/*header("Content-type: application/x-msdownload");
header("Content-Disposition: attachment; filename=log.csv");
header("Pragma: no-cache");
header("Expires: 0");*/
echo $col_headers.$data;
} else {
// Nothing needed to be output. Put an error message here or something.
echo 'No data available for this CSV.';
}
OK. First you have to Save the CSV file. If you set headers as you mentioned the file will be automatically downloaded. Please read this article on this.
http://us2.php.net/manual/en/function.fputcsv.php
Once you create your CSV file you can email it using PHP mail function. If you need some library just check this out. It's easy to implement.
http://www.redvodkajelly.com/code/php-email-class/
I have some PHP code that runs a query on a database, saves the results to a csv file, and then allows the user to download the file. The problem is, the csv file contains page HTML around the actual csv content.
I've read all the related questions here already, including this one. Unfortunately my code exists within Joomla, so even if I try to redirect to a page that contains nothing but headers, Joomla automatically surrounds it with its own navigation code. This only happens at the time of download; if I look at the csv file that's saved on the server, it does not contain the HTML.
Can anyone help me out with a way to force a download of the actual csv file as it is on the server, rather than as the browser is editing it to be? I've tried using the header location, like this:
header('Location: ' . $filename);
but it opens the file in the browser, rather than forcing the save dialog.
Here's my current code:
//set dynamic filename
$filename = "customers.csv";
//open file to write csv
$fp = fopen($filename, 'w');
//get all data
$query = "select
c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone as address_phone,
a.company,a.address1,a.address2,a.city,a.state,a.zip, c.last_signin
from {$dbpre}customers c
left join {$dbpre}customers_addresses a on c.id = a.customer_id order by c.last_signin desc";
$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
while ($row = mysql_fetch_array($votes,1)) {
//put header row
if ($counter == 1){
$headerRow = array();
foreach ($row as $key => $val)
$headerRow[] = $key;
fputcsv($fp, $headerRow);
}
//put data row
fputcsv($fp, $row);
$counter++;
}
//close file
fclose($fp);
//redirect to file
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$filename);
header("Content-Transfer-Encoding: binary");
readfile($filename);
exit;
EDITS
Full URL looks like this:
http://mysite.com/administrator/index.php?option=com_eimcart&task=customers
with the actual download link looking like this:
http://mysite.com/administrator/index.php?option=com_eimcart&task=customers&subtask=export
MORE EDITS
Here's a shot of the page that the code is on; the generated file still is pulling in the html for the submenu. The code for the selected link (Export as CSV) is now
index.php?option=com_eimcart&task=customers&subtask=export&format=raw
Now here is a screenshot of the generated, saved file:
It shrank during the upload here, but the text highlighted in yellow is the html code for the subnav (list customers, add new customer, export as csv). Here's what my complete code looks like now; if I could just get rid of that last bit of html it would be perfect.
$fp= fopen("php://output", 'w');
$query = "select c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone as address_phone, a.company, a.address1,
a.address2,a.city,a.state,a.zip,c.last_signin
from {$dbpre}customers c
left join {$dbpre}customers_addresses a on c.id = a.customer_id
order by c.last_signin desc";
$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
//redirect to file
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=customers.csv");
header("Content-Transfer-Encoding: binary");
while ($row = mysql_fetch_array($votes,1)) {
//put header row
if ($counter == 1){
$headerRow = array();
foreach ($row as $key => $val)
$headerRow[] = $key;
fputcsv($fp, $headerRow);
}
//put data row
fputcsv($fp, $row);
$counter++;
}
//close file
fclose($fp);
UPDATE FOR BJORN
Here's the code (I think) that worked for me. Use the RAW param in the link that calls the action:
index.php?option=com_eimcart&task=customers&subtask=export&format=raw
Because this was procedural, our link was in a file called customers.php, which looks like this:
switch ($r['subtask']){
case 'add':
case 'edit':
//if the form is submitted then go to validation
include("subnav.php");
if ($r['custFormSubmitted'] == "true")
include("validate.php");
else
include("showForm.php");
break;
case 'delete':
include("subnav.php");
include("process.php");
break;
case 'resetpass':
include("subnav.php");
include("resetpassword");
break;
case 'export':
include("export_csv.php");
break;
default:
include("subnav.php");
include("list.php");
break;
}
So when a user clicked on the link above, the export_csv.php file is automatically included. That file contains all the actual code:
<?
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=customers.csv");
header("Content-Transfer-Encoding: binary");
$fp= fopen("php://output", 'w');
//get all data
$query = "select
c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone as address_phone,
a.company,a.address1,a.address2,a.city,a.state,a.zip, c.last_signin
from {$dbpre}customers c
left join {$dbpre}customers_addresses a on c.id = a.customer_id order by c.last_signin desc";
$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
while ($row = mysql_fetch_array($votes,1)) {
//put header row
if ($counter == 1){
$headerRow = array();
foreach ($row as $key => $val)
$headerRow[] = $key;
fputcsv($fp, $headerRow);
}
//put data row
fputcsv($fp, $row);
$counter++;
}
//close file
fclose($fp);
This is a piece of sample code that I just cooked up to help you out. Use it as an action method in your controller.
function get_csv() {
$file = JPATH_ADMINISTRATOR . DS . 'test.csv';
// Test to ensure that the file exists.
if(!file_exists($file)) die("I'm sorry, the file doesn't seem to exist.");
// Send file headers
header("Content-type: text/csv");
header("Content-Disposition: attachment;filename=test.csv");
// Send the file contents.
readfile($file);
}
This alone will not be enough, because the file you download will still contain the surrounding html. To get rid of it and only receive the csv file's contents you need to add format=raw parameter to your request. In my case the method is inside the com_csvexample component, so the url would be:
/index.php?option=com_csvexample&task=get_csv&format=raw
EDIT
In order to avoid using an intermediate file substitute
//set dynamic filename
$filename = "customers.csv";
//open file to write csv
$fp = fopen($filename, 'w');
with
//open the output stream for writing
//this will allow using fputcsv later in the code
$fp= fopen("php://output", 'w');
Using this method you have to move the code that sends headers before anything is written to the output. You also won't need the call to the readfile function.
Add this method to your controller:
function exportcsv() {
$model = & $this->getModel('export');
$model->exportToCSV();
}
Then add a new model called export.php, code below. You will need to change or extend the code to your situation.
<?php
/**
* #package TTVideo
* #author Martin Rose
* #website www.toughtomato.com
* #version 2.0
* #copyright Copyright (C) 2010 Open Source Matters. All rights reserved.
* #license http://www.gnu.org/copyleft/gpl.html GNU/GPL
*/
//No direct acesss
defined('_JEXEC') or die();
jimport('joomla.application.component.model');
jimport( 'joomla.filesystem.file' );
jimport( 'joomla.filesystem.archive' );
jimport( 'joomla.environment.response' );
class TTVideoModelExport extends JModel
{
function exportToCSV() {
$files = array();
$file = $this->__createCSVFile('#__ttvideo');
if ($file != '') $files[] .= $file;
$file = $this->__createCSVFile('#__ttvideo_ratings');
if ($file != '') $files[] .= $file;
$file = $this->__createCSVFile('#__ttvideo_settings');
if ($file != '') $files[] .= $file;
// zip up csv files to be delivered
$random = rand(1, 99999);
$archive_filename = JPATH_SITE.DS.'tmp'.DS.'ttvideo_'. strval($random) .'_'.date('Y-m-d').'.zip';
$this->__zip($files, $archive_filename);
// deliver file
$this->__deliverFile($archive_filename);
// clean up
JFile::delete($archive_filename);
foreach($files as $file) JFile::delete(JPATH_SITE.DS.'tmp'.DS.$file);
}
private function __createCSVFile($table_name) {
$db = $this->getDBO();
$csv_output = '';
// get table column names
$db->setQuery("SHOW COLUMNS FROM `$table_name`");
$columns = $db->loadObjectList();
foreach ($columns as $column) {
$csv_output .= $column->Field.'; ';
}
$csv_output .= "\n";
// get table data
$db->setQuery("SELECT * FROM `$table_name`");
$rows = $db->loadObjectList();
$num_rows = count($rows);
if ($num_rows > 0) {
foreach($rows as $row) {
foreach($row as $col_name => $value) {
$csv_output .= $value.'; ';
}
$csv_output .= "\n";
}
}
$filename = substr($table_name, 3).'.csv';
$file = JPATH_SITE.DS.'tmp'.DS.$filename;
// write file to temp directory
if (JFile::write($file, $csv_output)) return $filename;
else return '';
}
private function __deliverFile($archive_filename) {
$filesize = filesize($archive_filename);
JResponse::setHeader('Content-Type', 'application/zip');
JResponse::setHeader('Content-Transfer-Encoding', 'Binary');
JResponse::setHeader('Content-Disposition', 'attachment; filename=ttvideo_'.date('Y-m-d').'.zip');
JResponse::setHeader('Content-Length', $filesize);
echo JFile::read($archive_filename);
}
/* creates a compressed zip file */
private function __zip($files, $destination = '') {
$zip_adapter = & JArchive::getAdapter('zip'); // compression type
$filesToZip[] = array();
foreach ($files as $file) {
$data = JFile::read(JPATH_SITE.DS.'tmp'.DS.$file);
$filesToZip[] = array('name' => $file, 'data' => $data);
}
if (!$zip_adapter->create( $destination, $filesToZip, array() )) {
global $mainframe;
$mainframe->enqueueMessage('Error creating zip file.', 'message');
}
}
}
?>
Then go to your default view.php and add a custom buttom, e.g.
// custom export to set raw format for download
$bar = & JToolBar::getInstance('toolbar');
$bar->appendButton( 'Link', 'export', 'Export CSV', 'index.php?option=com_ttvideo&task=export&format=raw' );
Good luck!
You can use Apache's mod_cern_meta to add HTTP headers to static files. Content-Disposition: attachment. The required .htaccess and .meta files can be created by PHP.
Another way to output CSV data in a Joomla application is to create a view using CSV rather than HTML format. That is, create a file as follows:
components/com_mycomp/views/something/view.csv.php
And add content similar to the following:
<?php
// No direct access
defined('_JEXEC') or die;
jimport( 'joomla.application.component.view');
class MyCompViewSomething extends JViewLegacy // Assuming a recent version of Joomla!
{
function display($tpl = null)
{
// Set document properties
$document = &JFactory::getDocument();
$document->setMimeEncoding('text/csv');
JResponse::setHeader('Content-disposition', 'inline; filename="something.csv"', true);
// Output UTF-8 BOM
echo "\xEF\xBB\xBF";
// Output some data
echo "field1, field2, 'abc 123', foo, bar\r\n";
}
}
?>
Then you can create file download links as follows:
/index.php?option=com_mycomp&view=something&format=csv
Now, you would be right to question the 'inline' part in the Content-disposition. If I recall correctly when writing this code some years ago, I had problems with the 'attachment' option. This link which I just googled now seemed familiar as the driver for it: https://dotanything.wordpress.com/2008/05/30/content-disposition-attachment-vs-inline/ . I've been using 'inline' ever since and am still prompted to save the file appropriately from any browsers I test with. I haven't tried using 'attachment' any time recently, so it may work fine now of course (the link there is 7 years old now!)