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


На веб-сайте на основе 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?"

ОБНОВЛЕНИЕ: Я отказался от этого подхода. Причины смотрите в моем ответе ниже.

Author: Alive to Die, 2008-09-13

11 answers

Вы также можете выполнить мета-обновление, которое поддерживает большинство браузеров. Download.com помещает один в тег noscript.

<meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip"/>
 16
Author: Soldarnal, 2008-09-13 15:18:14

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

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

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

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

 15
Author: Nathan Long, 2008-09-16 14:52:18

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

 5
Author: Mark Biek, 2017-01-09 12:47:01

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

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

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

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

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

Наконец, IE6 иногда не очень хорошо обрабатывает "толчок" загрузки, если он был инициирован из вложенного iframe. Я не совсем уверен, что вызывает проблему, но я считаю, что с IE6 проще избежать этого сценария.

 1
Author: scunliffe, 2008-09-15 13:32:27

Хой!

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

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

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

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

Лучший с уважением, Басти

 1
Author: bastiandoeen, 2008-09-22 13:03:01

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

 0
Author: aib, 2008-09-13 15:06:41

Я всегда просто создавал iframe, который указывает на файл.

<iframe src="/download.exe" frameborder="0" height="0" width="0"><a href="/download.exe">Click here to download.</a></iframe>
 0
Author: Dan Walker, 2008-09-13 15:37:52

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

 0
Author: Effata, 2008-09-15 11:56:47

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

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

Для достижения этой цели я бы сделал следующее:

Когда ваш пользователь отправляет форму, он получает результирующую страницу с вариантами пожертвования и текстом, в котором говорится, что его загрузка начнется через 5 секунд. И в разделе "Заголовок" этой страницы вы помещаете МЕТА-код, как сказал Солдарнал:

И это все.

 0
Author: Vitaly Sharovatov, 2008-09-15 12:49:01
<a href="normaldownload.zip" onclick="use_dhtml_or_ajax_to_display_page()">

Текущая страница не изменяется, если загрузка сохранена. Просто убедитесь, что загрузка не открывается в том же окне (правильный тип MIME или Content-Disposition), и вы сможете показать что угодно.

Смотрите более полный ответ

 0
Author: Kornel, 2017-05-23 11:46:25

Вы можете использовать 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...");
       }
    });
});
 0
Author: sagunms, 2015-04-17 07:01:30