ファイルをダウンロードする
ブラウザでファイルをダウンロードする方法
a 要素の download 属性を使う。(HTML5から)
ブラウザ内部のデータをダウンロードさせる場合
Blob を作り、Object URL を作って、a 要素の URL として引き渡す。
ブラウザ内部のデータを Blob にする場合
canvas を Blob にする
自動ダウンロードさせる場合
a 要素を click する。
var aElm = document.createElement("a");
a.href = ... // URL
a.type = ... // MIME type
document.body.appendChild(aElm);
a.click();
DOM に追加していない要素では click が効かないことがある。(仕様では動作未定義)
https://stackoverflow.com/questions/55162944/document-createelementa-click-not-working-in-firefox
基本的には、単純にHTTP(S)なら URL からホストを特定して、GET メソッドでリクエストすれば、該当のデータをダウンロードできる。
HTTP で直接ダウンロードさせる場合
ヘッダで以下を出力してから、内容をそのまま(バイナリのまま)出力する。
code:http
Content-Type: application/octet-stream
Content-Length: バイト数
Content-Disposition: attachment; filename="ISO-8859-1ファイル名"; filename*=UTF-8''パーセントエンコーディングされたファイル名
Content-Type はデータ形式にあった MIME タイプを選択する。単純バイナリの場合は application/octet-stream でよい。
filename="ISO-8859-1ファイル名"は filename*= の指定が解釈されなかったときの代理。今はもうなくてもいい気がする。
RFC 6266 Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)
section-4.3 に詳細あり
パーセントエンコーディング
参考
ダウンロードファイル名、文字化けとの格闘 https://negiblog.hatenablog.com/entry/2015/06/19/%e3%83%80%e3%82%a6%e3%83%b3%e3%83%ad%e3%83%bc%e3%83%89%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e5%90%8d%e3%80%81%e6%96%87%e5
PHP ではファイル転送する場合は、readfile 関数を使うと、ファイルをそのまま転送できる。
サイズが不定の場合は Content-Length ヘッダがなくても構わないが、その場合 TCP 接続が切断されるまでがデータとして取り扱われるので注意。
読み込まれる度に処理をさせたい場合は
Transfer-Encoding: chunked
を付ける。ストリーム出力の場合は事実上必須。(一般的なファイルダウンロードとは趣旨が異なる)
「a要素をクリックしたらダウンロード」で良いのに、ダウンロード時に別のページに移動する実装がある。その理由は?
昔のブラウザでは、勝手な推論をして、間違った種別でダウンロードされてしまったので、それを避ける。
「ダウンロード」と「その場での表示」との混同を避ける。
ウィルス対策などでブロックされてしまうのを避ける。
独自のダウンローダーを用意している。
トラフィック量を制約するため、順番待ちを実装している。
「自動的にダウンロード処理が始まるページ」を別に用意している。ダウンロードボタンを押した時に遷移する。
#ファイル