How can i auto download generated csv file in php? - php

I have seen many examples but none of them is resolving my issue.
I generated cvs file in ajax post request ( I am not changing window.location.href). I want this file to auto download just like what happens after changing window.location.href. Currently i don't know solution.Kindly help me here is my code
$file_name="temp_".time().".csv";
$new_csv = fopen($file_name, 'w');
fputcsv($new_csv, $csv_data);
fclose($new_csv);
header("Content-type: application/csv; charset=utf-8");
header("Content-disposition: attachment; filename =\"" .$file_name. "\"");
readfile($file_name);
unlink($file_name);
exit;
$this->setLayout(false);
return sfView::NONE;

Related

PHP: How to hide URL

I have the following download.php script to download a file, which works great:
<?php
header("Content-Type: application/octet-stream");
$file = $_GET["file"];
header("Content-Disposition: attachment; filename=" . urlencode($file));
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush();
$fp = fopen($file, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush();
}
fclose($fp);
?>
What I want to achieve is to hide the URL where this file is located, so that when the user clicks a link such as <a target="_blank" href="http://domain.com/files/download.php?file=filename.pdf">Download file</a>, a new tab opens up with no URL and starts downloding the file. What is actually happening is the new tab opens and the file download starts but the URL bar is displaying http://domain.com/files/download.php?file=filename.pdf.
If this cannot be done with php, how can I achieve this? I have seen several downloads where the URL is not shown, so I know this is somehow possible.
EDIT: Here is the reason I want to do this: We will send a html mailing with a link to the file download, and the website where this file download is hosted is not the website from the company which sends the mail.
As always, thank you very much.
A typical way doing this, is to place the files you want to provide for download outside your docroot.
Your download script should know about this place and has to process the requested filename considering this.
For example:
path/in/your/system/docroot/download.php
and
path/in/your/system/files/filename.pdf
If someone is requesting download.php?file=filename.pdf your script has to look up in path/in/your/system/files/ for this file and has to handle it.
You can create a new window with iframe content to that URL.
var win = window.open("", "Title", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=780, height=200, top="+(screen.height-400)+", left="+(screen.width-840));
win.document.body.innerHTML = "<iframe src='YOUR URL'></iframe>";
If you remove the target="_blank" no new tab will be opened and the file will just be downloaded.
In the end, it's not possible because the user can open Google Inspector and check the Network tab.
Edit: If that's the case, you would use JavaScript:
Edit 2: In case the popup is blocked by the browser or addon, use a fallback:
Edit 3: In case JS is disabled:
<head><meta http-equiv="refresh" content="5;http://domain.com/files/download.php?file=filename.pdf">
<script>
var win = window.open("http://domain.com/files/download.php?file=filename.pdf");
if (!win) {
window.location = "http://domain.com/files/download.php?file=filename.pdf";
}
</script>
</head>
Edit 4: If you don't want the user to see the domain of the user site at all, get your PHP script to download the file and then output that to the user:
header("Content-Type: application/octet-stream");
$file = $_GET["file"];
$file = 'http://otherdomain.com/location/' . $file; // This line should suffice for all that you're trying to do
header("Content-Disposition: attachment; filename=" . urlencode($file));
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush();
$fp = fopen($file, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush();
}
fclose($fp);
Submit the form as POST and use $_REQUEST to get the file:
$file = $_REQUEST["file"];

PHP Header download PDF

I've made a page where you can go and write text in a "textarea" and then when you click download you download that file as a .txt file. I've done the same thing to some other extensions and that is working fine. But it won't work with .PDF, nothing I read works. Here is the snippet I use for the .PDF downloading:
<?php
if($fileFormat == ".pdf"){
$content = $_POST['text'];
$name = stripslashes($_POST['name']);
$nameAndExt = $name.".pdf";
print strip_tags($content);
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="'.$nameAndExt.'"');
header('Content-Transfer-Encoding: binary ');
}
?>
I'm grateful for any answear, thanks!
// hold the filename for use elsewhere so you don't have to append .pdf every time
$filename = "$id.pdf";
// create the file
$pdf->output( $filename );
// set up the headers
header("Content-Description: File Transfer");
header("Content-disposition: attachment; filename={$filename}");
header("Content-Type: application/pdf");
header("Content-Transfer-Encoding: binary");
header('Content-Length: ' . filesize($file));
// push the buffer to the client and exit
ob_clean();
flush();
// read the file and push to the output stream
readfile( $filename );
// remove the file from the filesystem
unlink( $filename );
exit();
I would recommend a class like TCPDF, see http://www.tcpdf.org/. I used it couple of times and it's quite nice (open source).

php download file: header()

I need some eduction please.
At the end of each month, I want to download some data from my webserver to my local PC.
So, I've written a little script for that, which selects the data from the DB.
Next, I want to download it.
I've tried this:
$file=$month . '.txt';
$handle=fopen($file, "w");
header("Content-Type: application/text");
header("Content-Disposition: attachment, filename=" . $month . '.txt');
while ($row=mysql_fetch_array($res))
{
$writestring = $row['data_I_want'] . "\r\n";
fwrite($handle, $writestring);
}
fclose($handle);
If I run this, then the file is created, but my file doesn't contain the data that I want. Instead I get a dump from the HTML-file in my browser..
What am I doing wrong..
Thanks,
Xpoes
Below script will help you download the file created
//Below is where you create particular month's text file
$file=$month . '.txt';
$handle=fopen($file, "w");
while ($row=mysql_fetch_array($res)){
$writestring = $row['data_I_want'] . "\r\n";
fwrite($handle, $writestring);
}
fclose($handle);
//Now the file is ready with data from database
//Add below to download the text file created
$filename = $file; //name of the file
$filepath = $file; //location of the file. I have put $file since your file is create on the same folder where this script is
header("Cache-control: private");
header("Content-type: application/force-download");
header("Content-transfer-encoding: binary\n");
header("Content-disposition: attachment; filename=\"$filename\"");
header("Content-Length: ".filesize($filepath));
readfile($filepath);
exit;
Your current code does not output a file, it just sends headers.
in order for your script to work add the following code after your fclose statement.
$data = file_get_contents($file);
echo $data;

HTML source download instead of CSV file

I have below source code (PHP) use to download CSV file
$file_name = date("YmdHis") . ".csv";
Header('Content-Type: text/csv');
Header("Content-disposition: attachment; filename=${file_name }");
Header("Content-type: application/octet-stream; name=${file_name }");
header('Pragma: 1');
header('Cache-control: private, max-age=60, pre-check=30');
session_cache_limiter('private_no_expire');
$csv = $header.$contents;
if (mb_detect_encoding($csv) == 'SJIS-win') {
$csv = mb_convert_encoding($csv, 'UTF-8', 'SJIS-win');
}
echo $csv;
exit;
With $header and $contents is read from database.
This source work fine with Firefox, IE but i got problem with Quihoo360 (an browser of China called : 360安全浏览器). Instead of downloading CSV file with the content read from database, it download csv with the content is the HTML source of the displaying page.
Can someone let me know how to solve this problem.
Thank you very much.
Instead of your content type, try setting it to :
Content-Type: text/plain
See a good list of content types.
Edit: Try this in you PHP:
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=example.csv');
header('Pragma: no-cache');
// echo out the csv file
Use a content-type of application/force-download to force browsers to download your file. I think that is what you're asking for, right?

why doesn't download window appear in browser for long when I export data

I try export data from database to .csv. When I click export link I don't see save window in browser for a very long time if there is quite a lot amount of data. It can be quite confusing if the script looks like hanging for some time and after quite a long time one can see save window in browser.
The code is something like this in controller:
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();
$fileName = $list->list_name . '.csv';
$this->getResponse()->setHeader('Content-Type', 'text/csv; charset=utf-8')
->setHeader('Content-Disposition', 'attachment; filename="'. $fileName . '"');
$contacts = new Contact();
$contacts->export($listId);
Export method reads records one by one and prints it something like this:
$fp = fopen('php://output', 'w');
foreach ($mongodbCursor as $subscriber) {
$row = formRow($subscriber);
fputcsv($fp, $row);
}
I see on some applications that save winow appear almost immediately and when you click save you see progress of downloading.
I tried to replace:
$this->getResponse()->setHeader('Content-Type', 'text/csv; charset=utf-8')
->setHeader('Content-Disposition', 'attachment; filename="'. $fileName . '"');
with this one:
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="'. $fileName . '"');
It didn't help so far.
I wonder if it's possible to send headers before all data are read one by one from database?
Thank your for your assistance.
Hmm I'm not familiar with php://output, my application writes my information with fopen,fwrite,fclose to a temporary file afterwards I give it out with similiar header(); options.
$filesize = filesize("tmp/export.csv");
header("Content-Type: text/csv");
header("Content-Disposition: attachment; filename=\"export.csv\"");
header("Conent-Length: $filesize");
readfile("tmp/export.csv");
unlink("tmp/export.csv");
exit;
This one gives the download window of your browser instantly.
You could try to do this:
call the header function instead of $this->getResponse()->setHeader() (the response content might be saved in a buffer and outputed only when it is completed - the time the export finishes)
try to echo the content directly instead of writing to php://output (if you set the headers before that, everything you echo will be placed in the generated CSV file)
EDIT
Replace fputcsv with a function like print_row below
function print_row($row) {
echo '"' . implode('","', $row) . '"' . "\r\n";
}
The function gets the first parameter as an array, adds " and , and echoes to content.
// $file = path of file
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
Source: http://php.net/manual/en/function.readfile.php
Try using application/force-download instead of text/csv in your Content-Type value.
header("Content-Type: application/force-download; name=\"" . $fileName . "\"");
This will force an actual download box instead of just showing the content in the browser.
Here is some documentation from MIME Application:
Mime application/force-download, which is typically expressed as mime application/x-force-download, is typically used in conjunction with PHP code to trigger a download box rather than for displaying content in a Web browser.
For example, if you had a file on your website that you want the user to download rather than view in the Web browser, you could enter the appropriate mime application/force-download code in the file’s header content type field. Note that mime application/force-download is not a registered MIME type. In addition, when used in PHP code, the preferred spelling of mime application/force-download contains the “x-” prefix.
I don't know if this a good solution, I didn't explore it much, but it seems it's working.
It cotroller after I add some data to buffer after headers, before exporting.
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="'. $fileName . '"');
echo str_pad('', ini_get('output_buffering'));
ob_flush();
flush();
Model_Subscriber1::exportList($listId);
To make it works in controller I added in Zend Bootstrap.php:
/**
* hint to the dispatcher that it should not use output buffering to capture output generated by action controllers.
* By default, the dispatcher captures any output and appends it to the response object body content.
*/
protected function _initFront()
{
$frontController = Zend_Controller_Front::getInstance();
$frontController->setParam('disableOutputBuffering', 1);
}
It look like in this case I get download window in browser quickly and then data are exporting which could take quite a long time. I don't know if this solution is acceptable now. I'd be glad to here your opinion about it.
It cause issues with adding empty data to export file.
So, I change it controller to.
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="'. $fileName . '"');
Model_Subscriber1::exportList($listId);
And chang function for export to something like this:
foreach ($mongodbCursor as $subscriber) {
$row = formRow($subscriber);
echo '"' . implode('","', $row) . '"' . "\r\n";
ob_flush();
flush();
}
Your function may want to call flush / ob_flush just before long operation and let the HTTP header send to client before long process.

Categories