Trying to download a file which is dynamically generated by the the data posted. I have the results coming back. I'm just not sure how I can save the results into a proper file locally once the information (stream) is returned from the server.
Here is the ajax call:
function download_pdf(){
alert("made it" + result_array);
$.ajax({
type: "POST",
url: "report_generation/downlaod_pdf.php",
data: { result_array: result_array },
success: function(results){
alert(results);
},
error:
function(xmlHttpRequest, status, error){
alert(xmlHttpRequest + "| ajax failure: could not download haq report | " + status + " | error:" + error);
var xmlHttpRequestStr = "";
for(var x in xmlHttpRequest)
xmlHttpRequestStr = xmlHttpRequestStr + xmlHttpRequest[x];
alert(xmlHttpRequestStr);
}
});
}
This function is called from a hyperlink like so, and the success method is returning...
<a class="haq_button" href="javascript:download_pdf()"><span>Download Report As PDF</span></a>
UPDATE: Here is a snippet of code from the file generation in download_pdf
// set the headers, prevent caching
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Disposition: attachment; filename=\"$file_name\"");
// set appropriate headers for attachment or streamed file
if ($is_attachment) {
header("Content-Disposition: attachment; filename=\"$output_file_name\"");
}
else {
header('Content-Disposition: inline;');
header('Content-Transfer-Encoding: binary');
}
// set the mime type based on extension, add yours if needed.
$ctype_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"pdf" => "application/pdf",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
);
$ctype = isset($content_types[$file_ext]) ? $content_types[$file_ext] : $ctype_default;
header("Content-Type: " . $ctype);
//check if http_range is sent by browser (or download manager)
if(isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if ($size_unit == 'bytes')
{
//multiple ranges could be specified at the same time, but for simplicity only serve the first range
//http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
header('HTTP/1.1 416 Requested Range Not Satisfiable');
exit;
}
}
else
{
$range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1))
{
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
header('Content-Length: '.($seek_end - $seek_start + 1));
}
else
header("Content-Length: $file_size");
header('Accept-Ranges: bytes');
set_time_limit(0);
fseek($file, $seek_start);
while(!feof($file))
{
print(#fread($file, 1024*8));
ob_flush();
flush();
if (connection_status()!=0)
{
#fclose($file);
exit;
}
}
// file save was a success
#fclose($file);
exit;
It's not posible. Only you can do is to open new browser window with that PDF url or change location of current window like that: window.location = 'report_generation/downlaod_pdf.php';
This is not possible using javascript/ajax. You have to use regural download link, or in your case form. If you want to have some error handling using javascript if pdf generation fails and still keep the same page open, you can submit into a hidden iframe.
You can create a dynamic form and submit it, it will open a new window/tab and if it fails you can show a message in that page. In anyway, the right way to handle and track an exception is not on the receiver, but sender (download_pdf.php)
To create a dynamic form:
var VerifyForm = document.createElement("form");
VerifyForm.target = "_blank"; //You must specify here your target
VerifyForm.method = "POST";
VerifyForm.action = "download_pdf.php";
var dataInput = document.createElement("input");
dataInput.type = "hidden";
dataInput.name = "mydata"; //var name
dataInput.value = value; //var value
VerifyForm.appendChild(dataInput); //Apend var to form, repeat for n
document.body.appendChild(VerifyForm);
VerifyForm.submit();
If you still try to it at your own way, is impossible, I recommend you read more about what means the capital "A" in "Ajax"
You can try to force the download of the file by adding these HTTP headers in the downlaod_pdf.php
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: public");
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=$your_file_name");
header("Content-Transfer-Encoding: binary");
readfile($your_file_content);
EDIT : and also add window.location.href = your_php_script_path in the js file
Related
PHP $_SERVER does not return HTTP_range key and without that key how can I perform a "resume download" or download in chunks?
if (isset($_SERVER['HTTP_RANGE'])) {
echo "find";
} else{
echo "not find";
}
i can't get $_SERVER['HTTP_RANGE'] from server .......
There is no key HTTP_RANGE when i print $_SERVER
===================================================
<?php
// get the file request, throw error if nothing supplied
// hide notices
#ini_set('error_reporting', E_ALL & ~ E_NOTICE);
//- turn off compression on the server
#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 'Off');
if(!isset($_REQUEST['file']) || empty($_REQUEST['file']))
{
header("HTTP/1.0 400 Bad Request");
exit;
}
// sanitize the file request, keep just the name and extension
// also, replaces the file location with a preset one ('./myfiles/' in this example)
$file_path = $_REQUEST['file'];
$path_parts = pathinfo($file_path);
$file_name = $path_parts['basename'];
$file_ext = $path_parts['extension'];
$file_path = './myfiles/' . $file_name;
// allow a file to be streamed instead of sent as an attachment
$is_attachment = isset($_REQUEST['stream']) ? false : true;
// make sure the file exists
if (is_file($file_path))
{
$file_size = filesize($file_path);
$file = #fopen($file_path,"rb");
if ($file)
{
// set the headers, prevent caching
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Disposition: attachment; filename=\"$file_name\"");
// set appropriate headers for attachment or streamed file
if ($is_attachment) {
header("Content-Disposition: attachment; filename=\"$file_name\"");
}
else {
header('Content-Disposition: inline;');
header('Content-Transfer-Encoding: binary');
}
// set the mime type based on extension, add yours if needed.
$ctype_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
);
$ctype = isset($content_types[$file_ext]) ? $content_types[$file_ext] : $ctype_default;
header("Content-Type: " . $ctype);
//check if http_range is sent by browser (or download manager)
if(isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if ($size_unit == 'bytes')
{
//multiple ranges could be specified at the same time, but for simplicity only serve the first range
//http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
header('HTTP/1.1 416 Requested Range Not Satisfiable');
exit;
}
}
else
{
$range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1))
{
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
header('Content-Length: '.($seek_end - $seek_start + 1));
}
else
header("Content-Length: $file_size");
header('Accept-Ranges: bytes');
set_time_limit(0);
fseek($file, $seek_start);
while(!feof($file))
{
print(#fread($file, 1024*8));
ob_flush();
flush();
if (connection_status()!=0)
{
#fclose($file);
exit;
}
}
// file save was a success
#fclose($file);
exit;
}
else
{
// file couldn't be opened
header("HTTP/1.0 500 Internal Server Error");
exit;
}
}
else
{
// file does not exist
header("HTTP/1.0 404 Not Found");
exit;
}
?>
My code is this in php file for downloading any file but resume capability showing unknown plz can u suggest me the code for that functionality
its my php page to download a file, have to change code or what to do for changing resume capability in idm ?
if(!isset($_SESSION['user_id'])){
header('location:../index.php');}
$uname=$_SESSION['uname'];
$uid= $_SESSION['user_id'];
function output_file($file, $name, $mime_type='')
{
/*
This function takes a path to a file to output ($file), the filename that the browser will see ($name) and the MIME type of the file ($mime_type, optional).
*/
//Check the file premission
//if(!is_readable($file)) die('File not found or inaccessible!');
$size = filesize($file);
$name = rawurldecode($name);
/* Figure out the MIME type | Check in array */
$known_mime_types=array(
"pdf" => "application/pdf",
"txt" => "text/plain",
"html" => "text/html",
"htm" => "text/html",
"exe" => "application/octet-stream",
"zip" => "application/zip",
"doc" => "application/msword",
"xls" => "application/vnd.ms-excel",
"ppt" => "application/vnd.ms-powerpoint",
"gif" => "image/gif",
"png" => "image/png",
"jpeg"=> "image/jpg",
"jpg" => "image/jpg",
"php" => "text/plain"
);
if($mime_type==''){
$file_extension = strtolower(substr(strrchr($file,"."),1));
if(array_key_exists($file_extension, $known_mime_types)){
$mime_type=$known_mime_types[$file_extension];
} else {
$mime_type="application/force-download";
};
};
//turn off output buffering to decrease cpu usage
#ob_end_clean();
// required for IE, otherwise Content-Disposition may be ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: ' . $mime_type);
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
header('Content-Length: 2052595');
header('Content-Range: bytes 339843-2392437/2392438');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']))
{
list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
list($range) = explode(",",$range,2);
list($range, $range_end) = explode("-", $range);
$range=intval($range);
if(!$range_end) {
$range_end=$size-1;
} else {
$range_end=intval($range_end);
}
$new_length = $range_end-$range+1;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $new_length");
header("Content-Range: bytes $range-$range_end/$size");
} else {
$new_length=$size;
header("Content-Length: ".$size);
}
/* Will output the file itself */
$chunksize = 3*(1024*1024); //you may want to change this
$bytes_send = 0;
if ($file = fopen($file, 'r'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length)
)
{
$buffer = fread($file, $chunksize);
print($buffer); //echo($buffer); // can also possible
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
} else
//If no permissiion
die('Error - can not open file.');
//die
die();
}
//Set the time out
set_time_limit(0);
$temp = explode("\\", $_REQUEST['filename']);
//path to the file
$file_path=$_REQUEST['filename'];
//Call the download function with file path,file name and file type
output_file($file_path, ''.$temp[3].'', 'text/plain');
?>
<?php
$uname=$_COOKIE["uname"];
//echo $uname;
$file=$_REQUEST['filename'];
$file_name="E:\\upload\\$uname\\$file";
$fid=$_REQUEST['fid'];
$con=mysql_connect("localhost","root","Net#123");
$db=mysql_select_db("file_storage",$con);
$query1=mysql_query("SELECT * FROM upload WHERE file_id=$fid");
$row1=mysql_fetch_array($query1);
if($row1)
{
$file_db=$row1['name'];
// If the requested file is exist
if(file_exists($file_name)){
// Get the file size
$file_size=filesize($file_name);
// Open the file
$fh=fopen($file_name, "r");
// Download speed in KB/s
$speed=1024;
//Initialize the range of bytes to be transferred
$start=0;
$end=$file_size-1;
//Check HTTP_RANGE variable
if(isset($_SERVER['HTTP_RANGE']) &&
preg_match('/^bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $arr)){
// Starting byte
$start=$arr[1];
if($arr[2]){
// Ending byte
$end=$arr[2];
}
}
//Check if starting and ending byte is valid
if($start>$end || $start>=$file_size){
header("HTTP/1.1 416 Requested Range Not Satisfiable");
header("Content-Length: 0");
}
else{
// For the first time download
if($start==0 && $end==$file_size){
// Send HTTP OK header
header("HTTP/1.1 200 OK");
}
else{
// For resume download
// Send Partial Content header
header("HTTP/1.1 206 Partial Content");
// Send Content-Range header
header("Content-Range: bytes ".$start."-".$end."/".$file_size);
}
// Bytes left
$left=$end-$start+1;
// Send the other headers
header("Content-Type: application/octet-stream");
header("Accept-Ranges: bytes");
// Content length should be the bytes left
header("Content-Length: ".$left);
header("Content-Disposition: attachment; filename=".$file_db);
// Read file from the given starting bytes
fseek($fh, $start);
// Loop while there are bytes left
while($left>0){
// Bytes to be transferred
// according to the defined speed
$bytes=$speed*1024;
// Read file per size
echo fread($fh, $bytes);
// Flush the content to client
flush();
// Substract bytes left with the tranferred bytes
$left-=$bytes;
// Delay for 1 second
sleep(1);
}
}
fclose($fh);
}
else{
//If the requested file is not exist
//Display error message
echo "File not found!";
}
}
exit();
?>
This code worked for , files are downloading with resume capability...
Please see the RFC on headers on how to report your capabilities to your clients:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
14.5 Accept-Ranges
The Accept-Ranges response-header field allows the server to
indicate its acceptance of range requests for a resource:
Accept-Ranges = "Accept-Ranges" ":" acceptable-ranges
acceptable-ranges = 1#range-unit | "none"
Origin servers that accept byte-range requests MAY send
Accept-Ranges: bytes
but are not required to do so. Clients MAY generate byte-range
requests without having received this header for the resource
involved. Range units are defined in section 3.12.
Servers that do not accept any kind of range request for a
resource MAY send
Accept-Ranges: none
to advise the client not to attempt a range request.
i have created this application which creates a csv file from given list from DB and than allows user to download it! When i finished the job i came to realise that there is a security issues!
Here is the ajas i am using to make a request:
$.ajax({
type: "POST",
url:HTTPS + '/lib/model/data/ctlRates.php?export=1',
data: {
ext: ext,
filter: filter,
fileName: fileName
},
dataType: 'json',
success: function(data){
if(data['results'] == "success"){
console.log(data['results']);
var filename = data['filename'];
var extension = data['ext'];
window.location = HTTPS + '/lib/model/data/ctlRates.php download=1&filename='+filename+'&ext='+extension;
} else {
console.log(data['results']);
}
}
});
} else {
alert("Error: File name and extension must be provided");
}
});
And i imagine that most of you already sees the problem!
but here is the controller to which window.location is pointing:
if(isset($_GET['download']) && $_GET['download'] == 1){
$filePath = "/path/to/file/dir";
$name = $_GET['filename'];
$extension = $_GET['ext'];
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header('Content-Description: File Transfer');
header('Content-type: text/'.$extension.'');
header('Content-Disposition: attachment; filename="'.$name.".".$extension.'');
header("Content-Transfer-Encoding: binary");
header("Pragma: public");
ob_clean();
flush();
readfile($filePath.$name.".".$extension);
}
Started testing and came to realize that everyone can ender filename and extension they pleases and get files from that directory....Any ideas how to burry this hole?
And i imagine that most of you already sees the problem!
Not really - there are very few security issues i javascript - and this does not exhibit any of them - the problem is how you are procesing your data server-side. Do not attempt to server security holes with javascript changes.
If you want to restrict access to a specific directory tree...
if(isset($_GET['download']) && $_GET['download'] == 1){
$filePath = "/path/to/file/dir";
$fetchfrom = realpath($filepath . '/'
. /* basename( */ $name /* ) */
. "." . $extension);
if (substr($fetchfrom, 0, strlen($filepath))!=$filepath) {
header("HTTP/1.0 404 Not Found");
print "Directory traversal not allowed";
exit;
}
This question already has answers here:
PHP generate file for download then redirect
(11 answers)
Closed 3 years ago.
Page 1 links to page 2. Page 2 serves a download using the following code:
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/pdf');
readfile($file);
header("location: mainpage.php");
The result being the user "stays" on page 1 but is served a download.
How can I set things up, so that users remain on page 1 but it refreshes after the download is served.
I don't know javascript so I am hoping for a purely PHP solution.
In my opinion I wouldn't think you would necessarily need to refresh page1 at all. You should be able to force the download via a link within page1. See below:
Page1.php with a link
Download PDF
Page2.php
$filename = $_GET['pdf'] . '.pdf';
header('Content-type: application/pdf');
header("Content-disposition: attachment; filename= '$filename'");
header("location: $filename");
This will allow the download to start whilst you remain on page1.
Hope this is what you had in mind.
Didn't know of this before, but it's just one of the nice HTTP headers and most of us already know of it from HTML: Refresh.
Just add the following header call:
header('Refresh: 0; url=http://stackoverflow.com/');
You can check what the referer is by $_SERVER['HTTP_REFERER']. So you should be able to put this in you're page1.php:
if($_SERVER['HTTP_REFERER'] == page2.php) {
echo "<meta http-equiv=\"refresh\" content=\"0;url=http://www.yourdomain.com/page1.php\">";
exit();
}
This way, you check if your visitor is coming from page2.php, and if they are, you only parse a meta-tag which refresh the browser. When it is refreshed, it wouldn't refresh again, because the HTTP_REFERER is now page1.php.
No sure if you ever got this answered, but I had the same problem,
here is my solution
The AJAX jquery
$(function(){
$("#itemList").on("click", "a.downloadLink", function(){ //this binds a click event handler on the itemList container that will listen out for any a with class of downloadLink inside it being clicked
var link = $(this);
var item = link.parent();
var forId = item.data("itemid");
var started = new Date(); //the alternative to tracking time elapsed is to just use a simple counter you increment - "poll 5 times" etc. if your doing .5 second intervals, then 5 times = 2.5 seconds for example. Time elapsed may result in less polls, if a poll takes a long time to return, for example. Use whichever approach feels better.
var maxTime = 5000; //5 seconds
function poll(){
$.ajax({
type: "POST",
url: "Watergetstatus.php",
data: {FID: forId}, //this will be turned into a request for page1?forId=1&oldValue=2 - I expect it in this example to return a json-encoded response of {"changed":true|false, "newHtml":"replacementContent on success"}
datatype :'json',
success: function(data){
if (data.changed=true)
{
window.location.reload(true);
}
else {
var elapsed = (new Date())-started;
//window.location.reload(true);
if (elapsed <= maxTime) setTimeout(poll, 500); // Poll again in .5 seconds
//else you can assume the link didn't open / work / the database never changed etc - handle or ignore as needed
}
},
error: function() {
alert("borken"); //the request to the server bombed out; up to you if you want to simply re-queue for another try like above until the expiry time or if you want to show an error or just simply ignore it.
}
});
}
setTimeout(poll, 500); //wait 0.5 seconds before polling
});
});
The HTML had a large list of dynamic links
<div data-itemid="<?php echo $row_Files['FID']; ?> " >
<a class="downloadLink" href="PLC_FILES/WaterCheckOut.php?FID=<?php echo $row_Files['FID']; ?> " target=""><img src="PLCImages/download.fw.png"></a>
</div>
The Poling file watergetstatus.php
mysql_select_db($database_PLC, $PLC);
$query_files = "SELECT * FROM files WHERE FID = '{$_POST['FID']}'";
$files = mysql_query($query_files, $PLC) or die(mysql_error());
$row_files = mysql_fetch_assoc($files);
$totalRows_files = mysql_num_rows($files);
if($row_files['Status'] ==2)
{
$data= array("changed"=>true);
echo json_encode($data);
}
else
{
$data= array("changed"=>false);
echo json_encode($data);
}
THe download file link watercheckout.php
if ( $row_files['Status']==1 ) {
$file_path = $row_files['FileName'];;
$path_parts = pathinfo($file_path);
$file_name = $path_parts['basename'];
$file_ext = $path_parts['extension'];
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
);
$ctype = isset($content_types[$file_ext]) ? $content_types[$file_ext] : $ctype_default;
$file = $row_files['FileName'];
$path = "Historical/".date('Y-m-d-His');
$newfile = $path."_".$file;
$today = date('Y-m-d H:i:s');
header('Content-disposition: attachment; filename='.$file);
header("Content-Type: " . $ctype);
header('Content-Length: ' . filesize($file));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
mysql_select_db($database_PLC, $PLC);
mysql_query("UPDATE files SET Status = '2'");
ob_clean();
flush();
readfile($file);
rename($file, $newfile);
I have simplified my code and cut out alot, so it may be missing something, but this was the general frame work that I used and it works for me
Hope this helps someone, as there was not much out there
//----------------- TOP OF DOWNLOAD_PAGE.PHP ----------------------
$download_code = mysql_real_escape_string(urldecode($_GET['code']));
$download = mysql_real_escape_string(urldecode($_GET['download']));
$self = $_SERVER["PHP_SELF"]."?code=$download_code";
//refresh page after download...
echo"
<script type=\"text/javascript\">
function downloadRedirect(){
var redirect_url = \"$self\";
setTimeout(\"DoTheRedirect('\"+redirect_url+\"')\",
parseInt(0.5*1000));
}
function DoTheRedirect(url) { window.location=url; }
</script>
";
...
$filepath = "/var/www/vhosts/YOUR_DOMAIN.com/digital_downloads/";
if (isset($_GET['download'])) {
$file = $_GET['download'];
if (file_exists($filepath.$download) &&
is_readable($filepath.$download) && (preg_match('/\.zip$/',$download) || preg_match('/\.zipx$/',$download) )) {
...
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$download."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filepath.$download));
ob_end_flush();
readfile($filepath.$download);
}//end if file_exists
}//end if isset
//----------------- BOTTOM HALF OF DOWNLOAD_PAGE.PHP ----------------------
//link generated to download and call JS to refresh page
echo "Click to Download
I am trying to append some details in to a file and add that for download.
I am using JavaScript and PHP for this purpose.. Clicking download button, it will fire an AJAX request.
$.ajax({
url:"php/test.php",
type: 'POST',
data: { totalQuery : test1, },
success: function(finalEntityList){
},
});
Lets assume test.php has a single line code
$html="Test";
Now I want to add this to a file and make it available for download. I've used the code
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=data.csv');
$output = fopen('php://output', 'w');
fwrite($output, $html);
fclose($output);
But the download will not start automatcially... I've to open the POST request link using firebug so that the download will be initiated.. what could be wrong??
Perhaps what you need to do is simply return the path of the file with your AJAX call and then use JavaScript to "initiate" the download by using one of the following -
window.open
window.location.href
$.ajax({
url:"php/test.php",
type: 'POST',
dataType: 'json',
data: { totalQuery : test1, },
success: function(response){
// initiate download using direct path to file
window.location.href = response.URL;
}
});
Now your test.php file will only need to return the URL path for the download file in a JSON format -
$filename = 'data.csv';
$path = $_SERVER['DOCUMENT_ROOT'].'/downloads/';
echo json_encode(array('URL'=>$path.$filename));
You might consider returning the URL as a raw string - but I feel using JSON might be better because you can easily add additional information in to the response without needing additional parsing functions. All this makes it a more robust choice.
It requires some more parameters and headerinfo:
$file = "data.csv";
$mime_type = "text/csv";
$size = filesize($file);
$name = rawurldecode($name);
#ob_end_clean(); //turn off output buffering to decrease cpu usage
// required for IE, otherwise Content-Disposition may be ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: ' . $mime_type);
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']))
{
list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
list($range) = explode(",",$range,2);
list($range, $range_end) = explode("-", $range);
$range=intval($range);
if(!$range_end)
{
$range_end=$size-1;
}
else
{
$range_end=intval($range_end);
}
$new_length = $range_end-$range+1;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $new_length");
header("Content-Range: bytes $range-$range_end/$size");
}
else
{
$new_length=$size;
header("Content-Length: ".$size);
}
/* output the file itself */
$chunksize = 1*(1024*1024); //you may want to change this
$bytes_send = 0;
if ($file = fopen($file, 'r'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while(!feof($file) && (!connection_aborted()) && ($bytes_send<$new_length))
{
$buffer = fread($file, $chunksize);
print($buffer); //echo($buffer); // is also possible
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
}
else
die('Error - can not open file.');