Forçar a abrir o pop-up "Salvar como ..." aberto no link de texto, clique em PDF em HTML

173

Tenho alguns catálogos PDF de tamanho grande no meu site e preciso vinculá-los como download. Quando pesquisei no Google, encontrei uma coisa mencionada abaixo. Ele deve abrir o pop-up " Salvar como ... " no link, clique em ...

 <head>
    <meta name="content-disposition" content="inline; filename=filename.pdf">
    ...

Mas não funciona: / Quando vinculo a um arquivo como abaixo, ele apenas vincula a um arquivo e está tentando abrir o arquivo.

    <a href="filename.pdf" title="Filie Name">File name</a>

ATUALIZAÇÃO (de acordo com as respostas abaixo):

Pelo que vejo, não existe uma solução 100% confiável entre navegadores para isso. Provavelmente, a melhor maneira é usar um dos serviços da web listados abaixo e fornecer um link para download ...

designer-tentando-codificação
fonte
1
não sirva o tipo MIME para arquivos PDF.
bhups
Eu tentei sua solução atualizada, artmania - mas ocorreu o mesmo problema que estou tendo no Safari. Recebo o que parece o PDF na janela do navegador e somente quando clico nas guias "Visualizar" ou "Fazer o download" na parte inferior é que recebo o recurso de pesquisa de que tanto preciso.
precisa saber é o seguinte
sem o clique: stackoverflow.com/questions/2598658/…
Ciro Santilli (
semelhante, mas menos tipo de arquivo específico: stackoverflow.com/questions/1465573/...
Ciro Santilli郝海东冠状病六四事件法轮功

Respostas:

267

De uma resposta para Forçar um navegador a salvar o arquivo como após clicar no link :

<a href="path/to/file" download>Click here to download</a>
Ayush Gupta
fonte
17
No momento deste comentário, o downloadatributo está limitado ao Chrome, Firefox e Opera. Mesmo versões recentes do IE e Safari não são compatíveis. Para suporte futuro: consulte caniuse.com/#feat=download !
Sygmoral 5/09/14
A verificação de erros do Netbeans se queixa, mas parece funcionar bem. Você pode especificar um nome preliminar para o novo arquivo da seguinte forma: download = "myFile.txt"
Yster
1
Isso funciona no Edge no momento da redação deste comentário e parece ser a única maneira possível de interromper a abertura de PDFs com hiperlink na péssima tentativa do Edge de exibir um PDF.
No momento deste comentário, eu testei no Chrome, Opera, Edge, Mozilla. Todos os mais recentes. Está trabalhando em todos, exceto no Mozilla.
SI
7
Isso funciona apenas para links da mesma origem, conforme mencionado em caniuse.com/#feat=download . Se seus links são de origem cruzada, sua única opção (por enquanto) é forçar o tipo de resposta para "application / octet-stream", como muitas respostas sugerem. Se você não tiver acesso ao servidor, poderá tentar procurá-lo e definir o cabeçalho da resposta manualmente.
Jean-baptiste
80
<a href="file link" download target="_blank">Click here to download</a>

Funciona para mim no Firefox e Chrome.

DrWaky
fonte
2
É exatamente o mesmo que a principal resposta atual, de Ayush Gupta em 2013. No entanto, target="_blank"isso pode torná-lo um pouco mais utilizável para navegadores sem suporte (os PDFs são abertos em uma nova janela / guia, em vez de sobrescrever a página atual).
Sygmoral 5/09/14
3
Para mim, target="_blank"era necessário que downloadsó não conseguiu acionar o download corretamente (Chrome)
casraf
2
Se você fornecer uma sequência no downloadatributo, ela será usada como nome do arquivo. Estou usando-o em scripts de usuário o tempo todo.
weaknespase
34

As meta tags não são uma maneira confiável de obter esse resultado. Geralmente, você nem deve fazer isso - deve ficar ao usuário / agente de usuário decidir o que fazer com o conteúdo que você fornece. O usuário sempre pode forçar o navegador a baixar o arquivo, se desejar.

Se você ainda deseja forçar o navegador a baixar o arquivo, modifique os cabeçalhos HTTP diretamente. Aqui está um exemplo de código PHP:

$path = "path/to/file.pdf";
$filename = "file.pdf";
header('Content-Transfer-Encoding: binary');  // For Gecko browsers mainly
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT');
header('Accept-Ranges: bytes');  // Allow support for download resume
header('Content-Length: ' . filesize($path));  // File size
header('Content-Encoding: none');
header('Content-Type: application/pdf');  // Change the mime type if the file is not PDF
header('Content-Disposition: attachment; filename=' . $filename);  // Make the browser display the Save As dialog
readfile($path);  // This is necessary in order to get it to actually download the file, otherwise it will be 0Kb

Observe que isso é apenas uma extensão do protocolo HTTP; alguns navegadores podem ignorá-lo de qualquer maneira.

Karel Petranek
fonte
4
Na prática, acredito que isso seja amplamente implementado.
Matthew Wilson
Esta é a melhor solução, sem complicações e funciona. Você pode baixar diretamente qualquer tipo de arquivo usando este método. +1
casraf 16/06/12
3
A codificação de transferência de conteúdo não existe no HTTP. Codificação de conteúdo: nenhuma é inútil.
Julian Reschke
Faça uma nota em sua resposta, que se o arquivo for de um servidor externo / domínio, então esta resposta pode não ser a solução ...
T.Todua
Gostaria de acrescentar que tive esse código ou falha semelhante em determinados servidores quando os arquivos ficam grandes (> 80 MB no meu caso). Usar ob_end_flush()também não ajudou.
Hendrik
22

Eu tive esse mesmo problema e encontrei uma solução que funcionou muito bem até agora. Você coloca o seguinte código no seu .htaccessarquivo:

<FilesMatch "\.(?i:pdf)$">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>

Ele veio de Forçar o download de um arquivo em vez de aparecer no navegador .

Tony
fonte
4
Isso funcionou bem, pois eu tinha um diretório de documentos específico para downloads. Omiti o ForceType, apenas para deixar os tipos como estão. Eu também não precisava da distinção entre maiúsculas e minúsculas; o meu já parece não fazer distinção entre maiúsculas e minúsculas. <FilesMatch "\.(pdf|xlsx?|docx?)$">
Adicionei
Isso funcionou maravilhosamente, mesmo no OSX Safari, onde outras respostas (incluindo a aceita, como comentou um comentarista) são limitadas a determinados navegadores que suportam o recurso HTML fornecido. Este parece mais ideal para mim, pois funcionou de maneira geral, embora exija acesso de nível superior aos arquivos de configuração do servidor.
31915 bwright #
Você também pode colocar isso no seu arquivo apache.conf, não uso .htaccess, pois consome mais recursos.
Michael Fever
Como um site hospedado no Windows implementaria isso, uma vez que eles não podem ler arquivos htaccess?
precisa saber é o seguinte
9

Eu encontrei uma solução muito simples para o Firefox (funciona apenas com um href relativo e não direto): add type="application/octet-stream":

<a href="./file.pdf" id='example' type="application/octet-stream">Example</a>
Do utilizador
fonte
1
@ Martin Chrome no Chrome OS e Firefox no Linux. Acontece que o arquivo precisa ser local para funcionar. Meu href era um URL para armazenamento em nuvem.
precisa saber é o seguinte
7

Tente adicionar esta linha ao seu arquivo .htaccess.

AddType application/octet-stream .pdf

Espero que funcione, pois é independente do navegador.

Sharad Gautam
fonte
Eu estaria interessado em saber por que isso foi downvoted - é um dos métodos mais simples e funciona: css-tricks.com/snippets/htaccess/...
Nathan Hornby
As pessoas tentam modificar a funcionalidade principal de um servidor em sites de hospedagem gratuitos e, em seguida, diminuem o voto porque não conseguem fazê-lo funcionar. Todas as outras soluções terão advertências, pois é um "truque" para substituir isso.
Carrinho abandonado
Estou com o voto negativo porque é a solução errada para o problema. É uma má idéia mexer com tipos de recursos.
Brad
@ NathanHornby - Eu não diminuí a votação, mas isso não funcionaria em nenhum site hospedado no Windows, pois eles não usam .htaccess.
precisa saber é o seguinte
Não reduzi o voto, mas esta solução afeta cegamente TODOS os arquivos desse sufixo. É indiscriminado e, portanto, não será apropriado em todos os casos.
JBH
6

Geralmente isso acontece, porque algumas configurações ou plug-ins de navegadores abrem PDF diretamente na mesma janela como uma simples página da web.

O seguinte pode ajudá-lo. Eu fiz isso em PHP há alguns anos atrás. Mas atualmente não estou trabalhando nessa plataforma.

<?php
    if (isset($_GET['file'])) {
        $file = $_GET['file'];
        if (file_exists($file) && is_readable($file) && preg_match('/\.pdf$/',$file)) {
            header('Content-type: application/pdf');
            header("Content-Disposition: attachment; filename=\"$file\"");
            readfile($file);
        }
    }
    else {
        header("HTTP/1.0 404 Not Found");
        echo "<h1>Error 404: File Not Found: <br /><em>$file</em></h1>";
    }
?>

Salve o acima como download.php .

Salve esse pequeno trecho como um arquivo PHP em algum lugar do seu servidor e você pode usá-lo para fazer o download de um arquivo no navegador, em vez de exibir diretamente. Se você deseja exibir outros arquivos que não PDF, remova ou edite a linha 5.

Você pode usá-lo assim:

Adicione o seguinte link ao seu arquivo HTML.

<a href="download.php?file=my_pdf_file.pdf">Download the cool PDF.</a>

Referência de: Este blog

Ashay
fonte
7
Essa parece ser uma boa maneira de exibir todos os arquivos do servidor para quem está prestando atenção. download.php?file=database_password_file.phppor exemplo.
Pbarney
5

Basta colocar o código abaixo no seu .htaccessarquivo:

AddType application/octet-stream .csv
AddType application/octet-stream .xls
AddType application/octet-stream .doc
AddType application/octet-stream .avi
AddType application/octet-stream .mpg
AddType application/octet-stream .mov
AddType application/octet-stream .pdf

Ou você também pode fazer truques por JavaScript

element.setAttribute( 'download', whatever_string_you_want);
manish1706
fonte
1
Isso não pressupõe que o servidor da Web seja o Apache ?
Peter Mortensen
5

Acabei de usar isso, mas não sei se funciona em todos os navegadores.

Funciona no Firefox:

<a href="myfile.pdf" download>Click to Download</a>
NowLiveLove
fonte
1
Isso é sugerido, e com mais informações básicas, em uma resposta anterior .
precisa saber é o seguinte
4

Um realmente maneira simples de conseguir isso, sem usar sites de download externos ou modificar cabeçalhos, etc. é simplesmente criar um arquivo ZIP com o PDF dentro e vincular diretamente ao arquivo ZIP. Isso sempre acionará a caixa de diálogo Salvar / Abrir, e ainda é fácil para as pessoas clicar duas vezes nas janelas PDF em que o programa associado ao .zip é iniciado.

BTW ótima pergunta, eu estava procurando uma resposta também, uma vez que a maioria dos plug-ins PDF incorporados ao navegador leva muito tempo para exibir qualquer coisa (e geralmente travam o navegador enquanto o PDF está sendo carregado).

Mr. Bungle
fonte
31
Terrível usabilidade. Muitos usuários finais não sabem o que fazer com um arquivo zip.
CodeWarrior
1
Às vezes, solutioans simples são as melhores soluções!
elrado 21/10
1
Não é uma boa solução. Eu tenho exatamente esse problema com o Firefox e um arquivo ZIP. O que devo fazer? ZIP o arquivo? Nesse caso, modificar os cabeçalhos HTTP pode ser uma solução, mas não tenho acesso a isso.
Arnaud Weil
2

Uma solução do lado do servidor é mais compatível, até que o atributo "download" seja implementado em todos os navegadores.

Um exemplo de Python pode ser um manipulador de solicitação HTTP personalizado para um armazenamento de arquivos. Os links que apontam para o armazenamento de arquivos são gerados assim:

http://www.myfilestore.com/filestore/13/130787e71/download_as/desiredName.pdf

Aqui está o código:

class HTTPFilestoreHandler(SimpleHTTPRequestHandler):

    def __init__(self, fs_path, *args):
        self.fs_path = fs_path                          # Filestore path
        SimpleHTTPRequestHandler.__init__(self, *args)

    def send_head(self):
        # Overwrite SimpleHTTPRequestHandler.send_head to force download name
        path = self.path
        get_index = (path == '/')
        self.log_message("path: %s" % path)
        if '/download_as/' in path:
            p_parts = path.split('/download_as/')
            assert len(p_parts) == 2, 'Bad download link:' + path
            path, download_as = p_parts
        path = self.translate_path(path )
        f = None
        if os.path.isdir(path):
            if not self.path.endswith('/'):
                # Redirect browser - doing basically what Apache does
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        fs = os.fstat(f.fileno())
        self.send_header("Expires", '0')
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.send_header("Cache-Control", 'must-revalidate, post-check=0, pre-check=0')
        self.send_header("Content-Transfer-Encoding", 'binary')
        if download_as:
            self.send_header("Content-Disposition", 'attachment; filename="%s"' % download_as)
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Connection", 'close')
        self.end_headers()
        return f


class HTTPFilestoreServer:

    def __init__(self, fs_path, server_address):
        def handler(*args):
            newHandler = HTTPFilestoreHandler(fs_path, *args)
            newHandler.protocol_version = "HTTP/1.0"
        self.server = BaseHTTPServer.HTTPServer(server_address, handler)

    def serve_forever(self, *args):
        self.server.serve_forever(*args)


def start_server(fs_path, ip_address, port):
    server_address = (ip_address, port)
    httpd = HTTPFilestoreServer(fs_path, server_address)

    sa = httpd.server.socket.getsockname()
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
    httpd.serve_forever()
yucer
fonte
2

Uma maneira muito fácil de fazer isso, se você precisar forçar o download de um único link em sua página, é usar o atributo de download HTML5 no link href.

Consulte: http://davidwalsh.name/download-attribute

com isso, você pode renomear o arquivo que o usuário fará o download e, ao mesmo tempo, força o download.

Houve um debate sobre se isso é uma boa prática ou não, mas no meu caso eu tenho um visualizador incorporado para um arquivo PDF e o visualizador não oferece um link para download, por isso preciso fornecer um separadamente. Aqui, quero garantir que o usuário não abra o PDF no navegador da Web, o que seria confuso.

Isso não é necessário, abra a caixa de diálogo Salvar como, mas baixe o link diretamente para o destino de download predefinido. E, é claro, se você estiver criando um site para outra pessoa e precisar que ela escreva atributos manualmente em seus links, provavelmente é uma má idéia, mas se houver uma maneira de inserir o atributo nos links, isso pode ser uma solução leve.

JJxyz
fonte
1

Este é um post antigo, mas aqui está a minha solução em JavaScript, que usa a biblioteca jQuery.

<script>
(function($){
    var download = [];
    $('a.force-download, .force-download a').each(function(){
        // Collect info
        var $this = $(this),
            $href = $this.attr('href'),
            $split = $href.split('/'),
            $name = document.title.replace(/[\W_]/gi, '-').replace(/-{2,}/g, '-'); // get title and clean it for the URL

        // Get filename from URL
        if($split[($split.length-1)])
        {
            $tmp = $split[($split.length-1)];
            $tmp = $tmp.split('.');
            $name = $tmp[0].replace(/[\W_]/gi, '-').replace(/-{2,}/g, '-');
        }

        // If name already exists, put timestamp there
        if($.inArray($name, download) > -1)
        {
            $name = $name + '-' + Date.now().replace(/[\W]/gi, '-');
        }

        $(this).attr("download", $name);
        download.push($name);
    });
}(jQuery || window.jQuery))
</script>

Você só precisa usar a classe force-downloaddentro da sua <a>tag e forçará o download automaticamente. Você também pode adicioná-lo ao pai dive selecionará todos os links dentro dele.

Exemplo:

<a href="/some/good/url/Post-Injection_Post-Surgery_Instructions.pdf" class="force-download" target="_blank">Download PDF</a>

Isso é ótimo para o WordPress e outros sistemas ou sites personalizados.

Ivijan Stefan Stipić
fonte
0

Após o nome do arquivo no código HTML, adiciono ?forcedownload=1

Essa foi a maneira mais simples de acionar uma caixa de diálogo para salvar ou baixar.

Bonnie
fonte
0

Se você possui um plugin no navegador que sabe como abrir um arquivo PDF, ele será aberto diretamente. Como no caso de imagens e conteúdo HTML.

Portanto, a abordagem alternativa não é enviar seu tipo MIME na resposta. Dessa maneira, o navegador nunca saberá qual plugin deve abri-lo. Portanto, ele fornecerá uma caixa de diálogo Salvar / Abrir .

sushil bharwani
fonte
Isso é difícil de conseguir, porque é o servidor que envia o tipo MIME e, ao vincular diretamente a um arquivo PDF, você não pode alterar os cabeçalhos.
precisa saber é o seguinte
0

Eu apenas tive um problema muito semelhante com o problema adicional necessário para criar links de download para arquivos dentro de um arquivo ZIP.

Tentei primeiro criar um arquivo temporário e, em seguida, forneci um link para o arquivo temporário, mas descobri que alguns navegadores apenas exibiam o conteúdo (um arquivo CSV Excel) em vez de oferecer o download. Eventualmente, encontrei a solução usando um servlet. Ele funciona no Tomcat e no GlassFish, e eu tentei no Internet Explorer 10 e Chrome.

O servlet usa como entrada um nome de caminho completo para o arquivo ZIP e o nome do arquivo dentro do zip que deve ser baixado.

Dentro do meu arquivo JSP, tenho uma tabela exibindo todos os arquivos dentro do zip, com links que dizem: onclick='download?zip=<%=zip%>&csv=<%=csv%>'

O código do servlet está em download.java:

package myServlet;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.zip.*;
import java.util.*;

// Extend HttpServlet class
public class download extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        PrintWriter out = response.getWriter(); // now we can write to the client

        String filename = request.getParameter("csv");
        String zipfile = request.getParameter("zip");

        String aLine = "";

        response.setContentType("application/x-download");
        response.setHeader( "Content-Disposition", "attachment; filename=" + filename); // Force 'save-as'
        ZipFile zip = new ZipFile(zipfile);
        for (Enumeration e = zip.entries(); e.hasMoreElements();) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            if(entry.toString().equals(filename)) {
                InputStream is = zip.getInputStream(entry);
                BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 65536);
                while ((aLine = br.readLine()) != null) {
                    out.println(aLine);
                }
                is.close();
                break;
            }
        }
    }
}

Para compilar no Tomcat, você precisa do caminho de classe para incluir tomcat \ lib \ servlet-api.jar ou no GlassFish: glassfish \ lib \ j2ee.jar

Mas qualquer um deles trabalhará em ambos. Você também precisa definir seu servlet web.xml.

mljm
fonte
0

Adicione um cabeçalho de resposta Content-Disposition: attachment; seguido pelo nome do arquivo. Remova o Meta Content-Disposition; Inline; que abrirá o documento na mesma janela

Em java, é definido como

response.setHeader("Content-Disposition", "attachment;filename=test.jpg");
johnmin
fonte
-2

Com arquivos PDF grandes, o navegador trava. No Mozilla, menu FerramentasOpçõesAplicativos e depois ao lado do tipo de conteúdo do documento Adobe Acrobat. Na lista suspensa Ação, selecione Sempre perguntar .

Isso não funcionou para mim, então o que funcionou foi:

Ferramentas de menu * → ComplementosAdobe Acrobat (plugin Adobe PDF para Firefox) → DESATIVAR. Agora eu posso baixar e-books!

Joojoo
fonte
2
você leu a pergunta? esta não é uma resposta cross browser
Mark
1
@mark também é instruções para um usuário solicitar downloads forçados de PDFs, não o proprietário de um site.
Nathan Hornby