I am trying to download a CSV file with PHP but I can not make it to get the dialog box.
I have changed the headers and used the readfile() function as shown here
This is my code:
$nodeId = 'something';
$filename = "/var/www/dkar/ruralBroadband/ruralApp/rural/csvExports/$nodeId.csv";
header('Content-type: text/csv');
header('Content-disposition: attachment; filename ="report.csv"');
readfile($filename);
** EDIT **
Tried also with this as suggested:
header('Content-Disposition: attachment; filename="report.csv"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize('report.csv'));
When I am checking the response in Firebug I can see the whole CSV file returned. Also the headers change into:
Content-Type text/csv
Content-disposition attachment; filename ="report.csv"
So I can not figure out why I dont get the dialog box to save the file.
Add these headers:
header('Content-Disposition: inline; filename="report.csv"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($filename));
After all I didn't use the above method and I did that, which works fine and its more straight forward:
var ajaxurl = 'exportNodeData.php', // script to run
data = {nodeId:nodeId}; // data to pass
$.post(ajaxurl, data, function (response) {
document.location.href = 'https://www.ruralauditor.gr/csvExports/'+nodeId+'.zip';
});
This is the ajax request, which I execute in order to create the CSV file (which is also zipped). I then use this line:
document.location.href = 'https://www.ruralauditor.gr/csvExports/'+nodeId+'.zip';
in order to force the download of the file.
Related
I have website which uses ajax for most of cases. I have allowed user to upload image through ajax. When user clicks on a button the image is displayed in modal through an ajax call.
Now, I want to user to begin his download by clicking on image without closing the modal or refreshing. I did tried with href. It works fine but, as I mentioned, I want to keep user on same page with modal open.
The code I have tried untill now is:
$(document).ready(function(){
var imgname;
imgname = '';
$("#modalimage").click(function(){
imgname = $("#downloadimg").val();
downloadImage(imgname);
})
})
function downloadImage(imagename){
$.ajax({
type : "POST",
url : "download.php",
data : { imagename : imagename } ,
success : function(response){
alert('success');
}
})
}
download.php code is:
if ( isset($_POST['imagename']) ) {
$filename = $_POST['imagename'];
$filepath = 'images/'.$filename;
}
echo $filepath;
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($filepath));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
readfile($filepath);
The problem here is when ajax make call to download.php it create a response in form of some binary codes and small image codes without initiating the download. Is it possible to download the image by ajax call?
Instead of calling it by ajax place this link:
<a href="download.php?imagename=<?php echo urldecode($imagename); ?>">
Clich here to download
</a>
where $imagename is the file path. And the link content can be the text or a thumbnail or whatever you want.
And just change the download.php code to get the image through $_GET and not $_POST and, important, remove the echo that there is in there, there should be no other content than the headers and the file content:
if ( isset($_GET['imagename']) ) {
$filename = $_GET['imagename'];
$filepath = 'images/'.$filename;
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($filepath));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
readfile($filepath);
You will not be redirected to the file and the file will be downloaded. No need of ajax for this.
In case you really prefer using javascript you could create the link dinamically:
$(document).ready(function(){
$("#modalimage").click(function(){
var imgname = $("#downloadimg").val();
var link = document.createElement("a");
link.download = name;
link.href = 'download.php?imagename=' + encodeURI(imgname);
link.click();
});
})
I'm trying to view files (i.e: excel sheets/pdf/images) on browser that are stored in database.
I already wrote a code for downloading the files from the database and it is working but I want to display it in the browser.
Here is the code:
<?php require_once('Connections/databasestudents.php'); ?>
<?php
$id = $_GET['id']; // ID of entry you wish to view. To use this enter "view.php?id=x" where x is the entry you wish to view.
$query = "SELECT fileContent, filetype FROM file where id = $id"; //Find the file, pull the filecontents and the filetype
$result = MYSQL_QUERY($query); // run the query
if($row=mysql_fetch_row($result)) // pull the first row of the result into an array(there will only be one)
{
$data = $row[0]; // First bit is the data
$type = $row[1]; // second is the filename
Header( "Content-type: $type"); // Send the header of the approptiate file type, if it's' a image you want it to show as one :)
print $data; // Send the data.
}
else // the id was invalid
{
echo "invalid id";
}
?>
What happens is that view.php is downloaded and nothing is viewed.
Any suggestions?
According to your code, $row[1] is "the filename". The Content type header should contain the content type instead, i.e. the file mime type, for example:
header('Content-type: application/pdf');
If you want to add a filename:
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename='.$row[1]);
print $data;
Be sure $data is the content of the file, something you can take from readfile() for example.
Read more on the manual: http://php.net/manual/en/function.readfile.php
Keep in mind that while PDF and images are easily viewable by a browser, I think Excel needs some ad hoc plugin for that.
A more complete example right out of the manual, to get you a more thorough idea (not all those headers are necessary, and you should change others accordingly to your code):
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;
i have written a code in php which will echo a pdf file.whenever i am trying to echo that pdf,the browser page is changing into gray colors and the loading icon at the bottom left side corner is appearing and after that it fails to show that pdf file.
what i can assure you that code upto fetching the data from databse is perfect.there is no error or mistake.after fetching the data i have used following headers to echo that file.i am not sure about these headers.
$mimetype = 'application/pdf';
$disposition = 'attachment';
header('Content-type: $mimetype');
header('Content-Disposition: inline; filename="$question"');
header('Content-Transfer-Encoding: binary');
header('Content-length: ' . strlen($question));
header('Accept-Ranges: bytes');
echo "$question";
NOTE: I have used .pdf extension in content-decomposition.but that was not fruitful to me.also used readfile() function and it was also not helpful to me. Can anyone tell me what's wrong there?
The main reason why page is changing into gray colors is that the browser is unable to detect content type correctly.
Try this:
header("Content-type: $mimetype");
header('Content-Disposition: inline; filename="'.$question.'"'); // Filename should be there, not the content
Instead of :
header('Content-type: $mimetype');
header('Content-Disposition: inline; filename="$question"');
It seems that you have invalid quotes, so the content type is not specified correctly.
EDIT
To clear out, let's assume that $question is the binary PDF content.
That is what your code should be:
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename=anything.pdf');
header('Content-Transfer-Encoding: binary');
echo $question;
ERRORS EXPLAINED
Let's discuss your original code and your errors.
$mimetype = 'application/pdf';
$disposition = 'attachment';
// First error: you have single quotes here. So output is 'Content-type: $mimetype' instead of the 'Content-type: application/pdf'
header('Content-type: $mimetype');
// Second error. Quotes again. Additionally, $question is CONTENT of your PDF, why is it here?
header('Content-Disposition: inline; filename="$question"');
header('Content-Transfer-Encoding: binary');
// Also bad: strlen() for binary content? What for?
header('Content-length: ' . strlen($question));
header('Accept-Ranges: bytes');
echo "$question";
ONE MORE EDIT
i have another query...i want to change the filename into $year.pdf..$
year may have values like 2007..how can i do that???
Try this :
$year = '2013'; // Assign value
header('Content-Disposition: inline; filename='.$year.'.pdf');
Instead of:
header('Content-Disposition: inline; filename=anything.pdf');
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.
The code below is for two purposes
1) I save a text file on my server in a folder named "backup_db" its working fine mean when I open that text file it contain all the data
2) At the same time i also make this file downloadable for a user so that he could download it for himself and could save it on his hard disk and according to my wish its downloading but unfortunately the .txt file saved on my hard disk is, when open its empty and i don't know why please help me out
//save file
$handle = fopen('backup_db/db-backup-'.date('d-m-Y_H-i-s').'-'.(md5(implode(',',$tables))).'.txt','w+');
$rr = fwrite($handle,$re);
//fclose($handle);
$ww = "db_backup".$rr.".txt";
//$handle = "";
header('Content-Disposition: attachment; filename=' . urlencode($ww));
header('Content-Type: application/force-download');
header('Content-Type: application/octet-stream');
header('Content-Type: application/download');
header('Content-Description: File Transfer');}}
You only set the HTTP header but did not write the file into the response body. Use either fpassthru() or readfile() to write the content of the file directly to the response.
Sample (taken from php.net)
<?php
$file = 'monkey.gif';
if (file_exists($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));
flush();
readfile($file);
exit;
}
?>
BTW:
Settings the same header multiple times simply overwrites the value set before unless you set the second parameter of header() to false.
Your code
header('Content-Type: application/force-download');
header('Content-Type: application/octet-stream');
header('Content-Type: application/download');
results in the following header:
Content-Type: application/download
Sending a file namein the header just gives the user a suggested filename. Try echoing out the contents of the file.
You should add
header("Content-Length: $size")
where $size is size of yout file in bytes.
Check this
ex :
$filename = urlencode($fileName); //download.txt
header("Content-Disposition: attachment; filename=\"" . $filename. "\";" );