質問
PHP ベースの Web サイトで、ユーザーが短いフォームに記入した後、ダウンロード パッケージを送信したいと考えています。サイトによって開始されるダウンロードは、「ダウンロードはすぐに開始されます」と表示される download.com のようなサイトと同様である必要があります。
数個の 考えられるアプローチ ブラウザの互換性については次のとおりです (簡単なテストに基づいて)。
1) を実行します window.open
新しいファイルを指します。
- FireFox 3 blocks this.
- IE6 blocks this.
- IE7 blocks this.
2) 新しいファイルを指す iframe を作成します。
- FireFox 3 seems to think this is OK. (Maybe it's because I already accepted it once?)
- IE6 blocks this.
- IE7 blocks this.
How can I do this so that at least these three browsers will not object?
ボーナス:ブラウザの条件文を必要としない方法はありますか?
(download.com は両方の方法を条件付きで採用していると思いますが、どちらも機能させることができません。)
回答と説明:
Q: "Why not point the current window to the file?"
A: That might work, but in this particular case, I want to show them some other content while their download starts - for example, "would you like to donate to this project?"
アップデート:私はこのアプローチを放棄しました。理由については、以下の私の回答を参照してください。
解決
ほとんどのブラウザーがサポートしているメタ更新を実行することもできます。Download.com では、noscript タグ内に 1 つを配置します。
<meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip"/>
他のヒント
アップデート:私はこのアプローチを放棄し、代わりに実際のファイルへのリンクをユーザーに提示することにしました。私の推論は次のとおりです。
サーバーで開始されたダウンロードの最初の試行はブラウザによってブロックされました。そこで私は次のように考えました。「ブラウザは正しいです。どうやって それ これが正規のダウンロードであることを知っていますか?それ すべき 明らかにユーザーが開始したものではないダウンロードをブロックします。」
サーバーで開始されるダウンロードに使用できる方法はどれでも可能です。 また マルウェアを送信したい人によって使用される可能性があります。したがって、ダウンロードは、ユーザーがリンクをクリックしてファイルを具体的に要求した場合にのみ行われます。
同意しないのは自由ですが、それでもダウンロードを開始したい場合は、このスレッドがその助けになることを願っています。
通常は、適切な Content-Type でファイルをブラウザに直接出力する PHP スクリプトを使用します。
if(file_exists($filename)) {
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: " . $content-type);
header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($filename));
readfile("$filename");
}else{
print "ERROR: the file " . basename($filename) . " could not be downloaded because it did not exist.";
}
唯一の欠点は、これにより HTTP ヘッダーが設定されるため、他の出力が得られる前に呼び出されることです。
ただし、PHP ダウンロード ページへのリンクを設定すると、現在のページのコンテンツを損なうことなく、ブラウザーにダウンロード ボックスがポップアップ表示されます。
問題点の 1 つは、ヘッダーが「正しく」設定されていない場合、IE (特にバージョン 6) で問題が発生する可能性があることです。
正しい Content-Type を設定していることを確認しますが、IE のキャッシュ オプションを (少なくとも) 次のように設定することも検討してください。 許可する キャッシング。ファイルが、ユーザーが保存するのではなく開くことができるファイルである場合 (例:MS Word ドキュメントなど)IE の初期バージョンでは、キャッシュにダウンロードされたファイルを指す「開く」リクエストを該当するアプリに渡すため、ファイルをキャッシュする必要があります。
関連する問題もあります。IE6 ユーザーのキャッシュがいっぱいの場合、ファイルが適切に保存されません (そのため、該当するアプリがファイルを開こうとすると、ファイルが壊れているというメッセージが表示されます)。
ダウンロード時の gzip アクションも無効にすることもできます (IE の場合)。
IE6/IE7 は両方とも、大量のダウンロードに関する問題を抱えています (例:4.x ギガ...) IE にはダウンロード マネージャーさえないため、ありそうなシナリオではありませんが、注意が必要です。
最後に、IE6 は、ネストされた iframe 内からダウンロードが開始された場合、ダウンロードの「プッシュ」をうまく処理できないことがあります。何が問題を引き起こすのか正確にはわかりませんが、IE6 を使用すると、このシナリオを回避するのが簡単であることがわかりました。
ほーい!
@ネイサン:私はまさにそれを行うことにしました:「getfile.php」に必要なものをすべてロードしてから、
header("Location: ./$path/$filename");
ブラウザ自体に、ファイルに対して正しいと思われることを何でも直接実行させます。これは Opera でも問題なく動作します。
ただし、ファイルへの直接アクセスが許可されていない環境ではこれが問題になります。その場合は、別の方法を見つける必要があります。(私のファイルは公開 PDF なので Discordia に感謝します!)
よろしく、バスティ
新しいファイルを指すように場所を変更してみてはいかがでしょうか?(例えば。window.location を変更することにより)
私はいつもファイルを指す iframe を作成してきました。
<iframe src="/download.exe" frameborder="0" height="0" width="0"><a href="/download.exe">Click here to download.</a></iframe>
現在のウィンドウをダウンロードに向けていないことについて。私の経験では、ダウンロードしても (正しいヘッダーが送信されている限り) ブラウザ ウィンドウは実際には更新されないため、「寄付してください」ページを表示することはできます。私は自分のサイトの 1 つで CSV エクスポートのためにこれを行っていますが、ユーザーに関する限り、安全なファイル ウィンドウがポップアップするだけです。したがって、Soldarnal が示したように、単純なメタリダイレクトをお勧めします。
要約すると、目標は 2 つあります。
- ダウンロードプロセスを開始します
- 寄付オプションのあるページをユーザーに表示する
これを達成するには、次のようにします。
ユーザーがフォームを送信すると、寄付オプションと、ダウンロードが 5 秒後に開始されるというテキストを含むページが表示されます。そして、このページの先頭セクションに、Soldarnal が言ったように META コードを配置します。<meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip>
以上です。
<a href="normaldownload.zip" onclick="use_dhtml_or_ajax_to_display_page()">
ダウンロードが保存された場合、現在のページは影響を受けません。ダウンロードが同じウィンドウで開かれないことを確認してください (適切な MIME タイプまたは Content-Disposition
)そして何でも表示できるようになります。
Javascript/jQuery を使用してダウンロードを開始できます。以下に例を示します。Ajax リクエストを削除して、setTimeout() ブロックだけを使用できます。
$("btnDownloadCSV").on('click', function() {
$.ajax({
url: "php_backend/get_download_url",
type: 'post',
contentType: "application/x-www-form-urlencoded",
data: {somedata: "somedata"},
success: function(data) {
// If iFrame already exists, remove it.
if($("[id^='iframeTempCSV_"]).length) {
$("[id^='iframeTempCSV_"]).remove();
}
setTimeout(function() {
// If I'm creating an iframe with the same id, it will permit download only the first time.
// So randHashId appended to ID to trick the browser.
var randHashId = Math.random().toString(36).substr(2);
// Create a fresh iFrame for auto-downloading CSV
$('<iframe id="iframeTempCSV_'+randHashId+'" style="display:none;" src="'+data.filepath+'"></iframe>').appendTo('body');
}, 1000);
},
error: function(xhr, textStatus, errorThrown) {
console.error("Error downloading...");
}
});
});