サイトにファイルのダウンロードリンクがあるとしましょう。
これらのリンクをクリックすると、AJAXリクエストをサーバーに送信し、サーバーはURLをファイルの場所とともに返します。
私がやりたいのは、応答が戻ったときにファイルをダウンロードするようにブラウザに指示することです。これを行うポータブルな方法はありますか?
このライブラリを試してください https://github.com/PixelsCommander/Download-File-JS これは、「ダウンロード可能な限り最高のエクスペリエンスをもたらすためのメソッドの属性と組み合わせ。
ここで説明- http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/
JavaScriptでダウンロードを開始するための理想的なコードのようです。
そのようにします。最初にこのスクリプトを追加します。
<script type="text/javascript">
function populateIframe(id,path)
{
var ifrm = document.getElementById(id);
ifrm.src = "download.php?path="+path;
}
</script>
これをダウンロードボタンが必要な場所に配置します(ここではリンクのみを使用します)。
<iframe id="frame1" style="display:none"></iframe>
<a href="javascript:populateIframe('frame1','<?php echo $path; ?>')">download</a>
ファイル「download.php」(サーバーに配置する必要があります)には、次のものが含まれています。
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
したがって、リンクをクリックすると、非表示のiframeがソースファイル「download.php」を取得/開きます。パスを取得パラメーターとして使用します。これが最良の解決策だと思います!
このソリューションのPHPの部分は単純なデモンストレーションであり、非常に安全ではない可能性があります。事前定義されたセットだけでなく、任意のファイルをダウンロードできます。 API資格情報などを含む可能性のあるサイト自体のソースコードの一部をダウンロードできます。
オープンソースを作成しました jQuery File Downloadプラグイン (- 例のデモ )( GitHub ) iframeでも同様に機能しますが、便利な機能がいくつかあります。
回答を読む-受け入れられたものも含めて、GETを介してreadfileに直接パスを渡すことのセキュリティへの影響を指摘したいと思います。
一部の人には自明のように見えるかもしれませんが、このコードを単にコピー/貼り付けするだけの人もいます。
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
このスクリプトに「/ path/to/fileWithSecrets」のようなものを渡すとどうなりますか?指定されたスクリプトは、webserverユーザーがアクセスできるファイルを喜んで送信します。
これを防ぐ方法については、この説明を参照してください。 ファイルパスが特定のサブディレクトリ内にあることを確認するにはどうすればよいですか?
これが独自のサーバーアプリケーションの場合、次のヘッダーを使用することをお勧めします
Content-disposition: attachment; filename=fname.ext
これにより、ブラウザはファイルをダウンロードし、ブラウザウィンドウにレンダリングしません。
JavaScriptからwindow.location.href = new_url
を呼び出すだけで、ユーザーがアドレスバーに入力したとおりにブラウザーがそのURLにリダイレクトされます。
Maxnkが言及している方法には同意しますが、ブラウザーにURLのダウンロードを自動的に強制することを再検討することができます。バイナリファイルでは正常に機能する場合がありますが、他の種類のファイル(テキスト、PDF、画像、ビデオ)の場合、ブラウザはディスクに保存するのではなくウィンドウ(またはIFRAME)でレンダリングする場合があります。
最終的なダウンロードリンクを取得するために本当にAjax呼び出しを行う必要がある場合、DHTMLを使用して(ajax応答から)ダウンロードリンクをページに動的に書き出すのはどうでしょうか。これにより、ユーザーはそれをクリックしてダウンロード(バイナリの場合)するか、ブラウザで表示するか、リンクの[名前を付けて保存]を選択してディスクに保存できます。それは余分なクリックですが、ユーザーはより多くのコントロールを持っています。
トップ投票の回答のセキュリティ上の欠陥を回避するには、iframe srcを(中間のphpファイルの代わりに)目的のファイルに直接設定し、ヘッダー情報を.htaccessファイルに設定します。
<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>
一番上の答えに関連して、セキュリティリスクの可能な解決策があります。
<?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']);
}
}
?>
Glob()関数を使用して(ダウンロードするファイルから1つ上のフォルダーのパスでダウンロードファイルをテストしました)ダウンロードが許可されているファイルのクイック配列を作成し、それに対して渡されたパスを確認できました。これにより、グラブされるファイルが機密性の高いものではないことが保証されるだけでなく、同時にファイルの存在もチェックされます。
〜注:Javascript/HTML〜
HTML:
<iframe id="download" style="display:none"></iframe>
そして
<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>
ページに非表示のiframeを作成し、サーバーから受け取ったURLにsrcを設定することをお勧めします-ダウンロードはページの再読み込みなしで開始されます。
または、現在のdocument.location.hrefを受信したURLアドレスに設定することもできます。ただし、要求されたドキュメントが実際に存在しない場合、ユーザーにエラーが表示される可能性があります。
ブラウザーを別のwindow.location.hrefにリダイレクトするだけでよいのに、なぜサーバー側のものを作成するのですか?
これは?file = QueryString( この質問から取得 )を解析し、1秒でそのアドレスにユーザーをリダイレクトするコードです(Androidブラウザーでも動作します):
<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>
プロジェクトにjQueryがある場合は、これらのwindow.onpopstateおよびwindow.onloadハンドラーを確実に削除し、$(document).ready(function(){});
ポップアップウィンドウを開くには、window.open()
をお勧めします。ダウンロードの場合、ウィンドウは表示されず、ファイルが取得されます。 404または何かがある場合、ユーザーは新しいウィンドウにそれを表示します(したがって、作業は煩わされませんが、エラーメッセージが表示されます)。