Pergunta

Em um site baseado em PHP, desejo enviar aos usuários um pacote de download depois que eles preencherem um pequeno formulário.O download iniciado pelo site deve ser semelhante a sites como download.com, que dizem “seu download começará em um momento”.

Alguns abordagens possíveis Eu conheço e compatibilidade do navegador (com base em um teste rápido):

1) Faça um window.open apontando para o novo arquivo.

- FireFox 3 blocks this.  
 - IE6 blocks this.  
 - IE7 blocks this.

2) Crie um iframe apontando para o novo arquivo.

- 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? 

Bônus:existe um método que não requer instruções condicionais do navegador?

(Acredito que download.com emprega ambos os métodos condicionalmente, mas não consigo fazer nenhum deles funcionar.)

Respostas e Esclarecimentos:

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?"

ATUALIZAR:Eu abandonei essa abordagem.Veja minha resposta abaixo por motivos.

Foi útil?

Solução

Você também pode fazer uma meta atualização, suportada pela maioria dos navegadores.Download.com coloca um em uma tag noscript.

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

Outras dicas

Atualizar:Decidi abandonar essa abordagem e, em vez disso, apenas apresentar ao usuário um link para o arquivo real.Meu raciocínio é este:

Minhas tentativas iniciais de download iniciado pelo servidor foram bloqueadas pelo navegador.Isso me fez pensar:"o navegador está certo.Como é que isto sabe que este é um download legítimo?Isto deve bloquear um download que não seja obviamente iniciado pelo usuário."

Qualquer método que eu possa usar para um download iniciado pelo servidor poderia também ser usado por alguém que deseja enviar malware.Portanto, os downloads só devem acontecer quando o usuário solicitar especificamente o arquivo clicando em um link referente a ele.

Você é livre para discordar e, se ainda quiser iniciar um download, esperamos que este tópico o ajude a fazer isso.

Normalmente, tenho apenas um script PHP que envia o arquivo diretamente para o navegador com o tipo de conteúdo apropriado

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.";
}

A única desvantagem é que, como isso define o cabeçalho HTTP, ele deve ser chamado antes de qualquer outra saída.

Mas você pode ter um link para a página de download do PHP e isso fará com que o navegador abra uma caixa de download sem atrapalhar o conteúdo da página atual.

Um problema é que você pode encontrar problemas com o IE (versão 6 em particular) se os cabeçalhos não estiverem configurados "corretamente".

Certifique-se de definir o tipo de conteúdo correto, mas considere também definir as opções de cache do IE (pelo menos) para permitir cache.Se o arquivo for um que o usuário possa abrir em vez de salvar (por exemplo,um documento do MS Word) as versões anteriores do IE precisam armazenar o arquivo em cache, pois entregam a solicitação de "abertura" ao aplicativo aplicável, apontando para o arquivo que foi baixado no cache.

Há também um problema relacionado: se o cache do usuário do IE6 estiver cheio, ele não salvará o arquivo corretamente (portanto, quando o aplicativo aplicável conseguir abri-lo, ele reclamará que o arquivo está corrompido.

Você também pode querer desativar qualquer ação gzip nos downloads (para IE)

IE6/IE7 têm problemas com downloads grandes (por exemplo,4.x Gigs...) não é um cenário provável, já que o IE nem tem um gerenciador de downloads, mas é algo que você deve estar ciente.

Finalmente, o IE6 às vezes não lida bem com um "push" de download se ele for iniciado a partir de um iframe aninhado.Não sei exatamente o que desencadeia o problema, mas acho que é mais fácil com o IE6 evitar esse cenário.

Olá!

@Nathan:Eu decidi fazer exatamente isso:Faça com que meu "getfile.php" carregue todas as coisas necessárias e depois faça um

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

para permitir que o próprio navegador faça diretamente o que achar correto com o arquivo.Isso funciona bem até no Opera comigo.

Mas isso será um problema em ambientes onde não é permitido acesso direto aos arquivos, nesse caso você terá que encontrar um caminho diferente!(Obrigado, Discordia, meus arquivos são PDFs públicos!)

Atenciosamente, Basty

Que tal alterar o local para apontar para o novo arquivo?(por exemplo.alterando window.location)

Sempre criei um iframe que aponta para o arquivo.

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

Quanto a não apontar a janela atual para o download.Na minha experiência, você ainda pode mostrar sua página "por favor, doe", já que os downloads (desde que enviem os cabeçalhos corretos) na verdade não atualizam a janela do navegador.Eu faço isso para exportações csv em um dos meus sites e, no que diz respeito ao usuário, apenas aparece uma janela de arquivo seguro.Então, eu recomendaria um meta-redirecionamento simples, como Soldarnal mostrou.

Apenas para resumir, você tem 2 objetivos:

  1. iniciar processo de download
  2. mostrar ao usuário uma página com opções de doação

Para conseguir isso eu faria o seguinte:

Quando o usuário envia o formulário, ele obtém a página resultante com opções de doação e um texto informando que o download começará em 5 segundos.E na seção principal desta página você coloca o código META como Soldarnal disse:<meta http-equiv="refresh" content="5;url=/download.php?doc=123.zip>

E isso é tudo.

<a href="normaldownload.zip" onclick="use_dhtml_or_ajax_to_display_page()">

A página atual não será afetada se o download for salvo.Apenas certifique-se de que o download não abra na mesma janela (tipo MIME adequado ou Content-Disposition) e você poderá mostrar qualquer coisa.

Veja resposta mais completa

Você pode usar Javascript/jQuery para iniciar o download.Aqui está um exemplo - você pode se livrar da solicitação Ajax e apenas usar o bloco 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...");
       }
    });
});
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top