Forcer l'ouverture de la fenêtre contextuelle «Enregistrer sous…» ouverte au lien texte cliquez pour PDF en HTML


173

J'ai des catalogues PDF de grande taille sur mon site Web et je dois les lier en téléchargement. Lorsque j'ai cherché sur Google, j'ai trouvé une telle chose ci-dessous. Il devrait ouvrir la fenêtre contextuelle " Enregistrer sous ... " au clic sur le lien ...

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

Mais cela ne fonctionne pas: / Lorsque je crée un lien vers un fichier comme ci-dessous, il ne fait que créer un lien vers le fichier et essaie d'ouvrir le fichier.

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

MISE À JOUR (selon les réponses ci-dessous):

Comme je le vois, il n'existe pas de solution multi-navigateurs fiable à 100% pour cela. Le meilleur moyen est probablement d'utiliser l'un des services Web énumérés ci-dessous et de fournir un lien de téléchargement ...


1
ne pas servir le type MIME pour les fichiers pdf.
bhups le

J'ai essayé votre solution mise à jour, artmania - mais le même problème que j'ai rencontré dans Safari s'est produit. J'obtiens ce qui ressemble au PDF dans la fenêtre du navigateur, et ce n'est que lorsque je clique sur les onglets «aperçu» ou «téléchargement» en bas que j'obtiens la fonction de recherche dont j'ai désespérément besoin.
heathwaller


Réponses:


268

D'une réponse à Forcer un navigateur à enregistrer le fichier comme après avoir cliqué sur le lien :

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

17
Au moment de ce commentaire, l' downloadattribut est limité à Chrome, Firefox et Opera. Même les versions récentes d'IE et de Safari ne le prennent pas en charge. Pour une assistance future: consultez caniuse.com/#feat=download !
Sygmoral

La vérification des erreurs Netbeans s'en plaint, mais cela semble fonctionner correctement. Vous pouvez spécifier un nom préliminaire pour le nouveau fichier comme ceci: download = "myFile.txt"
Yster

1
Cela fonctionne dans Edge au moment de la rédaction de ce commentaire et semble être le seul moyen possible d'empêcher l'ouverture de fichiers PDF avec hyperlien lors de la très mauvaise tentative d'Edge de visionneuse de PDF.

Au moment de ce commentaire, je l'ai testé sur Chrome, Opera, Edge, Mozilla. Tous les derniers. Fonctionne sur tous sauf sur Mozilla.
SI

7
Cela ne fonctionne que pour les liens de même origine, comme mentionné sur caniuse.com/#feat=download . Si vos liens sont d'origine croisée, votre seule option (pour l'instant) est de forcer le type de réponse à "application / octet-stream", comme le suggèrent de nombreuses réponses. Si vous n'avez pas accès au serveur, vous pouvez essayer de le proxy et définir l'en-tête de réponse manuellement.
jean-baptiste

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

Cela fonctionne pour moi dans Firefox et Chrome.


2
C'est exactement la même chose que la réponse principale actuelle, d'Ayush Gupta en 2013. target="_blank"Cela peut la rendre légèrement plus utilisable pour les navigateurs non compatibles (les fichiers PDF s'ouvrent ensuite dans une nouvelle fenêtre / onglet, plutôt que d'écraser la page actuelle).
Sygmoral

3
Pour moi, target="_blank"c'était nécessaire car downloadseulement échoué à déclencher le téléchargement correctement (Chrome)
casraf

2
Si vous donnez une chaîne dans l' downloadattribut, elle sera utilisée comme nom de fichier. Je l'utilise tout le temps dans les scripts utilisateur.
lownespase

34

Les balises Meta ne sont pas un moyen fiable d'atteindre ce résultat. En général, vous ne devriez même pas faire cela - il devrait être laissé à l'utilisateur / agent utilisateur de décider quoi faire avec le contenu que vous fournissez. L'utilisateur peut toujours forcer son navigateur à télécharger le fichier s'il le souhaite.

Si vous souhaitez toujours forcer le navigateur à télécharger le fichier, modifiez directement les en-têtes HTTP. Voici un exemple de code 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

Notez qu'il ne s'agit que d'une extension du protocole HTTP; certains navigateurs peuvent de toute façon l'ignorer.


4
Dans la pratique, je pense que cela est largement appliqué.
Matthew Wilson

C'est la meilleure solution, sans tracas et fonctionne. Vous pouvez télécharger directement n'importe quel type de fichier en utilisant cette méthode. +1
casraf

3
Content-Transfer-Encoding n'existe pas dans HTTP. Content-Encoding: aucun n'est inutile.
Julian Reschke

NOTEZ dans votre réponse que si le fichier provient d'un serveur / domaine externe, cette réponse n'est peut-être pas une solution ...
T.Todua

Je voudrais ajouter que j'ai eu ce code ou un code similaire échoué sur certains serveurs lorsque les fichiers deviennent volumineux (> 80 Mo dans mon cas). L'utilisation ob_end_flush()n'a pas aidé non plus.
Hendrik le

22

J'ai eu ce même problème et j'ai trouvé une solution qui a très bien fonctionné jusqu'à présent. Vous mettez le code suivant dans votre .htaccessfichier:

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

Il est venu de Forcer un fichier à télécharger au lieu de s'afficher dans le navigateur .


4
Cela fonctionnait bien, car j'avais un répertoire de documents particulier pour les téléchargements. J'ai omis le ForceType, juste pour laisser les types rester tels quels. Je n'avais pas non plus besoin de la sensibilité à la casse; le mien semble déjà insensible à la casse. J'ai ajouté quelques types supplémentaires, y compris optionnel-x pour les anciennes / nouvelles extensions Office:<FilesMatch "\.(pdf|xlsx?|docx?)$">
goodeye

Cela a fonctionné à merveille, même dans OSX Safari, où d'autres réponses (y compris celle acceptée, comme l'a souligné un commentateur) sont limitées à certains navigateurs prenant en charge la fonctionnalité HTML donnée. Celui-ci me semble plus idéal car il a fonctionné dans tous les domaines, bien qu'il nécessite un accès de plus haut niveau aux fichiers de configuration du serveur.
bwright du

Vous pouvez également le mettre dans votre fichier apache.conf, je n'utilise pas .htaccess car cela prend plus de ressources.
Michael Fever

Comment un site Web hébergé par Windows implémenterait-il cela, puisqu'il ne peut pas lire les fichiers htaccess?
PoloHoleSet

10

J'ai trouvé une solution très simple pour Firefox (ne fonctionne qu'avec un href relatif plutôt que direct): ajouter type="application/octet-stream":

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

1
@Martin Chrome sur Chrome OS et Firefox sur Linux. Il s'avère que le fichier doit être local pour qu'il fonctionne. Mon href était une URL vers le stockage en nuage.
ttfreeman

7

Essayez d'ajouter cette ligne à votre fichier .htaccess.

AddType application/octet-stream .pdf

J'espère que cela fonctionnera car il est indépendant du navigateur.


Je serais intéressé de savoir pourquoi cela a été déclassé - c'est l'une des méthodes et des méthodes les plus simples: css-tricks.com/snippets/htaccess
Nathan Hornby

Les gens essaient de modifier la fonctionnalité de base d'un serveur sur des sites d'hébergement gratuits, puis votent contre parce qu'ils ne peuvent pas le faire fonctionner. Toutes les autres solutions auront des mises en garde car c'est un "hack" pour remplacer cela.
Panier abandonné le

Je vote défavorablement parce que c'est la mauvaise solution au problème. C'est une mauvaise idée de jouer avec les types de ressources.
Brad

@NathanHornby - Je n'ai pas voté contre, mais cela ne fonctionnerait pour aucun site hébergé par Windows, car ils n'utilisent pas .htaccess.
PoloHoleSet

Je n'ai pas voté contre, mais cette solution affecte aveuglément TOUS les fichiers de ce suffixe. Il est aveugle et ne sera donc pas approprié dans tous les cas.
JBH

6

En général, cela se produit, car certains paramètres de navigateur ou plug-ins ouvrent directement le PDF dans la même fenêtre, comme une simple page Web.

Ce qui suit pourrait vous aider. Je l'ai fait en PHP il y a quelques années. Mais actuellement, je ne travaille pas sur cette plate-forme.

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

Enregistrez ce qui précède sous download.php .

Enregistrez ce petit extrait en tant que fichier PHP quelque part sur votre serveur et vous pouvez l'utiliser pour télécharger un fichier dans le navigateur, plutôt que de l'afficher directement. Si vous souhaitez diffuser des fichiers autres que PDF, supprimez ou modifiez la ligne 5.

Vous pouvez l'utiliser comme ceci:

Ajoutez le lien suivant à votre fichier HTML.

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

Référence de: Ce blog


7
Cela semble être une bonne façon de servir chaque fichier de votre serveur à tous ceux qui y prêtent attention. download.php?file=database_password_file.phppar exemple.
pbarney

5

Mettez simplement le code ci-dessous dans votre .htaccessfichier:

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 vous pouvez également faire des trucs en JavaScript

element.setAttribute( 'download', whatever_string_you_want);

1
Cela ne suppose-t-il pas que le serveur Web est Apache ?
Peter Mortensen

5

Je viens de l'utiliser, mais je ne sais pas si cela fonctionne sur tous les navigateurs.

Cela fonctionne dans Firefox:

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

1
Cela est suggéré, et avec plus d'informations générales, dans une réponse précédente .
usr2564301

4

Un moyen très simple d'y parvenir, sans utiliser de sites de téléchargement externes ou modifier les en-têtes, etc. consiste simplement à créer un fichier ZIP avec le PDF à l'intérieur et à le lier directement au fichier ZIP. Cela déclenchera TOUJOURS la boîte de dialogue Enregistrer / Ouvrir, et il est toujours facile pour les gens de double-cliquer sur les fenêtres PDF sur lesquelles le programme associé à .zip est lancé.

BTW excellente question, je cherchais également une réponse, car la plupart des plugins PDF intégrés au navigateur prennent tellement de temps à afficher quoi que ce soit (et bloquent souvent le navigateur pendant le chargement du PDF).


31
Terrible utilisabilité. De nombreux utilisateurs finaux ne sauraient pas quoi faire avec un fichier zip.
CodeWarrior

1
Parfois, de simples solutioans sont les meilleures solutions!
elrado

1
Pas une bonne solution. J'ai exactement ce problème avec Firefox et un fichier ZIP. Que devrais-je faire? ZIP le fichier? Dans ce cas, la modification des en-têtes HTTP pourrait être une solution mais je n'y ai pas accès.
Arnaud Weil

2

Une solution côté serveur est plus compatible, jusqu'à ce que l'attribut "download" soit implémenté dans tous les navigateurs.

Un exemple Python pourrait être un gestionnaire de requêtes HTTP personnalisé pour un magasin de fichiers. Les liens qui pointent vers le magasin de fichiers sont générés comme ceci:

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

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

Un moyen très simple de le faire, si vous avez besoin de forcer le téléchargement pour un seul lien sur votre page, est d'utiliser l'attribut de téléchargement HTML5 dans le lien href.

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

avec cela, vous pouvez renommer le fichier que l'utilisateur va télécharger et en même temps, il force le téléchargement.

Il y a eu un débat pour savoir si c'est une bonne pratique ou non, mais dans mon cas, j'ai une visionneuse intégrée pour un fichier PDF et la visionneuse n'offre pas de lien de téléchargement, je dois donc en fournir un séparément. Ici, je veux m'assurer que l'utilisateur n'ouvre pas le PDF dans le navigateur Web, ce qui serait déroutant.

Cela ne sera pas nécessaire d'ouvrir la boîte de dialogue Enregistrer sous, mais téléchargera le lien directement vers la destination de téléchargement prédéfinie. Et bien sûr, si vous créez un site pour quelqu'un d'autre et que vous avez besoin qu'ils écrivent manuellement des attributs sur leurs liens, c'est probablement une mauvaise idée, mais s'il existe un moyen d'intégrer l'attribut dans les liens, cela peut être une solution légère.


1

C'est un ancien article, mais voici ma solution en JavaScript à l'aide de la bibliothèque 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>

Il vous suffit d'utiliser la classe à l' force-downloadintérieur de votre <a>balise et forcera le téléchargement automatiquement. Vous pouvez également l'ajouter au parent divet récupérer tous les liens qu'il contient.

Exemple:

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

C'est idéal pour WordPress et tout autre système ou site Web personnalisé.


0

Après le nom du fichier dans le code HTML, j'ajoute ?forcedownload=1

Cela a été le moyen le plus simple pour moi de déclencher une boîte de dialogue pour enregistrer ou télécharger.


0

Si vous avez un plugin dans le navigateur qui sait comment ouvrir un fichier PDF, il s'ouvrira directement. Comme dans le cas des images et du contenu HTML.

L'approche alternative consiste donc à ne pas envoyer votre type MIME dans la réponse. De cette façon, le navigateur ne saura jamais quel plugin doit l'ouvrir. Par conséquent, il vous donnera une boîte de dialogue Enregistrer / Ouvrir .


C'est difficile à réaliser car c'est le serveur qui envoie le type mime et lors de la liaison directe à un fichier PDF, vous ne pouvez pas modifier les en-têtes.
Karel Petranek du

0

J'ai juste eu un problème très similaire avec le problème supplémentaire dont j'avais besoin pour créer des liens de téléchargement vers des fichiers dans un fichier ZIP.

J'ai d'abord essayé de créer un fichier temporaire, puis j'ai fourni un lien vers le fichier temporaire, mais j'ai trouvé que certains navigateurs afficheraient simplement le contenu (un fichier Excel CSV) plutôt que de proposer de télécharger. Finalement, j'ai trouvé la solution en utilisant un servlet. Cela fonctionne à la fois sur Tomcat et GlassFish, et je l'ai essayé sur Internet Explorer 10 et Chrome.

Le servlet prend comme entrée un nom de chemin complet vers le fichier ZIP et le nom du fichier à l'intérieur du zip qui doit être téléchargé.

Dans mon fichier JSP, j'ai un tableau affichant tous les fichiers à l'intérieur du zip, avec des liens qui disent: onclick='download?zip=<%=zip%>&csv=<%=csv%>'

Le code du servlet est dans 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;
            }
        }
    }
}

Pour compiler sur Tomcat, vous avez besoin du classpath pour inclure tomcat \ lib \ servlet-api.jar ou sur GlassFish: glassfish \ lib \ j2ee.jar

Mais l'un ou l'autre fonctionnera sur les deux. Vous devez également définir votre servlet dans web.xml.


0

Ajoutez un en-tête de réponse Content-Disposition: attachment; suivi du nom du fichier. Supprimez le méta Content-Disposition; Inline; qui ouvrira le document dans la même fenêtre

En java, il est défini comme

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

-2

Avec de gros fichiers PDF, le navigateur se bloque. Dans Mozilla, menu OutilsOptionsApplications , puis à côté du type de contenu Document Adobe Acrobat. Dans la liste déroulante Action, sélectionnez Toujours demander .

Cela n'a pas fonctionné pour moi, donc ce qui a fonctionné était:

Menu Outils * → Modules complémentairesAdobe Acrobat (plugin Adobe PDF pour Firefox) → DÉSACTIVER. Maintenant, je peux télécharger des livres électroniques!


2
avez-vous lu la question? ce n'est pas une réponse multi-navigateurs
Mark

1
@mark c'est aussi des instructions pour un utilisateur d'inviter des téléchargements forcés de PDF, pas un propriétaire de site Web.
Nathan Hornby
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.