I have created a HTML5 app that allows the user to download calendar entries in iCal format. These iCals are created using PHP. My approach until today is to generate the iCal file using PHP and writing it to hard disk on the web server. After that I pass the URL to this file to the front-end (JavaScript) so that it can be opened using the window.open() command.
This approach has the drawback that more and more files are being created on hard disk. I understood that there must be another way by adding a specific header to the response sent by the PHP iCal generator. Is this true?
I tried using these headers:
header('Content-type: application/force-download; charset=utf-8');
header('Content-Disposition: attachment; filename="eintrag.ics"');
When calling the PHP generation file directly, the iCal file is correctly displayed in the browser for being opened. But when I am calling this PHP file using AJAX from my HTML5 app, nothing happens.
What am I doing wrong?
Cheers
AJAX is "behind the scenes" communication between the user's browser and the server. Requesting data via AJAX will not display it to the user automatically, it simply delivers it to the browser. You are then responsible for acting with that data (displaying it on the page, sending it to the user, etc).
Without knowing more about your architecture, you could try something like (jQuery):
$.get('ical/', { param1: 'val', param2: 'val'}, function(response) {
// we can let the user decide to download the new ical
message = 'Your iCal is ready, click <a href="' + response.icalPath + '">here to download it';
$('.message').html(message);
// or force the user's browser to download the ical file directly
window.location.href = response.icalPath;
});
PHP:
// beep boop ... generate iCal
// return the new iCal path to the HTML5 app
return json_encode(array('success' => true, 'icalPath' => 'tmp/icals/generated.ical'));
If you really don't want to store the iCal on disk, then you can use a less flexible solution like:
window.location.href = '/ical?param=1¶m=2';
PHP would read the GET parameters, generate the iCal in memory and return with the headers you specified before.
Related
So my application generates pdf files using TCPDF, and that works fine. That is done inside php file, called with ajax. I'm using embed tag to preview them like:
$.ajax({
url: 'create_pdf_file.php',
success: function(){
/* https://stackoverflow.com/questions/17083018/jquery-loads-cached-file-inside-ajax-success-function */
$('#pdf_placeholder embed').attr('src','output/my_file.pdf?v=' + Math.random()');
}
});
Because many users could generate my_file.pdf at the same time, there could be a case when one user will preview a file generated for another user. So my question at this point is how to force TCPDF to output directly into that tag, not using temp file
Output('my_file','I')
not working here after ajax.
There is an advice here to echo pdf directly back, but i don't know how to do that or is it possible at all. Anyway will try with success(data) to receive that like json.
Other workaround is to give session-bond file name for each user, but is using session_id() and appending to the file name is safe? Most probably I will end with generating UID for each session.
Any general advices are welcome.
You should try passing what TCPDF will produce in a way widely used in embeding images: Data Uri
Embedding Base64 Images
This however might choke browser - i haven't test this.
I would rather save pdf file on server, print filename to browser or other ID of produced file so it could be read with "success" of the ajax request. Then calmly pass proper filename to Embed element. If you wish to do it more safely you can encode it using already used session-exclusive data like session cookie or data that is assosiated with that cookie on a server. You can bond pdf file access to IP that sent request to produce it and timestamp of request that caused production.
I am looking to see if such a scenario is possible -
My website hosts couple of mp3 files. The URL would look like www.abc.com/.mp3 .
Assume that I get an incoming request from a user on iOS/android, using his browser to access my mp3 link above
My question is, can i listen to the event (that of my website mp3 being accessed) and then send send another mp3 to the user?
I am looking at using PHP and javascript, maybe, to do this. Please direct me on the approach to do this.
If you want to use php or javascript as said in your question, I can imagine two solutions for you problem on client side (javascript) or server side (php) :
On client side, using javascript, you can wrap the call to the mp3 in a javascript function (maybe by ajax). This function will check the browser and depending on it get the proper mp3
On server side, using php, you may wrap the mp3 query in a PHP script, say getmp3.php?file=xxx.mp3. Your client page will not get the mp3 directly but ask it to this php script. This script will check User Agent and send the mp3 with something like :
// Get the asked mp3
$askedfile = _GET['file'];
// Get browser info
$browser = get_browser(null);
// Put filename to the proper mp3 file depending on the browser
$filename = ...;
// Put the proper content/type :
header('Content-Type: audio/mp3');
header('Content-Disposition: attachment; filename="$askedfile"');
header('Content-Length: '.filesize($file));
// Send the mp3
readfile($filename);
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Downloading Via JQuery AJAX Post not working
filedownload.php has below snippent.
$file = 'cut.png';
header("Content-Type: image/png");
header('Content-Disposition: attachment; filename="'.$file.'"');
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
readfile($file);
exit();
AJAX Call
jQuery.post('filedownload.php',{
'file' : result // not used for the time being
});
I make an ajax call to the filedownload.php file. It does not allow user to download the file. But If I run the php directly it allows user to download the file. What could be the issue ?
I would like to use core functions rather than using jQuery Plugins. If it's not possible a plugin would be fine.
Given that I use ajax because the page can not be refreshed.
The Problem
Let's take the example of a productivity web app such as a spreadsheet
editor, which has the ability to open, save, import and export. The
open and save options would involve loading a spreadsheet from the
database, whereas import and export deal with local files on the
user's machine. To implement the export behavior, you might decide
that the user should have to save their spreadsheet first, allowing
you to export the data from the backend to file. But let's assume
instead you'd like to allow users to export their data without saving,
perhaps to afford them the option of working locally without ever
storing data on the server. In order to do this, you'd need to send
the current spreadsheet data to the backend and receive a file to
download. Unfortunately, this can not be handled using Ajax, since
Ajax can only receive responses in the form of text. In cases where
the data to be saved is rather lengthy, this poses a considerable
problem.
The Workaround
In order to make the request, you'd need to make a regular (not Ajax)
HTTP request using GET or POST. If the data is reasonably short, you
might get away with a GET request (perhaps by simply setting
Window.location to your export url), but due to varying browser
limitations on GET request length, a POST will most likely be needed.
The following plugin allows you to make a request that returns a file
in a similar syntax to jQuery's native Ajax functions.
jQuery Code Which fixes the problem
jQuery.download = function(url, data, method){
//url and data options required
if( url && data ){
//data can be string of parameters or array/object
data = typeof data == 'string' ? data : jQuery.param(data);
//split params into form inputs
var inputs = '';
jQuery.each(data.split('&'), function(){
var pair = this.split('=');
inputs+='<input type="hidden" name="'+ pair[0] +'" value="'+ pair[1] +'" />';
});
//send request
jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
.appendTo('body').submit().remove();
};
};
How to call
$.download('filedownload.php','filename='+filename );
Read more
I've got a large form where the user is allowed to input many different fields, and when they're done I need to send the contents of the form to the server, process it, and then spit out a .txt file containing the results of the processing for them to download. Now, I'm all set except for the download part. Setting the headers on the response to the jQuery .post() doesn't seem to work. Is there any other way than doing some sort of iframe trick to make this work (a la JavaScript/jQuery to download file via POST with JSON data)?
Again, I'm sending data to the server, processing it, and then would like to just echo out the result with headers to prompt a download dialog. I don't want to write the result to disk, offer that for download, and then delete the file from the server.
Don't use AJAX. There is no cross-browser way to force the browser to show a save-as dialog in JavaScript for some arbitrary blob of data received from the server via AJAX. If you want the browser to interpret the results of a HTTP POST request (in this case, offering a download dialog) then don't issue the request via AJAX.
If you need to perform some kind of validation via AJAX, you'll have to do a two step process where your validation occurs via AJAX, and then the download is started by redirecting the browser to the URL where the .txt file can be found.
Found this thread while struggling with similar issue. Here's the workaround I ended up using:
$.post('genFile.php', {data : data}, function(url) {
$("body").append("<iframe src='download.php?url="+url+"' style='display: none;'></iframe>");
});
genFile.php creates the file in staging location using a randomly generated string for filename.
download.php reads the generated file, sets the MIME type and disposition (allowing to prompt using a predefined name instead of the random string in the actual filename), returns the file content and cleans up by deleting the source file.
[edit] might as well share the PHP code...
download.php:
<?php
$fname = "/tmp/".$_GET['url'];
header('Content-Type: text/xml');
header('Content-Disposition: attachment; filename="plan.xml"');
echo file_get_contents($fname);
unlink ($fname);
?>
genFile.php:
<?php
$length = 12;
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = substr( str_shuffle( $chars ), 0, $length ).'.xml';
$fh = fopen(('tmp/'.$str), 'w') or die("can't open file");
fwrite($fh,$_POST["data"]);
fclose($fh);
echo $str;
?>
Rather than using jQuery's .post(), you should just do a normal POST by submitting the form, and have the server respond with appropriate Content-Encoding and MIME-type headers. You can't trigger a download through post() because jQuery encapsulates the returned data.
One thing I see in use rather frequently, though, is this:
$.post('generateFile.php', function(data) {
// generateFile builds data and stores it in a
// temporary location on the server, and returns
// the URL to the requester.
// For example, http://mysite.com/getFile.php?id=12345
// Open a new window to the returned URL which
// should prompt a download, assuming the server
// is sending the correct headers:
window.open(data);
});
I am using Yii Framework, TCPDF and jQuery to generate a pdf.
The pdf is generated by inputing in a form and submitting it using ajax.
The pdf is created but here is the problem when it returns to the client, it down not download.
here is the php code
$pdf->Output('Folder Label.pdf','D');
the jQuery on success function has
success: function(data) {
window.open(data);
}
Which i got from this site.
Can you please help
If the problem is that you are not getting the browser's download dialog for the PDF, then the solution is to do it this way:
First, redirect the browser (using window.location as the other answers say) to navigate to a special controller action in your application, e.g. with this url: http://your.application.com/download/pdf/filename.pdf.
Implement the action referenced in the URL like this:
public function actionPdf() {
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="filename.pdf";');
header('Content-Length: '.filesize('path/to/pdf'));
readfile('path/to/pdf');
Yii::app()->end();
}
This will cause the browser to download the file.
You need to save the PDF to somewhere on your server and then issue window.location = '/url/to/pdf-you-just-saved.pdf'; from your javascript. The users browser will then prompt them to download the PDF file.
in tcpdf , just pass this argument the Output method:
$pdf->Output('yourfilename.pdf', 'D');
that's all
Not quite, that will cause errors on some browsers, this is the correct way to set the window location.
window.location.assign( downloadUrlToPdf );
So
Send a request to make the pdf via Ajax to the server
Process and generate the pdf on the server
Return in the Ajax call the url to the file you just made
Use the above code fragment to open a download of said file