Download zip works from html form but not from ajax - javascript

I have this code and it's working fine
HTML
<form method="POST" action="http://example.com/downloadtest.php">
<button type="submit">Submit button</button>
</form>
PHP (downloadtext.php)
header("access-control-allow-origin: *");
$urls = array("www.domain.com/image1.jpg", "www.domain.com/image2.jpg");
//php code do download the images to a temp folder
function createZipfile($folderName) {
// make sure to send all headers first
// Content-Type is the most important one (probably)
//
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="myzip.zip"');
// use popen to execute a unix command pipeline
// and grab the stdout as a php stream
// (you can use proc_open instead if you need to
// control the input of the pipeline too)
//
$fp = popen('zip -r -j - tmp/'.$folderName, 'r');
// pick a bufsize that makes you happy (8192 has been suggested).
$bufsize = 8192;
$buff = '';
while( !feof($fp) ) {
$buff = fread($fp, $bufsize);
echo $buff;
}
pclose($fp);
}
I get a zip-file. But I want to know when all the images are downloaded so I am trying to use ajax insted with jsonp. I am using the same PHP code.
I want to replace the html form with ajax post. I now have this html and javascript (ajax post) instead of the html post form. The php script i still the same.
html
<button class="download-all-images">Download</button>
javascript
$(".download-all-images").click(function(){
$.ajax({
url:"http://example/downloadtest.php",
type: "POST",
dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
success:function(json){
alert("Success ");
},
error:function(e){
alert("Error " + e.message);
}
});
});
I'am not getting any zip file with the ajax method and ajax gives me "Error: undefined". I get "Success" if I comment out the zip-file code but keep the code that downloads the images to a temp folder. My php script is not on the same server as the site (html/javascript). And I get a response with this in my php file
echo $_GET['callback'] . '('.json_encode($urls).')';
if I comment out my zip-function.

Related

Create & download a file on button click

I need to create an excel file (based on some data that are on the server) and download it. All of this when a button is triggered.
What I did for now is to create an HTML button that calls a javascript function.
This javascript function makes an AJAX call to a PHP file that creates the excel file through the library "Spreadsheet" and then supposed to download it.
The excel file is created in the server but the download isn't triggered.
HTML side :
<button type="button" class="btn btn-primary" onclick="downloadExcel()">
Javascript side :
function downloadExcel(){
$.ajax({
url: 'download.php',
type : "POST",
data : { action: "create_sheet"}
});
}
PHP side :
$action = (string)$_POST['action'];
if("create_sheet" == $action) {
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');
$writer = new Xlsx($spreadsheet);
$writer->save('myExcel.xlsx');
ob_clean();
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;
filename="myExcel.xlsx"');
$writer->save("php://output");
exit;
}
The excel file is created but the download isn't triggered.
What am I doing wrong?
Thank you for your help !
EDIT : When I delete the condition on the PHP side and call the download.php as suggested with :
DL
It works
Thank you

Send post variable in AJAX to PHP file for varaible

What should happen:
When button clicked, it calls report.php and sends "main" as type
Type "main" is picked up in report.php and used as $typename
$data varaible is populated with the contents of main.json
What does happen:
> [25-Sep-2018 13:56:56] WARNING: [pool www] child 11 said into stderr: "NOTICE: PHP message: PHP Notice: Undefined index: type in
> /var/www/html/report.php on line 27"
> [25-Sep-2018 13:56:56] WARNING: [pool www] child 11 said into stderr: "NOTICE: PHP message: PHP Warning: file_get_contents(.json):
> failed to open stream: No such file or directory in
> /var/www/html/report.php on line 28"
> 2018/09/25 13:57:00 [error] 8#8: *5 FastCGI sent in stderr: "PHP message: PHP Notice: Undefined index: type in
> /var/www/html/report.php on line 27
index.php
<script>
$(document).ready(function(){
$("button").click(function(){
$.ajax({
url: 'report.php',
type: "POST",
dataType:'json',
data: ({type: main}),
success: function(result){
$("#output").html(result);
}
});
});
});
</script>
report.php
$typename = $_POST['type'];
echo $typename;
$data = file_get_contents("$typename.json");
main.json
{
"reportDescription":{ <....>
}
The problem is that you are trying to send an undefined variable main to your php file. This variable doesn't exist, so you get an error. Strings must be wrapped with single or double quotes.
You should change data: ({type: main}), to
data: {type: 'main'},
(The perenthesis are not needed)
To send the string to your PHP file.
Now in your PHP file, you need to output $data.
$typename = $_POST['type'];
echo $typename;
$data = file_get_contents("$typename.json");
echo $data;
You should change data: {type: 'main'}, as answered before.
But the php code in that answer could be improved. This code could lead to security issues, particularly to a Server Side Request Forgery. You need to set a clear boundary between the user supplied data and your application code, you need to validate the code to avoid some evil uses of file_get_contents:
One can request a random website by http or use another protocol like ssh to connect to other server reachable from your web server
Someone can scan your directories and read operating system files
So, beware what you do with user input, you need to validate it. I would use the following code.
// strip all slashes and directories, use only the filename
$typename = basename($_POST['type']);
$filename = __DIR__.'/'.basename($_POST['type']).".json";
if (!file_exist($filename)){
echo "ERROR";
}
// do not output anything till validated
// echo $typename;
// use a header to tell the user that this is a json file
header('Content-Type: application/json');
$data = file_get_contents($filename);
echo $data;

How to use AJAX and JSON to get data returned from a PHP file

For starters this website is being run on a Debian machine.
I have a SQLite3 database that has current news articles in it. I am trying to use PHP to query the database for these articles, and pass it as JSON to AJAX, so it can be displayed on my webpage. Right now nothing is being shown and I don't know where the error is.
Here is the PHP code to get the information from the database:
<?php
class MyDB extends SQLite3
{
function __construct()
{
$this->open('website.db');
}
}
$db = new MyDB();
$result = $db->query('SELECT * FROM news');
echo json_encode($result);
?>
Here is the JavaScript where the AJAX is located:
<script type="text/javascript">
function getNews()
{
console.log("firstStep");
$(document).ready(function()
{
console.log("secondStep");
$.getJSON("http://localhost/getNews.php",function(result){
console.log("thirdStep");
$('news').append(result); // display result
});
});
}
I think the error is occurring around $.getJSON("http://localhost/getNews.php",function(result), as in the console, thirdStep is never being outputted.
This is the HTML it should be appending to:
<div id = "newsEntry"> <news> test </news> </div>
Any help would be appreciated.
To find out what's going on, you might want to add an error handler:
$(document).ready(function() {
$.ajax({
url: "http://localhost/getNews.php",
dataType: "json",
success: function(result) {
console.log("thirdStep");
},
error: function(err) {
alert(err);
}
});
})
By default, the web server serves content as application/html. So when you simply echo a JSON string, it's treated like text on a html page. To really return JSON from your server, you need to specifically set it.
Include this line before your echo:
header('Content-Type: application/json; charset=utf-8');
Edit
On inspection of you PHP code, you are missing one line. Note that $db->query() returns you an SQLite3Result. You need to call:
$array = $result->fetchArray(SQLITE3_ASSOC); // get an associative array first
$json = json_encode($array);
header('Content-Type: application/json; charset=utf-8');
echo $json

Sending data to PHP page to make a spreadsheet out of it

For some reason, when I try to send JSON data to a PHP page (where it gets downloaded as a spreadsheet), it runs without error, but doesn't bring up the prompt to download the spreadsheet. The JSON has generated without problem (I have made the PHP page create the file on the server, before trying to make it download without creating it).
Here is the JavaScript code that sends the JSON data to the server:
function writeToSpreadsheet()
{
// get the json for #theTable
var tableJSON = tableToJSON("tr:not(#titleRow)");
//alert(tableJSON);
alert("Sending table data to be written to the spreadsheet...");
$.post('/ResearchProject/tableContent/exportTable.php', {'table': tableJSON}).done(
function(response) { alert(((response == '') ? response : (tableJSON.title + ' written to file!')));})
.fail(function (xhr, ajaxOptions, thrownError) { alert("ERROR:" + xhr.responseText+" - "+thrownError); });
}
and here is exportTable.php
<?php
function cleanData(&$str)
{
$str = preg_replace("/\t/", "\\t", $str); // escaping all of the tabs
$str = preg_replace("/\r?\n/", "\\n", $str); // escaping any and all cases of carriage return
// if there is a single double-quote in the string, we wrap the string in quotes, replace every single double-quote with double double-quotes, and
// end with a double-quote
if(strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
}
// the data is coming from a JSON object that is being sent here
if (isset($_POST['table']))
{
$tableJSON = $_POST['table']; # somehow, this is already a PHP array (exactly the one we need)!!
// get the name of the table from the $tableJSON
$tableName = $tableJSON['title'];
// get the title row from $tableJSON
$titleRow = $tableJSON['titleRow'];
// fix the titleRow
foreach ($titleRow as $heading)
{
$heading = trim(preg_replace('/\s+/', ' ', $heading));
}
// get the rows from $tableJSON
$rows = $tableJSON['rows'];
// form the filename from the tableName
$fileName = $tableName . '.xls';
// here, we download the file without even creating it
header("Content-Disposition: attachment; filename=\"$fileName\"");
header("Content-Type: application/vnd.ms-excel");
// we echo the titleRow first
array_walk($titleRow, 'cleanData');
echo implode(chr(9), $titleRow) . "\r\n";
?>
<script>console.log('Title row written to file.');</script>
<?php
// now we echo the data
foreach($rows as $row)
{
array_walk($row, 'cleanData');
echo implode(chr(9), $row) . "\r\n";
?>
<script>console.log('Data row written to file.');</script>
<?php
}
}
else
{
echo 'You sent me no data :(\n';
}
?>
OK, MikeWarren, how do I test this??
You can test it by selecting a table from the dropdown menu and clicking the "Export table to spreadsheet" button here: http://dinotator.biokdd.org/ResearchProject/tableViewer.php
I am trying to have it where the table that is on the HTML page gets converted into an JSON object, and then downloaded. Thus, I would need to POST the data to the PHP page, right? (Query strings don't work.)
Query strings won't work because you are using jQuery's $.post call which means that your data is sent in the body of the request, as opposed to a query string which is what a GET uses. For JSON you do indeed want to use a POST.
As for what's going wrong, you need to decode your JSON into a PHP array using json_decode. Unfortunately it can't simply handle JSON how it is.
So most likely you'll want to do:
// now a poorly named variable
$tableJSON = json_decode($_POST['table']);
Also, looking at your Ajax, $.post does accept a .fail() listener, but it doesn't pass any error data as part of the callback. So if you want to be able to handle incoming response errors you'll need to use $.ajax:
$.ajax({
type: "POST",
url: "/your/url.php",
dataType: "json",
error: errorCallback
});
Finally, looking at how your code is structured, if you're actually trying to save to file, you're going to need some more logic. Right now, you're just rendering that table, and then returning it as a response which will show up in your done function. You're going to add some more logic in order to make it actually download. This question entails your exact problem.
Good luck!
I have found so much bad advice on the internet about how to solve this problem. One of the answers here also didn't work. :(
I have decided to get advice from a friend of mine, and me and him have decided on this approach:
Have my exportData.php simply write the data to $_SESSION, echo a JSON-encoded "success", and then exit
On exit, on the client-side of things, if "success" has been received, have the JavaScript open up a new tab to a file that I have created called downloadFile.php which actually does the downloading.
Why didn't sending the data between files work?
Downloading data entails setting the right headers and printing the data. When you send data to the file to do this (via AJAX), the buffer that the data is printed to is the one for response. You can see this by saying something like
success: function(response)
{
alert(response);
} and see the data that you "downloaded" not get downloaded, but get printed on-screen.
However, if you go to the file instead of simply passing data to it, your data will download, provided that it has access to the data that you are trying to download. You can see examples of this here: www.the-art-of-web.com/php/dataexport/ . In those examples, the data was "static" (that is, only existing in the scope of that PHP file, until download happened).
We then see that we should let another file handle the downloading. Here is what its contents should look like:
<?php
if (!isset($_SESSION))
session_start();
function cleanData(&$str)
{
$str = preg_replace("/\t/", "\\t", $str); // escaping all of the tabs
$str = preg_replace("/\r?\n/", "\\n", $str); // escaping any and all cases of carriage return
// if there is a single double-quote in the string, we wrap the string in quotes, replace every single double-quote with double double-quotes, and
// end with a double-quote
if(strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
}
// get the data from $_SESSION
if (isset($_SESSION))
{
$fileName = $_SESSION['fileName'];
$titleRow = $_SESSION['titleRow'];
$rows = $_SESSION['rows'];
// set the excel headers
header("Content-Type: application/vnd.ms-excel");
//header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$fileName\"");
header("Pragma: no-cache");
header("Expires: 0");
// attempt download
array_walk($titleRow, 'cleanData');
echo implode(chr(9), $titleRow) . "\r\n";
// now we echo the data
foreach($rows as $row)
{
array_walk($row, 'cleanData');
echo implode(chr(9), $row) . "\r\n";
}
}
else
{
die('Problem with session variable. Data could not be sent for download.');
}
exit;
?>
Of course, before doing this, make sure that you have 'fileName', 'titleRow', and 'rows' already written to $_SESSION.
This should help anyone having problem downloading HTML table to Excel spreadsheet via PHP, and the best part is that you don't have to bloat your server by downloading an entire library, for potentially the functionality of one button!!

How to have PHP in JavaScript?

I tried embedding PHP in my JavaScript code to see what happens. Nothing actually happened. Can someone suggest me a way to do this?
<head>
<script>
function myF() {
n=document.getElementById("name").value
r=document.getElementById("reason").value
<?php
$f = fopen("VisitorLog.txt", "w");
fwrite($f, "Profile viewed on "+Date()+" by "+n+" Reason= "+r);
fclose($f);
?>
document.getElementById("name").disabled=true;
document.getElementById("reason").disabled=true;
document.getElementById("register").disabled=true;
document.getElementById("link").style.display="inline";
alert("You have successfully registered.");
}
</script>
</head>
I'm new to all this stuff and still learning. Please try explaining in simpler terms. :P
First keep in mind that PHP is rendered on the server and Javascript will be interpreted at your client(Web browser). so if you echo something from PHP it will be sent with the html and it won't be executed with the Javascript as you are assuming here.
To accomplish what you want here you need to make an AJAX call to a PHP script which will update your views log.
Edit:
on update.php file
<?php
$n = $_POST['n'];
$r = $_POST['r'];
$f = fopen("VisitorLog.txt", "w");
fwrite($f,"Profile viewed on ".date("Y-m-d H:i:s")." by ".$n." Reason= "+$r);
fclose($f);
And on your javascript (assuming you have jquery loaded)
<script>
function myF()
{
$.post("update.php",
{
n : document.getElementById("name").value,
r : document.getElementById("reason").value
},
function({
document.getElementById("name").disabled=true;
document.getElementById("reason").disabled=true;
document.getElementById("register").disabled=true;
document.getElementById("link").style.display="inline";
alert("You have successfully registered.");
}));
}
</script>
The main concept you need to understand is that Javascript runs on the client side, namely the web browser, and PHP on the server. The PHP code you have added to your page is executed before any Javascript is processed.
If you want your Javascript to send data to your PHP application you need to use Ajax.
Using libraries such as jQuery will make your life a lot easier.
Here's an example of how that can work using jQuery.
PHP - log.php
<?php
$string = sprintf('Profile viewed on %s by %s Reason= %s',
$_POST['date'], $_POST['name'], $_POST['reason']);
$f = fopen("VisitorLog.txt", "w");
fwrite($f, $string);
fclose($f);
?>
Javascript
var n = $("#name").val();
var r = $("#reason").val();
var d = new Date();
$.ajax({
url: '/path/to/log.php',
method: 'POST',
data: {name: n, reason: r, date: d}
}).done(function(response){
// response contains the output of log.php
});
Reference
http://api.jquery.com/id-selector/
http://api.jquery.com/jQuery.ajax/
PHP is rendered on server-side. JavaScript is rendered on client-side.
Like everyone said. You can't mix server side code with client side code.. php is renderd/executed at server side an js in the client's browser..
If possible separate js and php. A working solution could be: (assuming jQuery for the ajax call, actually another framework or even plain js could be used)
in your js file (or in the script tag in the header)
function log(message, success, failure){
$.ajax({
url: "logger.php",
data: {
message: message
},
success: success,
error: failure
})
}
function myF(){
var n=document.getElementById("name").value,
r=document.getElementById("reason").value;
log( "Profile viewed on "+Date()+" by "+n+" Reason= "+r, function(){
console.log('I successfully logged');
}, function(jqXHR, textStatus, errorThrown){
console.log('something went wrong', jqXHR, textStatus, errorThrown);
});
document.getElementById("name").disabled=true;
document.getElementById("reason").disabled=true;
document.getElementById("register").disabled=true;
document.getElementById("link").style.display="inline";
alert("You have successfully registered.");
}
in a file logger.php
<?php
if(isset($_GET['message'])){
$f = fopen("VisitorLog.txt", "w");
fwrite($f, $_GET['message']);
fclose($f);
}
?>
PhP is executed on the server, before the page loads. So your PhP will execute, then the page loads. Then the javascript loads. So your javascript here will not trigger the PhP.
The two ways to do this:
- Run the PhP script when the page laods on the server
- Use AJAX to run a server-side php script to register the userdetails.
Javascript runs on the client side, php runs on the server side. You need to make e.g. an ajax call to some method on the server side that will do server-side tasks.
Only the server can interpret and run the php code. Make sure that the file you are editing is stored in a server with php installed (you can try WAMP or XAMPP if you want to test locally in your computer).

Categories

Resources