I'm trying to dynamically create data in JavaScript that downloads with a .csv extension, but am unable to associate a filename with the download. Here's a code snippet:
var data = '1,2,3';
window.location =
"data:application/csv;charset=UTF-8;content-disposition:attachment;filename=export.csv,"
+ encodeURIComponent(data);
This downloads, but the file name is generic, without a .csv extension.
I can do this server-side, with the following PHP code:
<?php
header('Content-type: text/csv');
header('Content-disposition: attachment;filename=export.csv');
echo "1,2,3";
?>
Additionally, if my back is to the wall, I can modify my Javascript to send an Ajax out to the server and get this in return, but I'd prefer a pure Javascript solution. Is there a browser-independent, Flash-free way of doing this?
EDIT
Someone pointed out this question as a possible duplicate. I did goo-diligence and checked previous SO articles. I am still asking this because some time has passed since those questions, so I am hoping:
Browser features may have changed favorably.
Older browsers are less of a constraint, so certain solutions may be more viable now than when the previous questions were asked.
Additionally, if it makes the question more palpatable, I'm specifically asking about inserting a type of content header into a data URI (as per the subject), which is a twist on the other questions.
Thanks in advance.
Related
I generate some images using a PHP lib.
Sometimes the browser does not load the new generated file.
How can I disable cache just for images created dynamically by me?
Note: I have to use same name for the created images over time.
A common and simple solution to this problem that feels like a hack but is fairly portable is to add a randomly generated query string to each request for the dynamic image.
So, for example -
<img src="image.png" />
Would become
<img src="image.png?dummy=8484744" />
Or
<img src="image.png?dummy=371662" />
From the point of view of the web-server the same file is accessed, but from the point of view of the browser no caching can be performed.
The random number generation can happen either on the server when serving the page (just make sure the page itself isn't cached...), or on the client (using JavaScript).
You will need to verify whether your web-server can cope with this trick.
Browser caching strategies can be controlled by HTTP headers. Remember that they are just a hint, really. Since browsers are terribly inconsistent in this (and any other) field, you'll need several headers to get the desired effect on a range of browsers.
header ("Pragma-directive: no-cache");
header ("Cache-directive: no-cache");
header ("Cache-control: no-cache");
header ("Pragma: no-cache");
header ("Expires: 0");
Solution 1 is not great. It does work, but adding hacky random or timestamped query strings to the end of your image files will make the browser re-download and cache every version of every image, every time a page is loaded, regardless of whether or not the image has changed on the server.
Solution 2 is useless. Adding nocache headers to an image file is not only very difficult to implement, but it's completely impractical because it requires you to predict when it will be needed in advance, the first time you load any image that you think might change at some point in the future.
Enter Etags...
The absolute best way I've found to solve this is to use ETAGS inside a .htaccess file in your images directory. The following tells Apache to send a unique hash to the browser in the image file headers. This hash only ever changes when the image file is modified and this change triggers the browser to reload the image the next time it is requested.
<FilesMatch "\.(jpg|jpeg)$">
FileETag MTime Size
</FilesMatch>
If you need to do it dynamically in the browser using javascript, here is an example...
<img id=graph alt=""
src="http://www.kitco.com/images/live/gold.gif"
/>
<script language="javascript" type="text/javascript">
var d = new Date();
document.getElementById("graph").src =
"http://www.kitco.com/images/live/gold.gif?ver=" +
d.getTime();
</script>
I checked all the answers and the best one seemed to be (which isn't):
<img src="image.png?cache=none">
at first.
However, if you add cache=none parameter (which is static "none" word), it doesn't effect anything, browser still loads from cache.
Solution to this problem was:
<img src="image.png?nocache=<?php echo time(); ?>">
where you basically add unix timestamp to make the parameter dynamic and no cache, it worked.
However, my problem was a little different:
I was loading on the fly generated php chart image, and controlling the page with $_GET parameters. I wanted the image to be read from cache when the URL GET parameter stays the same, and do not cache when the GET parameters change.
To solve this problem, I needed to hash $_GET but since it is array here is the solution:
$chart_hash = md5(implode('-', $_GET));
echo "<img src='/images/mychart.png?hash=$chart_hash'>";
Edit:
Although the above solution works just fine, sometimes you want to serve the cached version UNTIL the file is changed. (with the above solution, it disables the cache for that image completely)
So, to serve cached image from browser UNTIL there is a change in the image file use:
echo "<img src='/images/mychart.png?hash=" . filemtime('mychart.png') . "'>";
filemtime() gets file modification time.
I know this topic is old, but it ranks very well in Google. I found out that putting this in your header works well;
<meta Http-Equiv="Cache-Control" Content="no-cache">
<meta Http-Equiv="Pragma" Content="no-cache">
<meta Http-Equiv="Expires" Content="0">
<meta Http-Equiv="Pragma-directive: no-cache">
<meta Http-Equiv="Cache-directive: no-cache">
I was just looking for a solution to this, and the answers above didn't work in my case (and I have insufficient reputation to comment on them). It turns out that, at least for my use-case and the browser I was using (Chrome on OSX), the only thing that seemed to prevent caching was:
Cache-Control = 'no-store'
For completeness i'm now using all 3 of 'no-cache, no-store, must-revalidate'
So in my case (serving dynamically generated images out of Flask in Python), I had to do the following to hopefully work in as many browsers as possible...
def make_uncached_response(inFile):
response = make_response(inFile)
response.headers['Pragma-Directive'] = 'no-cache'
response.headers['Cache-Directive'] = 'no-cache'
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '0'
return response
Changing the image source is the solution. You can indeed do this by adding a timestamp or random number to the image.
Better would be to add a checksum of eg the data the image represents. This enables caching when possible.
Let's add another solution one to the bunch.
Adding a unique string at the end is a perfect solution.
example.jpg?646413154
Following solution extends this method and provides both the caching capability and fetch a new version when the image is updated.
When the image is updated, the filemtime will be changed.
<?php
$filename = "path/to/images/example.jpg";
$filemtime = filemtime($filename);
?>
Now output the image:
<img src="images/example.jpg?<?php echo $filemtime; ?>" >
i had this problem and overcoming like this.
var newtags='<div class="addedimage"><h5>preview image</h5><img src="'+one+'?nocache='+Math.floor(Math.random() * 1000)+'"></div>';
I've used this to solve my similar problem ... displaying an image counter (from an external provider). It did not refresh always correctly. And after a random parameter was added, all works fine :)
I've appended a date string to ensure refresh at least every minute.
sample code (PHP):
$output .= "<img src=\"http://xy.somecounter.com/?id=1234567890&".date(ymdHi)."\" alt=\"somecounter.com\" style=\"border:none;\">";
That results in a src link like:
http://xy.somecounter.com/?id=1234567890&1207241014
If you have a hardcoded image URL, for example: http://example.com/image.jpg you can use php to add headers to your image.
First you will have to make apache process your jpg as php.
See here:
Is it possible to execute PHP with extension file.php.jpg?
Load the image (imagecreatefromjpeg) from file then add the headers from previous answers. Use php function header to add the headers.
Then output the image with the imagejpeg function.
Please notice that it's very insecure to let php process jpg images. Also please be aware I haven't tested this solution so it is up to you to make it work.
Simple, send one header location.
My site, contains one image, and after upload the image, there not change, then I add this code:
<?php header("Location: pagelocalimage.php"); ?>
Work's for me.
I want to download a file when I click on a link. The file is served dynamically.
Download!
But I need to be able to display error to the user if /server/myfunc?id=XXX link does not provide a file. I can return a boolean false or any http code through this link if file isn't present.
What should be the most appropriate method for this implementation. Note that I do not wish to alter the current state of page in any manner, just trigger the file download without affecting the page. And display error if file is not to be downloaded.
You can't do that only with html as far as it is a static language. I would suggest you to use a 'if/else' clause written in php or java. Here you have some documentation, and a concrete sample here. Anyway here you are a sample that could fit exactly on your case (taking into account you are inserting the php on the html).
<?php
var = url
if (isset($var) && ($var === true){ ?>
Download!
<?php } else { ?>
<p>Hey, there is no URL!</p>
<?php } ?>
I know I am replying very late, But it maybe useful for someone facing this kind of issue.
When using Synchronous HTTP calls, Its very difficult to show error Message as it would replace whole web page instead which we dont want.
So, Its better to use AJAX
Click here JohnCulviner Blog for more details - how to use AJAX for downloads
Also, Go through following SO link Download a file by query Ajax
My question is about PHP security for this particular operation:
I want to use javascript to pull all json files from a particular directory on my web server. I have done like so:
I pull all the correct file names with this PHP script ("get-data.php"):
<?php
echo json_encode(glob('*.json'));
?>
Then I move that array into javascript with
var oReq = new XMLHttpRequest();
oReq.onload = function() {
fileNames = JSON.parse(this.responseText);
};
oReq.open("get", "get-data.php", true);
oReq.send();
Then I use the following to read the files into an array:
function getMapInfo(fileName){
$.get(fileName, function(result) {
var map = JSON.parse(result);
mapData.push(map);
});
}
I got some of this code from here: How to pass variables and data from PHP to JavaScript?
and I have read up on xss a little here and here and it is my understanding that "untrusted data" is data that the user would enter which would then be run in a script? I believe that my above solution doesn't contain unsafe data since it only pulls files that are already on my server, is that correct?
Overall, my question is: is this a safe way to allow my code to retrieve multiple unknown files from my server? Eventually, I want uses to "save" map data to the server which will then be read by the above script for others to see.
Thanks very much,
Jordan
Yes, this is perfectly safe. You will just need to ensure the security is part of the php code when needed, by limiting or filtering what it can select (already fine there) and how .json files are validated and stored, once that is addressed you will be fine and your existing solution is perfectly safe. You can also modify .htaccess file to hide folder content if you have a concern about others viewing directories on your website.
So I've been researching this for a couple days and haven't come up with anything conclusive. I'm trying to create a (very) rudimentary liveblogging setup because I don't want to pay for something like CoverItLive. My process is: Local HTML file > Cloud storage (Dropbox/Drive/etc) > iframe on content page. All that works, and with some CSS even looks pretty nice despite the less-than-awesome approach. But here's the thing: the liveblog itself is made up of an HTML table, and I have to manually copy/paste the code for a new row, fill in the timestamp, write the new message, and save the document (which then syncs with the cloud and shows up in the iframe). To simplify the process I've made another HTML file which I intend to run locally and use to add entries to the table automatically. At the moment it's just a bunch of input boxes and some javascript to automate the timestamp and write the table row from the input data.
Code, as it stands now: http://jsfiddle.net/LukeLC/999bH/
What I'm looking to do from here is find a way to somehow export the generated table data to another .html file on my hard drive. So far I've managed to get this code...
if(document.documentElement && document.documentElement.innerHTML){
var a=document.getElementById("tblive").innerHTML;
a=a.replace(/</g,'<');
var w=window.open();
w.document.open();
w.document.write('<pre><tblive>\n'+a+'\n</tblive></pre>');
w.document.close();
}
}
...to open just the generated table code in a new window, and sure, I can save the source from there, but the whole point is to eliminate steps like that from the process.
How can I tell the page to save the generated code to a separate .html file when I click on the 'submit' button? Again, all of this happens locally, not on a server.
I'm not very good with javascript--and maybe a different language will be necessary--but any help is much appreciated.
I suppose you could do something like this:
var myHTMLDoc = "<html><head><title>mydoc</title></head><body>This is a test page</body></html>";
var uri = "data:application/octet-stream;base64,"+btoa(myHTMLDoc);
document.location = uri;
BTW, btoa might not be cross-browser, I think modern browsers all have it, but older versions of IE don't. AFAIK base64 isn't even needed. you might be able to get away with
var uri = "data:application/octet-stream,"+myHTMLDoc;
Drawbacks with this is that you can't set the filename when it gets saved
You cant do this with javascript but you can have a HTML5 link to open save dialogue:
<a href="pageToDownload.html" download>Download</a>
You could add some smarts to automate it on the processed page after the POST.
fiddle : http://jsfiddle.net/ghQ9M/
Simple answer, you can't.
JavaScript is restricted to perform such operations due to security reasons.
The best way to accomplish that, would be, to call a server page that would write
the new file on the server. Then from javascript perform a POST request to the
server page passing the data you want to write to the new file.
If you want the user to save the page to it's file system, this is a different
problem and the best approach to accomplish that, would be to, notify the user/ask him
to save the page, that page could be your new window like you are doing w.open().
Let me do some demonstration for you:
//assuming you know jquery or are willing to use it :)
var html = $("#tblive").html().replace(/</g, '<');
//generating your download button
$.post('generate_page.php', { content: html })
.done(function( data ) {
var filename = data;
//inject some html to allow user to navigate to the new page (example)
$('#tblive').parent().append(
'Check your Dynamic Page!');
// you data here, is the response from the server so you can return
// your new dynamic page file name here.
// and maybe to some window.location="new page";
});
On the server side, something like this:
<?php
if($_REQUEST["content"]){
$pagename = uniqid("page_", true) . '.html';
file_put_contents($pagename, $_REQUEST["content"]);
echo $pagename;
}
?>
Some notes, I haven't tested the example, but it works in theory.
I assume that with this the effort to implement it should be minimal, assuming this solves your problem.
A server based solution:
You'll need to set up a server (or your PC) to serve your HTML page with headers that tell your browser to download the page instead of processing the HTML markup. If you want to do this on your local machine, you can use software such as WAMP (or MAMP for Mac or LAMP for Linux) that is basically a web server in a .exe. It's a lot of hassle but it'll work.
have a browser program that lets the user play chess - move pieces etc. trying to let the user download the resultant pgn (Content-Type: PGN) directly from browser.
does it have something to do with data:URI? is there some example somewhere?
only interested in modern browsers
I am not quite sure if I understand your question correctly. Do you mean you generate an image in PNG format but the browser does not offer download, instead shows the image directly?
If so, the solution is to indicate a file for download by setting the appriopriate MIME type as HTTP header "content type".
In PHP you do it like this:
header("Content-Type: application/force-download");
or
header("Content-Type: application/octet-stream");
When the browser receives this MIME type it will not try to display the content itself.
You can use a Data URI but there are some limitations. Here's an example, based on my answer to an earlier question. The first thing you'll note is that you can't really control the filename, but it works OK in Firefox and Chrome other than that, but probably not so well in IE (I've not tried it).
Assuming you can already generate the PGN as a string, the code to create a Data URI is quite straightforward:
function exportData(data, target) {
var exportLink = document.createElement('a');
exportLink.setAttribute('href', 'data:application/x-chess-pgn;base64,' + window.btoa(data));
exportLink.appendChild(document.createTextNode('sample.pgn'));
document.getElementById(target).appendChild(exportLink);
}
Just set data with whatever you're generating and set up an element to hold the link once it's created.
In the future we'll have better solutions for this sort of issue, but there's no browser support for it yet.