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
Related
My script works like that :
I make an AJAX call to a PHP script
The PHP script process a lot of data and writes the result to a .csv file (via fopen/fwrite/fclose)
When the PHP is done, I want my AJAX to open a download pop-up with the resulted file from the call
The last part is the problem here. When I try to make the user download the file, it just returns a 0 byte file.
The problem doesn't come from my PHP script since the file on the server is correctly modified and is the result of the data processing.
I've tried window.open, window.location, appending an anchor with download attribute, download.js, delaying the download, server permissions, etc. Nothing works.
I don't want to go the blob way since it's a lot of server-side data processing, and even if I could, I'm still really wondering why the heck I always get a 0 byte file
My AJAX call :
$.ajax({
url : './dataProcessing.php',
type : 'POST',
dataType : 'text',
success : function(result, status){
console.log(result); //Result being my file path
console.log(status);
window.open(result, '_self'); //One of the many things I've tried
},
error : function(result, status){
console.log(result);
console.log(status);
}
});
My PHP globally consists of :
<?php
$filename = 'myFile.csv';
$resource = fopen($filename, 'w');
//fwrite some lines
fclose($resource);
echo $filename;
?>
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.
I'm beginner to symfony.
I have a twig template with 2 buttons that calls an external .js that executes an ajax call.
Button 1 calls function 'delete', and this is the js code:
var path = $("#abc").attr("data-path");
/*grabs it from some div in the twig template.. <div id="abc" data-path="{{path('delete')}}"></div>*/
function delete(n){
$.ajax({
type: "POST",
url: path,
data: {id : n},
"success":function(data){
alert('ok');
}
});
}
Button 2 calls function 'edit' which is the same code except that the 'url' goes to another 'action', and the 'data' is not a json, (it is data: formData)
Routing.yml for function delete is:
delete:
pattern: /delete
defaults: {_controller: TPMainBundle:Default:delete }
And this is the controller action:
public function deleteAction()
{
$id = $_POST['id'];
/*other code to work with doctrine making queries to delete from database*/
}
(The js code is from a webpage done without symfony and it works fine)
I was told the right way to retrieve the POST in the action, reglardless it was whether a json or formData, was using the same that I used in PHP:
$id = $_POST['id'];
Here, I have 2 problems.
First, I don't know if this is correct because it doesn't work.
Second, I don't know how can I know if i'm retrieving the POST OK !!
When I did this without symfony, I checked if I was getting the POST with the command 'fwrite', because the ajax went to a PHP file instead of an Action, and then with the command fwrite I created a .txt file with the output of an echo to see if the $_POST was recovered or not.
But here in symfony I don't know how to check it, so I'm driving myself crazy.. trying to implement the solutions I read without being sure if they work..
and with the extra problem that since I'm newbie for me it's a bit confusing trying to install some external bundles for debug. Please help
The correct approach for acessing post or get params is using Symfony's Request object. You can pass it as an argument of a controller action, or retrieve it from the controller directly. Here's two examples:
public function deleteAction(Request $request)
{
if ($request->isMethod('POST')) {
$id = $request->get('id');
}
}
Without passing the Request as a parameter:
public function deleteAction()
{
if ($this->getRequest()->isMethod('POST')) {
$id = $this->getRequest()->get('id');
}
}
Extra tip for people who comes from PHP and doesn't know how to check if they are retrieving the POST or not: - send it to a .php
public function deleteAction($request)
{
$id = SOME RETRIEVED CODE YOU AREN'T SURE YOU ARE RETRIEVING THE RIGHT WAY;
/*you can send this variable to a view, symfony allows you to use .php files but you have to name their extension as html.php not just .php*/
return $this->render('TPMainBundle:Default:test.html.php', array('id' => $id));
}
And then, in that view:
<?php
echo $id;
$myfile = fopen("somename.txt", "w") or die("Unable to open file!");
$txt = 'Id is: '.$id;
fwrite($myfile, $txt);
fclose($myfile);
This will generate a .txt
So, you can open the .txt and check if you have recovered the DATA or not!
The file will be located inside the 'web' folder..
The other tips is to check the 'app/log/dev.log' thanks #Zain Saqer
In Symfony you get your POST data from the current Request object (That's how we do it in Symfony), one way to get the current Request object is by adding $request variable as first parameter in your action function.
Your action function could be like this:
public function deleteAction(Request $request)
{
//check if our POST var is there
if($request->request->has('id')){
//it's there
$id = $request->request->get('id');
/*other code to work with doctrine making queries to delete from database*/
}else{
//it's not there!
}
}
Regarding installing third party bundle, use Composer to do this task for you, and don't forget to add the class path of the installed bundle to $bundles array in AppKernal class. Follow this link to know how to do this.
I've read many articles in this site or other sites (Redirect with POST to application/csv without form, jQuery.post(), PHP and redirects, ... ) but without any valuable solutions.
My problem is the following :
in my site (html5, JQuery), there is a table. A feature of the site
is to export the table as a csv file which will be available for
download,
This feature is implemented as follow :
2.1 a javascript is called which extracts the data of the table,
2.2 this JS redirect to a php service and pass as arguments the datas. The code is the
following :
var url= jmcnet.request.getOrigin()+'/commons/php/dt_csv_export.php' ;
location.href = url+"?action=generate&csv_type=export_task&csv_data=" +encodeURIComponent(csv);
2.3 The php script format the input (csv_data parameter), write a temporay file and returns the content of the temporary file. The code is the following :
$h = #fopen($csv_file_name, 'w');
fputcsv($h, $csv_row, ',', '"');
fclose($h);
// export file content to JS
header('Content-Encoding: UTF-8');
header('Content-Type: text/ csv; charset =UTF-8');
header('Content-Disposition: attachment; filename=export-table.csv');
header(' Pragma: no-cache');
echo "\xEF\xBB\xBF"; // UTF-8 BOM
readfile($csv_file_name);
2.4 The php file delete (unlink) the temporary file and exit,
My problem is that when the table is long, the URL called is not valid and the JS call to Php is down.
So, I imagine the 3 following solutions but no one is evident and all leads to other problems :
S1 : dont do a GET but a POST in JS. So the size of the csv_data
doesn't matter anymore. The problem is that I will have the content
of the csv file in JS var after the call succeed and I don't know or
find how to redirect to a page which content is in a JS var ? I
guess I will lose all header information doing this.
S2 : compress in JS the csv_data parameter and decompress it in Php.
I just don't know how to do that and if it possible ....
S3 : call the php with a POST. Modify the Php to return the URL of
the temporary file, and do a redirect in JS to this temporay URL.
The problems are that my Php must generate a file into a dir
directly visible on the Internet, the file name must be unique and
there is no way to simply delete the file after it has been read by
browser (and I hate cron or what else).
I'm sure I'm not the first one to have this problem, so I need your help to see what is the best practice for this problem.
I think you may be over-complicating this just a bit. There is no need for all of the JS redirect stuff, you can just point your forms action attribute to your csv_export php code and use POST to send your data.
if needed, you can modify the max size of a post request by editing the post_max_size option in your php.ini. heres what mine looks like:
; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; http://php.net/post-max-size
post_max_size = 8M
as for writing to a temporary file, php has built in I/O streams to handle that. for your purposes you'll probably want to use php://memory or php://temp (more info on those here: http://www.php.net/manual/en/wrappers.php.php)
so you can do something like this:
SAMPLE HTML:
<html>
<head>
<!-- include jquery because you say you are using it -->
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
//just a dummy function to represent your js to extract csv data from a table
function extract_table_data(){
var csv = "field1,field2,field3\n\
value1,value2,value3\n\
value4,value5,value5";
return csv;
}
$( document ).ready(function() {
//export link click handler
$('#export_link').click(function() {
$('#csv_data').val(extract_table_data());
$('#theform').submit();
});
});
</script>
</head>
<body>
<a id='export_link'>Export CSV</a>
<form id='theform' method='post' action='dropcsv.php'>
<input type='hidden' name='csv_data' id='csv_data'/>
</form>
</body>
</html>
dropcsv.php
//filename for our csv attachment
$export_filename = 'thefile.csv';
//grab csv data
$csv_data = $_POST['csv_data'];
//open file in memory
$f = fopen('php://memory', 'w'); //use php://temp if you want a tmp file instead
//load up csv file
fwrite($f, $csv_data);
// go back to the beginning of the file
fseek($f, 0);
header('Content-Type: application/csv');
header('Content-Disposition: attachement; filename="'.$export_filename.'"');
fpassthru($f);
fclose($f);
of course don't forget to add your error checking and sanitize the input.
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).