web-dev-qa-db-fra.com

Force à ouvrir la fenêtre "Enregistrer sous ..." PDF en HTML

J'ai des catalogues PDF de grande taille sur mon site Web et je dois les relier par téléchargement. Quand j'ai googlé, j'ai trouvé une chose telle que notée ci-dessous. Il devrait ouvrir la fenêtre contextuelle "Enregistrer sous ..." en cliquant sur le lien ...

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

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

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

UPDATE (selon les réponses ci-dessous):

À mon avis, il n’existe pas de solution multi-navigateurs fiable à 100%. La meilleure façon consiste probablement à utiliser l'un des services Web énumérés ci-dessous et à donner un lien de téléchargement ...

140

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

<a href="path/to/file" download>Click here to download</a>
227
Ayush Gupta
<a href="file link" download target="_blank">Click here to download</a>

Cela fonctionne pour moi dans Firefox et Chrome.

74
DrWaky

Les balises META ne sont pas un moyen fiable d'atteindre ce résultat. En règle générale, vous ne devriez même pas le faire - cela devrait être laissé à l'utilisateur/à l'agent utilisateur de décider de l'utilisation du 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 l’ignorer de toute façon.

33
Karel Petranek

J'ai eu le 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 fichier .htaccess

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

Il venait de Forcer le téléchargement d'un fichier au lieu de s'afficher dans le navigateur.

20
Tony

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

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

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.

5
Sharad Gautam

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

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

<?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 sous forme de fichier PHP quelque part sur votre serveur. Vous pouvez l'utiliser pour télécharger un fichier dans le navigateur plutôt que de l'afficher directement. Si vous souhaitez servir 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

5
Ashay

Il suffit de mettre le code ci-dessous dans votre fichier .htaccess:

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 aussi faire un tour en JavaScript

element.setAttribute( 'download', whatever_string_you_want);
4
manish1706

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

Un moyen très simple de le faire, si vous devez forcer le téléchargement pour un lien unique sur votre page, consiste à 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 tout en forçant le téléchargement.

Il y a eu un débat sur le point de savoir si c'est une bonne pratique ou non, mais dans mon cas, j'ai un visualiseur intégré pour un fichier pdf et celui-ci n'offre pas de lien de téléchargement, je dois donc le fournir séparément. Ici, je veux m'assurer que l'utilisateur ne voit pas le fichier pdf ouvert dans le navigateur Web, ce qui serait déroutant.

Cela n'ouvrira pas nécessairement la fenêtre Enregistrer sous, mais le lien sera téléchargé directement vers la destination de téléchargement prédéfinie. Et bien sûr, si vous faites un site pour quelqu'un d'autre et que vous avez besoin d'écrire manuellement les attributs de leurs liens 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.

3
Julius

Un moyen simple vraiment d'y parvenir, sans utiliser de sites de téléchargement externes ni de 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. Il est toutefois toujours facile pour les utilisateurs de double-cliquer sur la fenêtre PDF du programme associé à .Zip.

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

3
Mr. Bungle

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

Un exemple de 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 suit:

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
yucer

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
Bonnie

Ceci est un vieux post mais voici celui de ma solution en JavaScript que d'utiliser 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>

Vous devez simplement utiliser la classe force-download dans votre balise <a> et forcer le téléchargement automatiquement. Vous pouvez également l'ajouter au parent div et 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 parfait pour WordPress et tous les autres systèmes ou sites Web personnalisés.

0

Je viens d'avoir un problème très similaire avec le problème ajouté que j'avais besoin de créer des liens de téléchargement vers des fichiers au sein d'un fichier Zip.

J'ai d'abord essayé de créer un fichier temporaire, puis de fournir un lien vers le fichier temporaire, mais j'ai constaté que certains navigateurs afficheraient simplement le contenu (un fichier CSV Excel) plutôt que de proposer le téléchargement. 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 en entrée un nom de chemin complet vers le fichier Zip, ainsi que le nom du fichier dans le fichier Zip à télécharger.

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

Le code de 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, le chemin d'accès aux classes doit inclure Tomcat\lib\servlet-api.jar ou GlassFish: glassfish\lib\j2ee.jar.

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

0
mljm

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 n’est donc pas d’envoyer votre type MIME dans la réponse. De cette façon, le navigateur ne saura jamais quel plugin devrait l'ouvrir. Par conséquent, il vous donnera une boîte de dialogue Enregistrer/Ouvrir .

0
sushil bharwani