Linking to a download in HTML - javascript

I have to create a online time-table for the school. The part what is troubling me at the moment is not to be able to download a file by clicking on the filename.
I try to download a file by clicking on a button or a link with html/php maybe javascript but for javascript I should somehow combine php and javascript because javascript has no readfile-function.
Some of my attempts:
Download
This just shows the content of the file in the web browser but I am not able to download it. The content of my testmove.txt is testmove123, so I just see the text testmove123 in my browser.
Another example:
Javascript:
function download(file)
{
window.location=file;
}
+html:
<input type="button" value="Download" onClick="download('dateiupload/testmove.txt')" >
Makes the same.
Another example:
Javascript:
function download(path)
{
var ifrm = document.getElementById("frame");
ifrm.src = path;
}
+html:
<iframe id="frame" style="display:none"></iframe>
download
By clicking on "Download" the javascript function starts but nothing else happens and I see the same site.
Another example (with php):
Javascript:
function download(path)
{
var ifrm = document.getElementById(frame);
ifrm.src = "download.php?path="+path;
}
+html (same as above):
<iframe id="frame" style="display:none"></iframe>
download
+php (the reason my its more or less working):
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
This solution doesn't wait for a click from me and starts the download by starting the site.
A working solution I thought about would be to link to another site where the download automatically starts but its absolutely not how it have to be. I use $_POST variables on the site and I lose them when I leave the site and I can't come back after the download.
It must start the download by clicking on the filename.

You can download straight from the anchor tag by using the 'download' attribute.
<a href="dateiupload/testmove.txt" download>Download</a>
The filename of the downloaded file will be testmove.txt by default.
You can change the filename like this.
Download
More Details at w3Schools

You were correct to use those headers - as you can see, the file is being downloaded. The only problem now is to have it download when you want it to.
For a very simple solution, I would suggest setting up a download.php file that will be the page you download all files from. You would setup a GET parameter for this file and the URL would look something like this:
http://your-cool-site.com/download.php?filename=textmove.txt
Now inside download.php, you'll read that GET parameter which will be a filename, and then pass it eventually to the readfile function. This is the stage that you should think about enforcing some level of security as passing a path directly to the function could give people access to files that they shouldn't be looking at! Think about limiting the actual downloadable files to a limited selection of files or paths you know to be "safe" for people to download.
You'll also need to use the file name in the headers (and possibly even the size of the file to support displaying progress of the download).
Once you have this download.php file ready, you can place links to it from other pages in a very similar way that you have now:
Download File
Clicking on this link will make the request to download.php and when it gets the appropriate headers, the download will start.

Related

How can I add a mechanism on a web page to download an html file to their mobile device? (The link opens page rather than downloading the html file)

I have an html file that I would like to make available for offline use. This can be achieved easily by simply right clicking on the link on a desktop browser, then choosing "save as".
However, on a mobile device, I have tried using the download attribute on the anchor tag like so:
<a href="index.html" download>Download the page here.</a>
This seems to just take me to the page instead of downloading it.
My main goal is just to allow the user to download an html file to their mobile device.
There really isn't a right-click on mobile and holding down on the link shows a menu, but download isn't among them. The mobile browser itself may have a mechanism for saving a page once opened, but this would be sort of hard to walk the user through, and of course I'll have no idea what the mobile browser the user is using.
A special note here, the webpage I am trying to download does not have assets like images or style script files that need loaded in, all the assets are self-contained in the html file itself.
I actually came up with a solution to the problem, so I'll share it here, but I'm finding it hard to believe that there is not an easier way to do this.
My solution was essentially this, make an asynchronous request for the html file and read its text as a string. Then use that string to make a text blob and download it. Furthermore, to make sure the asset could be obtained from a local machine I served the data with a php file containing a header to ignore the cross origin restriction. (I didn't use fetch because I wanted to use settimeout).
To request an index.html file from the location https://www.mypage.com/:
Here is the downloader.php file located in the base directory:
header('Access-Control-Allow-Origin: *');
?>
<?php include_once 'index.html';?>
The html file the user clicks:
<!DOCTYPE html>
<html>
<body>
<button onclick="downloadPageAsText('https://www.mypage.com/downloader.php', 'index', '.html');">Download</button>
</body>
</html>
The functions to allow downloading:
function downloadPageAsText(url, basename, suffix){
let xhttp = new XMLHttpRequest();
xhttp.timeout = 1000;
xhttp.ontimeout = function(e) {
alert("Request timed out. Try again later");
};
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
saveStringToTextFile(xhttp.responseText, basename, suffix);
}
};
xhttp.open("GET", url, true);
xhttp.send();
}
function saveStringToTextFile(str1, basename = "myfile", fileType = ".txt") {
let filename = basename + fileType;
let blobVersionOfText = new Blob([str1], {
type: "text/plain"
});
let urlToBlob = window.URL.createObjectURL(blobVersionOfText);
let downloadLink = document.createElement("a");
downloadLink.style.display = "none";
downloadLink.download = filename;
downloadLink.href = urlToBlob;
document.body.appendChild(downloadLink);
downloadLink.click();
downloadLink.parentElement.removeChild(downloadLink);
}
Is there an easier way to allow the user to download an html file to their mobile device?
After help in the comments I found that adding the Content-Disposition header in the PHP file prompts the mobile browsers to use their download mechanisms.
It looks like there are 2 relatively simple ways to cause the html file to download.
You can use the anchor tag's download attribute which is supposed to prompt the browser to download the file instead of displaying it. Here is an example of its use:
Click to download
However, this only works for same-origin URLs, so although it may fit your use-case but not mine as I need the file to download from cross-origin URLS.
A second simpler way of making the html file download rather than display (using PHP), is to use the Content-Dispostion header which tells the users browser it should be downloading the file.
Here is an example of a PHP file called download.php, which will cause desiredpage.html to download with a suggested name of suggestname.html, using just an anchor tag from the client side.
<?php
$contents=file_get_contents("desiredpage.html");
$filename="suggestedname.html";
header('Access-Control-Allow-Origin: *');
header("Content-disposition:attachment;filename=".$filename);
echo $contents;
?>
And here is the anchor tag on the client-side:
Click here to download
Reference:
Download Link not working in html
With useful comments from:
Anirban and Christopher.

How to prevent PDF files from automatically downloading

i want to display pdf files in my website but unfortunately it will automatically download by idm.
here's my code:
$
<div class="viewerthesispdf">
<div id="viewer" class="pdf-viewer" data-url="<?php the_field('upload_pdfACField'); ?>"></div>
data-url is used to embed a file in a web page. That makes sense for images. It doesn't make sense for a PDF (or Excel or Word or most other file types) because normally these types of files are in place of a page, not a section of a web page. There are generally two solutions, depending on whether the files need to be restricted:
Use an href tag to reference the file. Download File1 I usually include target="_blank" in order to force a new page so that if there is a problem with the download you don't "lose" the original page, but it isn't strictly necessary. This will simply give a link to the file - and you can use a button, Font Awesome, images, etc. to make it fancier - but in the end "a link to a file".
Create a form which returns only the PDF as a result. Again I usually include target="_blank". The advantage of a form is that (a) the file doesn't have to actually exist on disk - it can be created by a script on-the-fly (technically this can be done with a link too - but typically a link would be a file rather than a script) and (b) you can include any necessary parameters for security, user-specific customization, etc. as part of the form. The form can use a GET or a POST depending on your preference.
Use href to show your pdf file list like this Filename , it will not start downloading automatically, only when user click on it, it will start download.

URL of file-download link

I am downloading a file from a location. I would like to get the download link of the file that's being downloaded. I want to save the link in a text file and then later use that link from other places to directly download the object. I am currently working on Firefox, but a generalized approach would be appreciated. Is there a way to do this? I tried JSOUP and I didn't succeed since it was generic to all the external links.
Often times downloaded files do not have source links. For example, say you click a "download" button on a website - it could easily send POST data to a form on a 'download.php' page something like this:
<?php
header("Content-Type: application/force-download");
header('Content-Description: File Transfer');
readfile($_POST['file']);
?>

How does a javascript download link work?

I've been using the Microsoft Technet site and you can download the ISO files by clicking a link on the page. The element is like this:
<a href="javascript:void(0)" onmouseout="HideToolTip()"
onmouseover="ShowToolTip(event,'Click here to download.')"
onclick="javascript:RunDownload('39010^313^164',event)"
class="detailsLink">Download</a>
I wasn't able to find the RunDownload() method in the scripts. And I wondered what it is likely to do. I mean usually when I provide a link for someone to download I provide an anchor to it:
download
But this is working differently what is the script doing? Because even when I ran 'Fiddler' I wasn't able to see the actual download location.
there's no such thing as a "javascript download" link. Javascript can open a new window, or simulate a click on a link.
What you have to find is which url the function triggered by this click will lead to.
here's an example of how to do it:
Suppose we have a:
<a id="download">download Here ยงยงยง</a>
then this jQuery code:
$('#download').click( function() {
window.location.href = 'http://example.org/download/ISO.ISO';
} );
will redirect to the URL http://example.org/download/ISO.ISO. Whether this url starts a download or not depends on HTTP headers and your browser, not on what javascript do.
Download location can be a url-rewritten path. This mean that maybe some parameters are given with HTTP Post and some HTTP handler in the Web server or web application may be getting some arguments from the HTTP request and write file bytes to an HTTP response, which absolutely hides where the file is located in the actual server's file system.
Maybe this is what's behind the scenes and prevents you to know the file location.
For example, we can have this:
http://mypage.com/downloads/1223893893
And you requested an executable like "whatever.exe" for downloading it to your hard disk. Where's the "http:/mypage.com/downloads/whatever.exe"? Actually, it doesn't exist. It's a byte array saved in a long database in some record, and "mypage" web application handles a request for a file that's identified as "1223893893" which can be a combination of an identifier, date time or whichever argument.
What I think the function RunDownload might do is that it might inform the server using get request to the server that another download is about to happen , or it might need to run the download background by setting the target attribute to an iframe so the user won't need to open another tab and download the file on the same page.
Download
JS
var runDownload=function(){
e.preventDefault();
increaseDownloadCountOnTheServer(location);
window.location.href="filelocation.exe";
}

starting file download with JavaScript

Let's say I have download links for files on my site.
When clicked these links send an AJAX request to the server which returns the URL with the location of the file.
What I want to do is direct the browser to download the file when the response gets back. Is there a portable way to do this?
We do it that way:
First add this script.
<script type="text/javascript">
function populateIframe(id,path)
{
var ifrm = document.getElementById(id);
ifrm.src = "download.php?path="+path;
}
</script>
Place this where you want the download button(here we use just a link):
<iframe id="frame1" style="display:none"></iframe>
download
The file 'download.php' (needs to be put on your server) simply contains:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
So when you click the link, the hidden iframe then gets/opens the sourcefile 'download.php'. With the path as get parameter.
We think this is the best solution!
It should be noted that the PHP part of this solution is a simple demonstration and potentially very, very insecure. It allows the user to download any file, not just a pre-defined set. That means they could download parts of the source code of the site itself, possibly containing API credentials etc.
I have created an open source jQuery File Download plugin (Demo with examples) (GitHub) which could also help with your situation. It works pretty similarly with an iframe but has some cool features that I have found quite handy:
User never leaves the same page they initiated a file download from. This feature is becoming crucial for modern web applications
Tested cross browser support (including mobile!)
It supports POST and GET requests in a manner similar to jQuery's AJAX API
successCallback and failCallback functions allow for you to be explicit about what the user sees in either situation
In conjunction with jQuery UI a developer can easily show a modal telling the user that a file download is occurring, disband the modal after the download starts or even inform the user in a friendly manner that an error has occurred. See the Demo for an example of this.
Just call window.location.href = new_url from your javascript and it will redirect the browser to that URL as it the user had typed that into the address bar
Reading the answers - including the accepted one I'd like to point out the security implications of passing a path directly to readfile via GET.
It may seem obvious to some but some may simply copy/paste this code:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
So what happens if I pass something like '/path/to/fileWithSecrets' to this script?
The given script will happily send any file the webserver-user has access to.
Please refer to this discussion for information how to prevent this: How do I make sure a file path is within a given subdirectory?
If this is your own server application then i suggest using the following header
Content-disposition: attachment; filename=fname.ext
This will force any browser to download the file and not render it in the browser window.
Try this lib https://github.com/PixelsCommander/Download-File-JS it`s more modern than all solutions described before because uses "download" attribute and combination of methods to bring best possible experience.
Explained here - http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/
Seems to be ideal piece of code for starting downloading in JavaScript.
A agree with the methods mentioned by maxnk, however you may want to reconsider trying to automatically force the browser to download the URL. It may work fine for binary files but for other types of files (text, PDF, images, video), the browser may want to render it in the window (or IFRAME) rather than saving to disk.
If you really do need to make an Ajax call to get the final download links, what about using DHTML to dynamically write out the download link (from the ajax response) into the page? That way the user could either click on it to download (if binary) or view in their browser - or select "Save As" on the link to save to disk. It's an extra click, but the user has more control.
To get around the security flaw in the top-voted answer, you can set the iframe src directly to the file you want (instead of an intermediate php file) and set the header information in an .htaccess file:
<Files *.apk>
ForceType application/force-download
Header set Content-Disposition attachment
Header set Content-Type application/vnd.android.package-archive
Header set Content-Transfer-Encoding binary
</Files>
I suggest to make an invisible iframe on the page and set it's src to url that you've received from the server - download will start without page reloading.
Or you can just set the current document.location.href to received url address. But that's can cause for user to see an error if the requested document actually does not exists.
In relation to the top answer I have a possible solution to the security risk.
<?php
if(isset($_GET['path'])){
if(in_array($_GET['path'], glob("*/*.*"))){
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
}
}
?>
Using the glob() function (I tested the download file in a path one folder up from the file to be downloaded) I was able to make a quick array of files that are "allowed" to be downloaded and checked the passed path against it. Not only does this insure that the file being grabbed isn't something sensitive but also checks on the files existence at the same time.
~Note: Javascript / HTML~
HTML:
<iframe id="download" style="display:none"></iframe>
and
<input type="submit" value="Download" onclick="ChangeSource('document_path');return false;">
JavaScript:
<script type="text/javascript">
<!--
function ChangeSource(path){
document.getElementByID('download').src = 'path_to_php?path=' + document_path;
}
-->
</script>
I'd suggest window.open() to open a popup window. If it's a download, there will be no window and you will get your file. If there is a 404 or something, the user will see it in a new window (hence, their work will not be bothered, but they will still get an error message).
Why are you making server side stuff when all you need is to redirect browser to different window.location.href?
Here is code that parses ?file= QueryString (taken from this question) and redirects user to that address in 1 second (works for me even on Android browsers):
<script type="text/javascript">
var urlParams;
(window.onpopstate = function () {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = window.location.search.substring(1);
urlParams = {};
while (match = search.exec(query))
urlParams[decode(match[1])] = decode(match[2]);
})();
(window.onload = function() {
var path = urlParams["file"];
setTimeout(function() { document.location.href = path; }, 1000);
});
</script>
If you have jQuery in your project definitely remove those window.onpopstate & window.onload handlers and do everything in $(document).ready(function () { } );

Categories