Erzwingen Sie das Öffnen des Popups "Speichern unter ...", das beim Klicken auf einen Textlink geöffnet wird. Klicken Sie für PDF in HTML


173

Ich habe einige große PDF-Kataloge auf meiner Website und muss diese als Download verknüpfen. Als ich gegoogelt habe, habe ich so etwas unten notiert gefunden. Es sollte das Popup " Speichern unter ... " beim Klicken auf den Link öffnen ...

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

Aber es funktioniert nicht: / Wenn ich wie unten auf eine Datei verweise, verlinkt es nur auf eine Datei und versucht, die Datei zu öffnen.

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

UPDATE (gemäß den Antworten unten):

Wie ich sehe, gibt es dafür keine 100% zuverlässige Cross-Browser-Lösung. Der wahrscheinlich beste Weg ist, einen der unten aufgeführten Webdienste zu verwenden und einen Download-Link anzugeben ...


1
Verwenden Sie nicht den Mimetyp für PDF-Dateien.
Bhups

Ich habe Ihre aktualisierte Lösung ausprobiert, artmania - aber das gleiche Problem, das ich in Safari hatte, ist aufgetreten. Ich erhalte im Browserfenster eine PDF-Datei, und nur wenn ich unten auf die Registerkarten "Vorschau" oder "Herunterladen" klicke, erhalte ich die Suchfunktion, die ich so dringend benötige.
Heathwaller


Antworten:


267

Von einer Antwort auf Erzwingen, dass ein Browser die Datei wie nach dem Klicken auf den Link speichert :

<a href="path/to/file" download>Click here to download</a>

17
Zum Zeitpunkt dieses Kommentars ist das downloadAttribut auf Chrome, Firefox und Opera beschränkt. Selbst neuere Versionen von IE und Safari unterstützen dies nicht. Für zukünftige Unterstützung: überprüfen Sie caniuse.com/#feat=download !
Sygmoral

Netbeans Fehlerprüfung beschwert sich darüber, aber es scheint gut zu funktionieren. Sie können einen vorläufigen Namen für die neue Datei wie folgt angeben: download = "myFile.txt"
Yster

1
Dies funktioniert in Edge zum Zeitpunkt des Schreibens dieses Kommentars und scheint die einzige Möglichkeit zu sein, das Öffnen von PDF-Dateien mit Hyperlinks zu stoppen, wenn Edge einen sehr schlechten Versuch mit einem PDF-Viewer unternimmt.

Zum Zeitpunkt dieses Kommentars habe ich ihn auf Chrome, Opera, Edge und Mozilla getestet. Alles neu. Arbeitet an allen außer an Mozilla.
SI

6
Dies funktioniert nur für Links gleichen Ursprungs, wie unter caniuse.com/#feat=download erwähnt . Wenn es sich bei Ihren Links um Cross-Origin-Links handelt, besteht Ihre einzige Option (vorerst) darin, den Antworttyp auf "application / octet-stream" zu setzen, wie viele Antworten vermuten lassen. Wenn Sie keinen Zugriff auf den Server haben, können Sie versuchen, ihn zu vertreten und den Antwortheader manuell festzulegen.
Jean-Baptiste

80
<a href="file link" download target="_blank">Click here to download</a>

Es funktioniert für mich in Firefox und Chrome.


2
Es ist genau das Gleiche wie die aktuelle Top-Antwort von Ayush Gupta aus dem Jahr 2013. Dies target="_blank"kann jedoch dazu führen, dass es für nicht unterstützende Browser etwas benutzerfreundlicher ist (PDFs werden dann in einem neuen Fenster / Tab geöffnet, anstatt die aktuelle Seite zu überschreiben).
Sygmoral

3
Für mich target="_blank"war notwendig, da downloadnur der Download nicht richtig ausgelöst werden konnte (Chrome)
casraf

2
Wenn Sie im downloadAttribut eine Zeichenfolge angeben, wird diese als Dateiname verwendet. Ich benutze es die ganze Zeit in Userscripts.
Schwachstellen

34

Meta-Tags sind kein zuverlässiger Weg, um dieses Ergebnis zu erzielen. Im Allgemeinen sollten Sie dies nicht einmal tun - es sollte dem Benutzer / Benutzeragenten überlassen bleiben, zu entscheiden, was mit den von Ihnen bereitgestellten Inhalten geschehen soll. Der Benutzer kann seinen Browser jederzeit zwingen, die Datei herunterzuladen, wenn er dies wünscht.

Wenn Sie den Browser dennoch zum Herunterladen der Datei zwingen möchten, ändern Sie die HTTP-Header direkt. Hier ist ein PHP-Codebeispiel:

$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

Beachten Sie, dass dies nur eine Erweiterung des HTTP-Protokolls ist. Einige Browser ignorieren es möglicherweise trotzdem.


4
In der Praxis glaube ich, dass dies weit verbreitet ist.
Matthew Wilson

Dies ist die beste Lösung, problemlos und funktioniert. Mit dieser Methode können Sie jeden Dateityp direkt herunterladen. +1
Casraf

3
Content-Transfer-Encoding existiert in HTTP nicht. Inhaltskodierung: Keine ist nutzlos.
Julian Reschke

Machen Sie in Ihrer Antwort einen Hinweis, dass die IF-Datei von einem externen Server / einer externen Domäne stammt, dann ist diese Antwort möglicherweise keine Lösung ...
T.Todua

Ich möchte hinzufügen, dass dieser oder ein ähnlicher Code auf bestimmten Servern fehlgeschlagen ist, wenn Dateien groß werden (in meinem Fall> 80 MB). Die Verwendung ob_end_flush()hat auch nicht geholfen.
Hendrik

22

Ich hatte das gleiche Problem und fand eine Lösung, die bisher großartig funktioniert hat. Sie fügen den folgenden Code in Ihre .htaccessDatei ein:

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

Es kam von Force a File to Download, anstatt im Browser angezeigt zu werden .


4
Dies funktionierte gut, da ich ein bestimmtes Dokumentverzeichnis zum Herunterladen hatte. Ich habe den ForceType weggelassen, nur um die Typen unverändert zu lassen. Ich brauchte auch keine Groß- und Kleinschreibung; meins scheint bereits zwischen Groß- und Kleinschreibung zu unterscheiden. Ich habe ein paar zusätzliche Typen hinzugefügt, einschließlich optional-x für die alten / neuen Office-Erweiterungen:<FilesMatch "\.(pdf|xlsx?|docx?)$">
goodeye

Dies hat auch in OSX Safari wunderbar funktioniert, wo andere Antworten (einschließlich der akzeptierten, wie ein Kommentator dort hervorhob) auf bestimmte Browser beschränkt sind, die die angegebene HTML-Funktion unterstützen. Dieser scheint mir idealer zu sein, da er auf der ganzen Linie funktioniert hat, obwohl er einen übergeordneten Zugriff auf die Serverkonfigurationsdateien erfordert.
Bwright

Sie können das auch in Ihre apache.conf-Datei einfügen. Ich verwende .htaccess nicht, da es mehr Ressourcen benötigt.
Michael Fever

Wie würde eine von Windows gehostete Website dies implementieren, da sie keine htaccess-Dateien lesen kann?
PoloHoleSet

9

Ich habe eine sehr einfache Lösung für Firefox gefunden (funktioniert nur mit einem Verwandten und nicht mit einem direkten href): add type="application/octet-stream":

<a href="./file.pdf" id='example' type="application/octet-stream">Example</a>

1
@ Martin Chrome unter Chrome OS und Firefox unter Linux. Es stellt sich heraus, dass die Datei lokal sein muss, damit sie funktioniert. Mein href war eine URL zum Cloud-Speicher.
ttfreeman

7

Versuchen Sie, diese Zeile zu Ihrer .htaccess-Datei hinzuzufügen.

AddType application/octet-stream .pdf

Ich hoffe, es wird funktionieren, da es browserunabhängig ist.


Es würde mich interessieren, warum dies abgelehnt wurde - es ist eine der einfachsten Methoden und funktioniert: css-tricks.com/snippets/htaccess/…
Nathan Hornby

Die Leute versuchen, die Kernfunktionalität eines Servers auf kostenlosen Hosting-Sites zu ändern und dann abzustimmen, weil sie ihn nicht zum Laufen bringen können. Jede andere Lösung wird Vorbehalte haben, da es ein "Hack" ist, dies zu ersetzen.
Verlassener Wagen

Ich stimme es ab, weil es die falsche Lösung für das Problem ist. Es ist eine schlechte Idee, sich mit Arten von Ressourcen herumzuschlagen.
Brad

@ NathanHornby - Ich habe es nicht abgelehnt, aber dies würde für keine von Windows gehostete Site funktionieren, da sie .htaccess nicht verwenden.
PoloHoleSet

Ich habe nicht abgelehnt, aber diese Lösung wirkt sich blind auf ALLE Dateien dieses Suffix aus. Es ist wahllos und daher nicht in allen Fällen angemessen.
JBH

6

Im Allgemeinen geschieht dies, weil einige Browsereinstellungen oder Plug-Ins PDF direkt im selben Fenster wie eine einfache Webseite öffnen.

Folgendes könnte Ihnen helfen. Ich habe es vor ein paar Jahren in PHP gemacht. Aber momentan arbeite ich nicht an dieser Plattform.

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

Speichern Sie die oben genannten als download.php .

Speichern Sie dieses kleine Snippet als PHP-Datei irgendwo auf Ihrem Server, und Sie können es verwenden, um eine Datei im Browser herunterzuladen, anstatt sie direkt anzuzeigen. Wenn Sie andere Dateien als PDF bereitstellen möchten, entfernen oder bearbeiten Sie Zeile 5.

Sie können es so verwenden:

Fügen Sie Ihrer HTML-Datei den folgenden Link hinzu.

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

Referenz von: Dieser Blog


7
Dies scheint eine gute Möglichkeit zu sein, jede einzelne Datei auf Ihrem Server für jeden bereitzustellen, der darauf achtet. download.php?file=database_password_file.phpbeispielsweise.
Pbarney

5

Fügen Sie einfach den folgenden Code in Ihre .htaccessDatei ein:

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

Oder Sie können auch einen Trick mit JavaScript ausführen

element.setAttribute( 'download', whatever_string_you_want);

1
Nimmt dies nicht an, dass der Webserver Apache ist ?
Peter Mortensen

5

Ich habe das gerade benutzt, aber ich weiß nicht, ob es in allen Browsern funktioniert.

Es funktioniert in Firefox:

<a href="myfile.pdf" download>Click to Download</a>

1
Dies wird in einer früheren Antwort mit mehr Hintergrundinformationen vorgeschlagen .
usr2564301

4

Ein wirklich einfache Möglichkeit, dies zu erreichen, ohne externe Download-Sites zu verwenden oder Header usw. zu ändern, besteht darin, einfach eine ZIP-Datei mit der darin enthaltenen PDF-Datei zu erstellen und direkt mit der ZIP-Datei zu verknüpfen. Dies löst IMMER das Dialogfeld Speichern / Öffnen aus, und es ist für Benutzer immer noch einfach, auf die PDF-Fenster zu doppelklicken, mit denen das mit .zip verknüpfte Programm gestartet wird.

Übrigens, ich habe auch nach einer Antwort gesucht, da die meisten in den Browser eingebetteten PDF-Plugins sooo lange brauchen, um etwas anzuzeigen (und den Browser oft hängen lassen, während das PDF geladen wird).


31
Schreckliche Benutzerfreundlichkeit. Viele Endbenutzer würden nicht wissen, was sie mit einer Zip-Datei tun sollen.
CodeWarrior

1
Manchmal sind einfache Lösungen die besten Lösungen!
Elrado

1
Keine gute Lösung. Ich habe genau dieses Problem mit Firefox und einer ZIP-Datei. Was soll ich machen? Datei komprimieren? In diesem Fall könnte das Ändern der HTTP-Header eine Lösung sein, aber ich habe keinen Zugriff darauf.
Arnaud Weil

2

Eine serverseitige Lösung ist kompatibler, bis das Attribut "Download" in allen Browsern implementiert ist.

Ein Python-Beispiel könnte ein benutzerdefinierter HTTP-Anforderungshandler für einen Dateispeicher sein. Die Links, die auf den Dateispeicher verweisen, werden wie folgt generiert:

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

Hier ist der Code:

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()

2

Eine sehr einfache Möglichkeit, dies zu tun, wenn Sie den Download für einen einzelnen Link auf Ihrer Seite erzwingen müssen, ist die Verwendung des HTML5-Download-Attributs im href-Link.

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

Damit können Sie die Datei umbenennen, die der Benutzer herunterladen wird, und gleichzeitig den Download erzwingen.

Es gab eine Debatte darüber, ob dies eine gute Praxis ist oder nicht, aber in meinem Fall habe ich einen eingebetteten Viewer für eine PDF-Datei und der Viewer bietet keinen Download-Link an, daher muss ich einen separat bereitstellen. Hier möchte ich sicherstellen, dass der Benutzer die PDF-Datei nicht im Webbrowser öffnet, was verwirrend wäre.

Öffnen Sie dazu nicht unbedingt den Dialog zum Speichern unter, sondern laden Sie den Link direkt zum voreingestellten Download-Ziel herunter. Und natürlich ist es wahrscheinlich eine schlechte Idee, wenn Sie eine Site für eine andere Person erstellen und diese manuell Attribute in ihre Links schreiben müssen. Wenn es jedoch eine Möglichkeit gibt, das Attribut in die Links zu integrieren, kann dies eine einfache Lösung sein.


1

Dies ist ein alter Beitrag, aber hier ist der meine Lösung in JavaScript, was die Verwendung der jQuery-Bibliothek betrifft.

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

Sie müssen nur die Klasse force-downloadin Ihrem <a>Tag verwenden und erzwingen den automatischen Download. Sie können es auch dem übergeordneten divElement hinzufügen und alle darin enthaltenen Links übernehmen.

Beispiel:

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

Dies ist ideal für WordPress und alle anderen Systeme oder benutzerdefinierten Websites.


0

Nach dem Dateinamen im HTML-Code füge ich hinzu ?forcedownload=1

Dies war für mich die einfachste Möglichkeit, ein Dialogfeld zum Speichern oder Herunterladen auszulösen.


0

Wenn Sie ein Plugin im Browser haben, das weiß, wie man eine PDF-Datei öffnet, wird es direkt geöffnet. Wie bei Bildern und HTML-Inhalten.

Der alternative Ansatz besteht also nicht darin, Ihren MIME-Typ in der Antwort zu senden. Auf diese Weise wird der Browser nie wissen, welches Plugin es öffnen soll. Daher erhalten Sie ein Dialogfeld zum Speichern / Öffnen .


Dies ist schwer zu erreichen, da der Server den MIME-Typ sendet und Sie beim direkten Verknüpfen mit einer PDF-Datei die Header nicht ändern können.
Karel Petranek

0

Ich hatte gerade ein sehr ähnliches Problem mit dem zusätzlichen Problem, dass ich Download-Links zu Dateien in einer ZIP-Datei erstellen musste.

Ich habe zuerst versucht, eine temporäre Datei zu erstellen, dann einen Link zur temporären Datei bereitgestellt, aber ich habe festgestellt, dass einige Browser nur den Inhalt (eine CSV-Excel-Datei) anzeigen, anstatt das Herunterladen anzubieten. Schließlich fand ich die Lösung mithilfe eines Servlets. Es funktioniert sowohl mit Tomcat als auch mit GlassFish, und ich habe es mit Internet Explorer 10 und Chrome versucht.

Das Servlet verwendet als Eingabe einen vollständigen Pfadnamen zur ZIP-Datei und den Namen der Datei in der Zip-Datei, die heruntergeladen werden soll.

In meiner JSP-Datei befindet sich eine Tabelle, in der alle Dateien in der Zip-Datei mit folgenden Links angezeigt werden: onclick='download?zip=<%=zip%>&csv=<%=csv%>'

Der Servlet-Code befindet sich in 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;
            }
        }
    }
}

Zum Kompilieren unter Tomcat muss der Klassenpfad tomcat \ lib \ servlet-api.jar oder unter GlassFish: glassfish \ lib \ j2ee.jar enthalten

Aber einer von beiden wird an beiden arbeiten. Sie müssen auch Ihr Servlet einstellen web.xml.


0

Hinzufügen eines Antwortheaders Inhaltsdisposition: Anhang; gefolgt vom Dateinamen. Entfernen Sie die Meta Content-Disposition; Inline; Dadurch wird das Dokument im selben Fenster geöffnet

In Java ist es gesetzt als

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

-2

Bei großen PDF-Dateien hängt der Browser. In Mozilla das Menü ExtrasOptionenAnwendungen und dann neben dem Inhaltstyp Adobe Acrobat-Dokument. Wählen Sie in der Dropdown-Liste Aktion die Option Immer fragen aus .

Das hat bei mir nicht funktioniert, also hat es funktioniert:

Menü-Tools * → Add-OnsAdobe Acrobat (Adobe PDF-Plugin für Firefox) → DEAKTIVIEREN. Jetzt kann ich E-Books herunterladen!


2
Hast du die Frage gelesen? dies ist keine Cross - Browser - Antwort
Mark

1
@mark ist auch eine Anweisung für einen Benutzer, erzwungene Downloads von PDFs zu veranlassen, nicht für einen Websitebesitzer.
Nathan Hornby
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.