105

I'm writing a web application that, among other things, allows users to upload files to my server. In order to prevent name clashes and to organize the files, I rename them once they are put on my server. By keeping track of the original file name I can communicate with the file's owner without them ever knowing I changed the file name on the back end. That is, until they go do download the file. In that case they're prompted to download a file with a unfamiliar name.

My question is, is there any way to specify the name of a file to be downloaded using just HTML? So a user uploads a file named 'abc.txt' and I rename it to 'xyz.txt', but when they download it I want the browser to save the file as 'abc.txt' by default. If this isn't possible with just HTML, is there any way to do it?

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
Sparafusile
  • 4,696
  • 7
  • 34
  • 57
  • `download` attributes it not works for blob url. refer to [How to set the download file extension for blob data](https://stackoverflow.com/q/71686536/6521116) – LF00 Apr 08 '22 at 03:18

6 Answers6

137

When they click a button to download the file, you can add the HTML5 attribute download where you can set the default filename.

That's what I did, when I created a xlsx file and the browser want to save it as zip file.

<a href="path/to/file" download="renamed.txt">Download</a>
<a href="downloads/export.xlsx" download="Data-Export.xlsx">Download Export</a>
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Mephiztopheles
  • 2,228
  • 1
  • 12
  • 25
  • 4
    sometimes download="myfilename" won't work if the filesize is not readable or the myfilename is omitted. – The Bumpaster Sep 20 '15 at 07:16
  • 2
    it depends on if the filesize is readable? i didn't know... but i think i remember i had problems with some files which didnt want to be renamed... maybe that could be the problem... well... in my case the files come from rackspace, so i can't access to the header :D – Mephiztopheles Sep 21 '15 at 09:46
  • There are several ways to avoid that, you can always download the file using curl or wget to a server, rename it using rename(thefileIdownloaded.file myfile.file) and then output the link, set the timer for 10minutes to delete that file and you always have a clean server and the file is on your server in that case you can do anything with it – The Bumpaster Sep 21 '15 at 13:29
  • 70
    "download" attribute is only honored for links to resources with the same-origin. – Gayan Dasanayake Sep 30 '17 at 11:52
  • `download` attributes it not works for blob url. refer to [How to set the download file extension for blob data](https://stackoverflow.com/q/71686536/6521116) – LF00 Apr 08 '22 at 03:18
102

Can't find a way in HTML. I think you'll need a server-side script which will output a content-disposition header. In php this is done like this:

header('Content-Disposition: attachment; filename="downloaded.pdf"');

if you wish to provide a default filename, but not automatic download, this seems to work.

header('Content-Disposition: inline; filename="filetodownload.jpg"');

In fact, it is the server that is directly serving your files, so you have no way to interact with it from HTML, as HTML is not involved at all.

Yoann Kergall
  • 2,993
  • 5
  • 22
  • 23
Palantir
  • 23,820
  • 10
  • 76
  • 86
7

just need to use HTML5 a tag download attribute

codepen live demo

https://codepen.io/xgqfrms/full/GyEGzG/

my screen shortcut.

enter image description here

enter image description here

update answer

  1. whether a file is downloadable depends on the server's response config, such as Content-Type, Content-Disposition;

  2. download file's extensions are optional, depending on the server's config, too.

'Content-Type': 'application/octet-stream',
// it means unknown binary file,
// browsers usually don't execute it, or even ask if it should be executed.

'Content-Disposition': `attachment; filename=server_filename.filetype`,
// if the header specifies a filename,
// it takes priority over a filename specified in the download attribute.

download blob url file

    function generatorBlobVideo(url, type, dom, link) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.responseType = 'arraybuffer';
      xhr.onload = function(res) {
        // console.log('res =', res);
        var blob = new Blob(
          [xhr.response],
          {'type' : type},
        );
        // create blob url
        var urlBlob = URL.createObjectURL(blob);
        dom.src = urlBlob;
        // download file using `a` tag
        link.href = urlBlob;
      };
      xhr.send();
    }

    (function() {
      var type = 'image/png';
      var url = 'https://cdn.xgqfrms.xyz/logo/icon.png';
      var dom = document.querySelector('#img');
      var link = document.querySelector('#img-link');
      generatorBlobVideo(url, type, dom, link);
    })();

https://cdn.xgqfrms.xyz/HTML5/Blob/index.html

refs

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition

https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#important_mime_types_for_web_developers

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
  • 2
    This doesn't work, at least on chrome. It just says "failed - no file" or "failed - server problem" when I tried it. – Brett Woodward Jan 05 '18 at 01:38
  • @BrettWoodward Can you show me what's your Chrome Version? It's OK for me. please, see the `gif` demo. – xgqfrms Jan 14 '18 at 13:35
  • @BrettWoodward this happens when href value points to page with error. Try removing "download" attribute to check if page works without downloading. – Māris Kiseļovs Mar 22 '19 at 13:10
  • `download` attributes it not works for blob url. refer to [How to set the download file extension for blob data](https://stackoverflow.com/q/71686536/6521116) – LF00 Apr 08 '22 at 03:19
  • It works for the `blob` url, please see the online live demo https://cdn.xgqfrms.xyz/HTML5/Blob/index.html – xgqfrms Apr 16 '22 at 16:44
3

Same code as @Hillkim Henry but with a.remove() improvement

This forces the document to remove the a tag from the body and avoid multiple elements

 const coverntFiletoBlobAndDownload = async (file, name) => {
  const blob = await fetch(file).then(r => r.blob())
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.style.display = 'none'
  a.href = url
  a.download = name // add custom extension here
  document.body.appendChild(a)
  a.click()
  window.URL.revokeObjectURL(url)
  // Remove "a" tag from the body
  a.remove()
}
bielb2
  • 31
  • 3
2

Sometimes @Mephiztopheles answer won't work on blob storages and some browsers.

For this you need to use a custom function to convert the file to blob and download it

const coverntFiletoBlobAndDownload = async (file, name) => {
  const blob = await fetch(file).then(r => r.blob())
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.style.display = 'none'
  a.href = url
  a.download = name // add custom extension here
  document.body.appendChild(a)
  a.click()
  window.URL.revokeObjectURL(url)
}
Hillkim Henry
  • 2,841
  • 13
  • 17
-1

Well, @Palantir's answer is, for me, the most correct way!

If you plan to use that with multiple files, then i suggest you to use (or make one) PHP Download Manager.

BUT, if you want to make that to one or two files, I will suggest you the mod_rewrite option:

You have to create or edit your .htaccess file on htdocs folder and add this:

RewriteEngine  on 
RewriteRule ^abc\.txt$  xyz.txt

With this code, users will download xyz.txt data with the name abc.txt

NOTE: Verify if you have already the "RewriteEngine on " on your file, if yes, add only the second for each file you wish to redirect.

Good Luck ;) (Sorry for my english)

Marcel Korpel
  • 21,536
  • 6
  • 60
  • 80
cusspvz
  • 5,143
  • 7
  • 30
  • 45