I have a JSON string I pass through an Ajax call when triggering a button.
The first thing I would like to be able to do and understand would be to pass the variable back in a generated file without saving it to server.
The strange thing that happens here is that the variable value is retrieved by the callback function and is displayed by the alert(data) call,
while the POST variable is recognised as empty and the JS script brings me to a blank process-data.php page.
When taking off the empty() condition I still get the variable displayed properly
but instead of having a blank page I get a 0 octet file to download.
Could this be a server problem, for info I'm running MAMP?
thanks for your answers.
Here is the HTML code
<button onclick="aCall()" button type="submit" formmethod="post"> DL "x" value as text </button>
Ajax code:
function aCall(){
$.ajax({
url: 'process-data.php',
type: 'POST',
data: {'value': [{x:250,y:300}]}, //that's an example
success: function(data){
alert(data);
window.location = 'process-data.php';
}
});
}
Here is the PHP code:
<?php
if (!empty($_POST['value'])) //I get a blank page with that condition on and a file if off.
{
$filename = 'test.txt';
header("Content-Description: File Transfer");
header("Content-Length: ". filesize("$filename").";");
header("Content-Disposition: attachment; filename=$filename");
header("Content-Type: application/octet-stream; ");
header("Content-Transfer-Encoding: binary");
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
header('Pragma: public');
echo $_POST['value'][0]['x'];
exit;
}
?>
in short here is what I get.
HTML -> AJAX -> PHP -> echo myValue
|
|
empty file <----------|
or Blank page |
|
popup |
showing the <---------'
variable's
value
Modify like this, no need of json_decode
From
if (!empty(json_decode($_POST['value'])))
To
if(isset($_POST['value']) && !empty($_POST['value']))
and
From
echo $json[0]->x;
to
echo $_POST['value'][0]['x'];
Related
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;
today i need some help, i know its not that hard and there is a lot of help for doing this in php in this site but i couldn't find nothing with AJAX, the technology im learning now and i want to master some day.
My code is the following.
$(".descarga").click(function(){
var paquete={idArchivo:$(this).val()};
$.post("includes/descargarPublicacion.php",paquete,procesarDatos);
});
So when a buttom from the "descarga" class i make a "packet", which i use it with the post method to send the data to the php file called descargarPublicacion.php
This is how it looks the php file:
<?php
session_start();
$mysqli = new mysqli("localhost", "root", "", "registroflashback");
if (isset($_GET['idArchivo'])) {
header("Content-type: application/vnd.msword");
header("Cache-Control: must-revalidate,post-check=0, pre-check=0");
header("Content-disposition:attachment;filename=yeaboi.doc");
header("Expires: 0");
$idPubliGet=$_GET['idArchivo'];
$resultadoBusqueda=$mysqli->query("SELECT * FROM publicaciones WHERE idPubli='$idPubliGet'");
if ($resultadoBusqueda->num_rows>0) {
//$resultadoBusqueda['titulo'];
echo 'descarga exitosa';
}else{
echo 'descarga no exitosa';
}
}else{
echo 'descarga no exitosa';
}
?>
I made a little research and people told me to use the headers to convert the file and download it, but it dosnt works for me, it dosnt generates any file, however it executes the "echo descarga exitosa" which i use as return value for the following function in the js file.
function procesarDatos(datos_devueltos){
alert(datos_devueltos);
if(datos_devueltos=="descarga exitosa"){
$("#alertaDescarga").show(1000);
}
if(datos_devueltos!="descarga exitosa"){
$("#alertaDescargaError").show(1000);
}
}
How i could generate a .doc file from html using ajax and jquery? I know i have it almost, it should be some detail but i dont know which one is, thats why im asking some experienced help! Thank you !
I do not understand why you want to to serve the .doc file via ajax. In my opinion it's easier to just provide valid .doc over a normal GET Request.
$(".descarga").click(function(){
//onClick transfer id via Get-Param and download file
window.location = "includes/descargarPublicacion.php?idArchivo="+$(this).val();
});
php part (descargarPublicacion.php)
<?php
if (isset($_GET['idArchivo'])) {
header("Content-type: application/vnd.msword");
header("Cache-Control: must-revalidate,post-check=0, pre-check=0");
header("Content-disposition:attachment;filename=yeaboi.doc");
header("Expires: 0");
//ID is available via GET because we send it as Url Param
$idPubliGet=$_GET['idArchivo'];
//#TODO fetch relevant data with given ID
//#TODO generate valid(!) doc File output
//- just echo'ing something will not result in an valid document for Word
echo $coumentContent;
}
?>
To provide/generate a valid Word document is a little bit more complicated. I would recommend you to look into a libary which does all the work for you.
E.g. https://github.com/PHPOffice/PHPWord
If you instead want to serve just some simple .txt File - change your header Content-Type to text/plain and the filename to yeaboi.txt and print/echo out the text-content
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.
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!!
I'm making a PNG image file from a dataURL string (thanks to the example from The PHP manual). I'd like this code to open the "Download file" dialog in the browser, so users can save this image locally, but calling the function imagepng() saves the image to my server instead. Am I using the wrong function when calling imagepng()? I'm trying to trigger a download by changing the headers, but it's still saving to the server.
<?php
$data = 'iVBORw0KGgoAAAANSUhEUgAAABwAAAASCAMAAAB/2U7WAAAABl'
. 'BMVEUAAAD///+l2Z/dAAAASUlEQVR4XqWQUQoAIAxC2/0vXZDr'
. 'EX4IJTRkb7lobNUStXsB0jIXIAMSsQnWlsV+wULF4Avk9fLq2r'
. '8a5HSE35Q3eO2XP1A1wQkZSgETvDtKdQAAAABJRU5ErkJggg==';
$data = base64_decode($data);
$im = imagecreatefromstring($data);
// set the headers, to trigger a download
header('Content-Disposition: attachment; filename="image.png"');
header('Content-Type: image/png');
imagepng($im, 'test_2.png');
imagedestroy($im);
?>
Also, I'm calling the PHP via the following JavaScript, (not sure if this is relevant to the results I'm getting)
$.ajax({
type: "POST",
url: "php/downloadimg.php",
dataType: 'text',
data: {
data : finishedImage.src
}
})
just call the imagepng function without the second parameter. if you follow the imagepng documentation you read that filling in the second parameter the image is saved to this filename.
pass only the image resource to the function and the raw image are send to the client.
http://php.net/manual/de/function.imagepng.php
header('Content-Disposition: attachment; filename="image.png"');
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
if you use php only files don't use the php close tag ?> to avoid leaked whitespaces and messed up your output stream.
It's worth noting that since you've already got the image data in PHP, there's no need to call the imagepng function or anything like it. All you need to do is dump your image data to the client after you set the headers, which will then decide for itself what to do with it.
So, something like this will work if you don't need to actually process the image server side:
<?php
$data = 'iVBORw0KGgoAAAANSUhEUgAAABwAAAASCAMAAAB/2U7WAAAABl'
. 'BMVEUAAAD///+l2Z/dAAAASUlEQVR4XqWQUQoAIAxC2/0vXZDr'
. 'EX4IJTRkb7lobNUStXsB0jIXIAMSsQnWlsV+wULF4Avk9fLq2r'
. '8a5HSE35Q3eO2XP1A1wQkZSgETvDtKdQAAAABJRU5ErkJggg==';
$data = base64_decode($data);
// set the headers, to trigger a download
header('Content-Disposition: attachment; filename="image.png"');
header('Content-Type: image/png');
echo $data;
?>