PHP download not working (download function not called) - javascript

I need to export data from a database through a webapp. And when I call the function with ajax post method. The file is created successfully on the server, but after that it is not downloading it, the download function is not called, somehow, or it is not working. I don't know the reason, and I don't get any error messages.
Here is my jQuery function that sets post data for the php:
$(document).ready(function(){
$('#exportCSV').click(function(){
var ajaxurl = 'admin.php?page=site&edit=false',
data = {'export': 'csv'};
$.post(ajaxurl, data, function (response) {
});
});
});
A switch that runs the selected file export function, than tries to download it
switch ($_POST['export']) {
case 'csv':
$query = $_SESSION['query'];
$FName=exportToCSV($conn,$query,$fName);
download($FName);
break;
}
And the download script that is not called, or is not working correctly
function download($file){
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$file");
header("Content-Length: ".filesize($file));
header("Content-Type: application/csv");
header("Content-Transfer-Encoding: binary");
readfile($file);
}
And this is how this "site" is called.
Everything above is in the "somesite.php" file
if(isset($_GET['page'])){
switch ($_GET['page']) {
case 'site':
include("somesite.php");
break;
}
}

Related

Ajax function not calling php script

So I'm making a Image gallery site, and I have a bunch of buttons such as approve image, and download image, which call the JS function "runAJAX" and based on the request type, the php is supposed to prefore a specific task. The issue I'm having is that the AJAX function is saying it's successfully run, but the php file is not being run. When I run it, "Request Completed" prints but no txt file is created like it supposed to. Any help would be greatly appreceated. Thank you very much.
// imageID is an int of the image UID
// request is a string that describes the button (approve, download etc.)
function runAJAX(imageID, request) {
// myArr is a JSON array
var myArr = allJSON;
console.log("UID is" + imageID);
for (var i = 0; i < myArr.length; i++){
if (myArr[i].UID == imageID){
switch (request) {
case "approve": myArr[i].approved = "true"; console.log("Approve was set to true"); break;
case "download": console.log("Image will be downloaded"); break;
default: console.log("No action will be done for this request");
} // switch
} // if
} // for
$.ajax({
type: "POST",
url: 'requestAJAX.php',
data: {request: request, newJSON: JSON.stringify(myArr), download: imageID},
success: function(){
console.log("Request Completed: " + request);
window.location.reload(false);
} // success
});
} // runAJAX
requestAJAX.php
<?php
switch ($_POST["request"]) {
case "approve":
// output to checking to see what the request is
touch("AJAXtest.txt");
file_put_contents("AJAXtest.txt", $_POST["request"]);
unlink("test.json");
$stringyJSON = json_decode($_POST["newJSON"], true);
$finalJSON = json_encode($stringyJSON, JSON_PRETTY_PRINT);
$file = "galleryinfo.json";
touch($file);
file_put_contents($file, $finalJSON);
break;
case "download":
// output for checking to see what the request is
touch("AJAXtest.txt");
file_put_contents("AJAXtest.txt", $_POST["request"]);
// Get parameters
$file = $_POST["download"];
$filepath = "UploadedImages/" . $file;
if(file_exists($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));
flush(); // Flush system output buffer
readfile($filepath);
exit;
} // if
break:
default:
// output for checking to see what the request is
touch("AJAXtest.txt");
file_put_contents("AJAXtest.txt", "No request made");
echo "No request was made";
}
?>

fileDownload.js jQuery plugin and PHP headers

I am using this great jquery.fileDownload.js plugin to allow users to download self-generated CSV files from my website.
From what I understood, based in the PHP code from this site (suggested by fileDownload creator), I need to set a cookie to identify when the download is sucessfull or not:
try {
$page = file_get_contents($filepath);
echo $page;
header('Set-Cookie: fileDownload=true; path=/');
} catch(Exception $e) {
header('Set-Cookie: fileDownload=false; path=/');
}
It works as expected when fileDownload=true, but fail event is never fired when fileDownload=false.
Here is my javascript code:
$.fileDownload('export.php')
.done(function() {
alert('Done!');
})
.fail(function() {
alert('Fail!');
});
And here is my export.php code:
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate');
header('Content-type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="file.csv"');
try {
// Code for generating the CSV file
header('Set-Cookie: fileDownload=true; path=/');
} catch(Exception $e) {
header('Set-Cookie: fileDownload=false; path=/');
}
exit;
When file is generated correcly I got the success message, but never get the fail message, even when simulating an issue.
Please, what I am missing? Thank you!
It looks like the cookie is only used to check if a download was completed, but not to assess failure. But it does catch HTTP errors, so the solution is simply sending a 500 from the server:
try {
$page = file_get_contents($filepath);
echo $page;
header('Set-Cookie: fileDownload=true; path=/');
} catch(Exception $e) {
http_response_code(500);
}

Save txt file from javascript with ajax call to PHP

Edit: I have a solution of sorts, but I do not understand why ajax is not working. Please see the edit below.
I want to save a txt file generated in javascript to the client machine.
I want the user to remain on the same webpage.
I am doing it via ajax with a call to a php page.
I want it to work in all major pc browsers; Chrome, Firefox, Internet Explorer and Edge.
Here is what I have so far:
htmlsave.js
dataARR = {
SaveFile: "This is the content.\nLine2.\nLine3"
};
var dataJSON = JSON.stringify(dataARR);
$.ajax({
type: "POST",
url: "htmlsave.php",
async: true,
cache: false,
crossDomain: false,
data: { myJson: dataJSON },
success: function (data) {
alert("success");
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("failure");
}
});
htmlsave.php
<?php
if(!isset($_POST) || !isset($_POST['myJson'])) {
exit(0);
}
$data = json_decode($_POST['myJson'], true);
if(!array_key_exists('SaveFile', $data) || !isset($data['SaveFile'])){
exit(0);
}
$contents = strval($data['SaveFile']);
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); // required for certain browsers
header("Content-Type: text/plain");
header("Content-Disposition: attachment; filename=\"mysavefile.txt\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . strlen($contents));
ob_clean();
flush();
echo $contents;
?>
What comes back (ie the data argument in success) is "This is the content.\nLine2.\nLine3".
There is no prompt to save the file with content "This is the content.\nLine2.\nLine3" as I had hoped.
Edit: A solution (but not a great one)
I have done a bit of tinkering and have something that works, in a fashion. Instead of calling through ajax I write in my javascript
document.location = "htmlsave.php?myJson=Line1Line2";
and in my php I have altered it to a get with
if(!isset($_GET) || !isset($_GET['myJson'])) {
exit(0);
}
$contents = $_GET['myJson'];
This works. This will be ok for small files, but I wanted to do reasonably large text files, and even zipped using lzw encoding. Anyone know why Ajax is not working?
Make sure your htmlsave.php starts with
<?php
If it does, see if your webserver is configured to pass .php files to your php implementation (fpm, mod_php, etc...)

extjs Hidden form after download not firing success

Scouring the net for how to separate the download data from the success/fail data when doing a download using a standardsubmit in extjs, and can't find anything specific about how to do this.
For example, I have a hidden form that I am using to force a download:
var hiddenForm = Ext.create('Ext.form.FormPanel', {
standardSubmit: true,
height: 0,
width: 0,
hidden: true
});
hiddenForm.getForm().submit({
url: 'downloadtxt.php',
method: 'POST',
success: function(form, action) {
console.log('success');
},
failure: function(form, action) {
console.log('failure');
}
});
and on the server in PHP I have this code:
$file_name = "test.txt";
$file_data = "The text to save in the file";
header("Content-Type: " . "text/plain");
header("Content-Length: " . strlen($file_data));
header("Content-Disposition: attachment; filename=\"" . $file_name . "\"");
$result["success"] = true;
$result["errors"] = array();
$result["data"] = $file_data;
echo json_encode($result);
In this case, the entire contents of the $result array gets put into the download file (effectively buggering the contents, and additionally the success/fail methods never get called in the submit() code. Now, if I change the PHP server code to:
$file_name = "test.txt";
$file_data = "The text to save in the file";
header("Content-Type: " . "text/plain");
header("Content-Length: " . strlen($file_data));
header("Content-Disposition: attachment; filename=\"" . $file_name . "\"");
echo $file_data;
then the downloaded file contains what I expected ("The text to save in the file"), but the success/fail methods still never get called in the submit() code. How is it possible to trigger the success/fail code, but yet not bugger up the contents of the download file?

Is it possible to save & retrieve the data filled in HTML form to/from xml file stored locally on PC?

I've recently made an HTML form to fill some service reports & now want to save & retrieve them on/from PC itself (preferably in xml format) (not on server).
I'hv checked it on w3scools /on this page too but still I couldn't get the desired solution.
Could you please inform me the possible ways to make it happen.
You can examine the Javascript behind this application (http://www.cloudformatter.com/Nimbus) like this page here:
Sample Nimbus Invoice
This code shows (1) data in the editor area being saved to local storage constantly, (2) option to make a pseudo HTML/XML file and download to disk (Save to ... Disk), (3) option to make that same package and save to storage on the web (New Nimble, Save Nimble). I am not going to go through all the code, the most relevant is here below for saving locally to disk a package stored in the variable "archive":
function SaveFile(archive) {
var textToBLOB = new Blob([archive.innerHTML], { type: 'text/xml' });
var sFileName = 'varypackage.html';
var newLink = document.createElement('a');
newLink.download = sFileName;
if (window.webkitURL !== null) {
newLink.href = window.webkitURL.createObjectURL(textToBLOB);
}
else {
newLink.href = window.URL.createObjectURL(textToBLOB);
newLink.style.display = 'none';
document.body.appendChild(newLink);
}
newLink.click();
}
Look here for all the code (which contains much more that just the saving/loading but it is in here): http://www.cloudformatter.com/Resources/pages/varyhtml/script/02_control.js
If I understand you, you want to store the data on the user's computer, is that right?
Then it would be the best to create an XML file and force download to user's computer.
(I'm using jQuery because it's fastest)
STEP 1: make an ajax request.
function downloadFormData(form){
var formData= $(form).serialize(); //form is an DOM element - the form you want to retrieve data from
$.ajax({
url:"save.php",
data: formData,
success: function (file) {
window.location.href = "download.php?path="+ file
}
});
}
2) Create a php file, name it as save.php with the following content in your root directory:
<?php
$xml_string = "<?xml version etc.?><data>";
foreach($_POST as $key=>$value)
$xml_string.='<'.$key.'>'.$value.'</'.$key.'>';
$xml_string.='</data>
$file = 'formData.xml';
// save to file
file_put_contents('./'.$file, $xml_string);
// return the filename
echo $file; exit;
5) Create a php file, name it as download.php with the following content in your root directory
<?php
$file = 'formData.xml'
// $file = trim($_GET['path']); if you use download.php for anything else
// force user to download the file
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/xml');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
unlink($file);
exit;
}
else {
echo "$file not found";
}
I hope you understand the way this works, because you definetly can't leave everything like that (then users could download any file they wanted), but i hope my answer will help you.
EDIT:
a PURE javascript solution
function createXMLandDownload(form){
var a = document.createElement("a");
a.download = "MyXml.xml"; //downloaded file name
a.addEventListener("click" , function (){
var xmlstring = '<?xml version="1.0" encoding="utf-8"?><data>';
$(form).find(":input").each(function(){
xmlstring+="<"+this.name+">"+this.value+"</"+this.name+">";
}
xmlstring+="</data>";
document.open('data:Application/octet-stream,' + encodeURIComponent(xmlstring ));
});
a.click();
}

Categories