Лучший способ начать загрузку?

На веб-сайте на основе PHP я хочу отправить пользователям пакет загрузки после того, как они заполнили короткую форму. Загрузка, инициированная сайтом, должна быть похожа на сайты, такие как 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.

 <meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip"/> 

Обновление: я решил отказаться от этого подхода и вместо этого просто представить пользователю ссылку на фактический файл. Мое рассуждение таково:

Мои первоначальные попытки загрузки с сервера были заблокированы браузером. Это заставило меня задуматься: «браузер прав. Как он узнает, что это законная загрузка? Он должен блокировать загрузку, которая явно не инициирована пользователем».

Любой метод, который я могу использовать для загрузки с сервера, также может использовать тот, кто хочет отправить вредоносное ПО. Поэтому загрузка должна происходить только тогда, когда пользователь запрашивает файл, кликнув по нему ссылку.

Вы можете не согласиться, и если вы все еще хотите начать загрузку, надеюсь, этот поток поможет вам это сделать.

Обычно у меня есть 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, и это приведет к тому, что браузер откроет окно загрузки, не испортив содержимое текущей страницы.

Один улов заключается в том, что вы можете столкнуться с проблемами с IE (в частности, версия 6), если заголовки не настроены «правильно».

Убедитесь, что вы установили правильный Content-Type, но также рассмотрите возможность установки параметров кэша для IE (по крайней мере), чтобы разрешить кеширование. Если файл один, который пользователь может открыть, а не сохранять (например, документ MS Word), ранние версии IE должны кэшировать файл, поскольку они передают «открытый» запрос в соответствующее приложение, указывая на загруженный файл в кеше.

Также существует связанная с этим проблема, если кеш пользователя IE6 заполнен, он не сохранит файл должным образом (при этом, когда соответствующее приложение получит руку, чтобы открыть ее, оно будет жаловаться, что файл поврежден.

Вы также можете включить любые действия gzip в загрузках (для IE)

У IE6 / IE7 есть проблемы с большими загрузками (например, 4.x Gigs …), не вероятный сценарий, поскольку IE даже не имеет диспетчера загрузки, а что-то, о чем нужно знать.

Наконец, IE6 иногда не красиво обрабатывает загрузку «push», если она была инициирована из встроенного iframe. Я не совсем уверен, что вызывает проблему, но я считаю, что IE6 легче избегать этого сценария.

Ха!

@Nathan: Я решил сделать именно это: пусть мой «getfile.php» загрузит все необходимые вещи, а затем сделает

 header("Location: ./$path/$filename"); 

чтобы позволить самому браузеру и непосредственно делать то, что, по его мнению, является правильным, делать с файлом. Это даже отлично работает в Opera со мной.

Но это будет проблемой в средах, где прямой доступ к файлам невозможен, в этом случае вам придется искать другой способ! (Спасибо Discordia, мои файлы являются общедоступными PDF-файлами!)

С наилучшими пожеланиями, Basty

Как изменить местоположение, чтобы указать на новый файл? (например, путем изменения window.location)

Я всегда делал iframe, указывающий на файл.

 <iframe src="/download.exe" frameborder="0" height="0" width="0"><a href="/download.exe">Click here to download.</a></iframe> 

Относительно не указывая текущее окно на загрузку. По моему опыту вы все равно можете показать свою страницу «пожалуйста, пожертвуйте», так как загрузки (пока они отправляют правильные заголовки) фактически не обновляют окно браузера. Я делаю это для экспорта csv на одном из моих сайтов, и, насколько это касается пользователя, он просто открывает окно безопасного файла. Поэтому я бы порекомендовал простой мета-редирект, как показал Солдарнал.

Чтобы подвести итог, у вас есть 2 цели:

  1. начать процесс загрузки
  2. показать пользователю страницу с вариантами пожертвования

Для этого я бы сделал следующее:

Когда ваш пользователь отправляет форму, он получает результирующую страницу с вариантами пожертвования и текст, говорящий, что его загрузка начнется через 5 секунд. И в главном разделе этой страницы вы помещаете META-код, как сказал Soldarnal: <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..."); } }); });