web-dev-qa-db-ja.com

HTMLでPDFをクリックしてテキストリンクをクリックして[名前を付けて保存]ポップアップを開くよう強制する

私は私のウェブサイトにいくつかの大きいサイズのPDFカタログを持っています、そして私はダウンロードとしてこれらをリンクする必要があります。私がグーグルしたとき、私は下記のようなことを見つけました。リンククリックで "名前を付けて保存..."というポップアップが表示されます。

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

しかし、それは動作しません:/私が以下のようにファイルにリンクするとき、それはファイルにリンクするだけでファイルを開こうとしています。

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

UPDATE(下記の回答による):

私が見たように、これに対して100%信頼できるクロスブラウザソリューションはありません。おそらく最善の方法は、以下にリストされているWebサービスのうちの1つを使用して、ダウンロードリンクを与えることです...

155

答えからリンクをクリックした後のようにブラウザにファイルを保存させる

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

FirefoxとChromeで動作します。

77
DrWaky

メタタグはこの結果を達成するための信頼できる方法ではありません。一般的に、あなたはこれさえするべきではありません - あなたが提供するコンテンツをどうするかを決めるのはユーザー/ユーザーエージェントに任されるべきです。ユーザーは、必要に応じていつでもブラウザにファイルのダウンロードを強制することができます。

それでもブラウザにファイルのダウンロードを強制したい場合は、HTTPヘッダを直接修正してください。これは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

これはHTTPプロトコルの単なる拡張であることに注意してください。とにかく無視するブラウザもあります。

33
Karel Petranek

私はこれと同じ問題を抱えていて、これまでのところうまくいっている解決策を見つけました。 .htaccessファイルに次のコードを入れます。

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

ブラウザに表示されるのではなく強制的にファイルをダウンロードするから来ました。

22
Tony

私はFirefox用の非常に簡単な解決策を見つけました(直接のhrefではなく相対的なものでのみ動作します):type="application/octet-stream"を追加してください:

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

この行をあなたの.htaccessファイルに追加してみてください。

AddType application/octet-stream .pdf

ブラウザに依存しないのでうまくいくことを願っています。

5
Sharad Gautam

単純なWebページのように同じウィンドウでPDFを直接開くブラウザ設定やプラグインがあるため、通常これが起こります。

以下が役に立つかもしれません。私は数年前のPHPでそれを行いました。しかし、現在私はそのプラットフォームに取り組んでいません。

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

上記をdownload.phpとして保存します。

この小さなスニペットをPHPファイルとしてサーバーのどこかに保存すると、直接表示するのではなく、ブラウザでファイルをダウンロードするために使用できます。 PDF以外のファイルを配信したい場合は、5行目を削除または編集してください。

あなたはそのようにそれを使うことができます:

HTMLファイルに次のリンクを追加してください。

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

からの参照: このブログ

5
Ashay

以下のコードを.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

あるいはJavaScriptでトリックすることもできます

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

私はこれを使いましたが、それがすべてのブラウザで機能するかどうかはわかりません。

Firefoxで動作します。

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

ページ上の単一のリンクに対してダウンロードを強制する必要がある場合、これを行うための非常に簡単な方法は、href-linkでHTML5 download-attributeを使用することです。

参照してください: http://davidwalsh.name/download-attribute

これにより、ユーザーがダウンロードするファイルの名前を変更し、同時にダウンロードを強制することができます。

これが良い習慣であるかどうかについての議論がありました、しかし私の場合私はpdfファイルのための埋め込みビューアーを持っていて、ビューアーはダウンロードリンクを提供しないので、私は別々に提供しなければなりません。ここで私はユーザーがウェブブラウザで開かれたpdfを得ないことを確かめたい、それは混乱を招くだろう。

これでダイアログを開く必要はありませんが、リンクはプリセットのダウンロード先に直接ダウンロードされます。そしてもちろん、あなたが他の誰かのためにサイトをやっていて、それらにそれらのリンクに手動で属性を書くことを必要とするならばおそらく悪い考えです、しかし、リンクに属性を入れる方法があれば、これは軽い解決策でありえます。

3
JJxyz

外部ダウンロードサイトを使用したりヘッダを変更することなくこれを達成するための本当に簡単な方法は、単にPDFを含むZipファイルを作成してZipファイルに直接リンクすることです。これは常にSave/Openダイアログを起動します、そしてそれでも.Zipに関連するプログラムが起動されるPDFウィンドウをダブルクリックするのは簡単なことです。

ところで、ほとんどのブラウザに埋め込まれたPDFプラグインは何でも表示するのに時間がかかります(そしてPDFがロードされている間はブラウザがハングすることがよくあります)。 ).

3
Mr. Bungle

"download"属性がすべてのブラウザに実装されるまで、サーバー側のソリューションはより互換性があります。

1つのPythonの例は、ファイルストア用のカスタムHTTPリクエストハンドラです。ファイルストアを指すリンクは、次のように生成されます。

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

これがコードです:

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

HTMLコードのファイル名の後に?forcedownload=1を追加します。

これは、保存またはダウンロードするためのダイアログボックスを表示するための最も簡単な方法です。

0
Bonnie

これは古くからの投稿ですが、ここで私がJavaScriptで解決したのは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>

force-downloadタグ内でクラス<a>を使用するだけで、自動的にダウンロードが強制されます。それを親のdivに追加して、その中のすべてのリンクをピックアップすることもできます。

例:

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

これはWordPressや他のシステムやカスタムWebサイトに最適です。

Zipファイル内のファイルへのダウンロードリンクを作成する必要があるという追加の問題と非常によく似た問題がありました。

最初に一時ファイルを作成し、次に一時ファイルへのリンクを提供しようとしましたが、一部のブラウザではダウンロードするのではなく単に内容(CSV Excelファイル)が表示されることがわかりました。結局、私はサーブレットを使って解決策を見つけました。 TomcatとGlassFishの両方で動作し、私はInternet Explorer 10とChromeでそれを試しました。

サーブレットはZipファイルへのフルパス名とダウンロードするZip内のファイル名を入力として取ります。

私のJSPファイルの中に、Zipの中のすべてのファイルを表示するテーブルがあり、そのリンクにはonclick='download?zip=<%=Zip%>&csv=<%=csv%>'が付いています。

サーブレットコードは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;
            }
        }
    }
}

Tomcat上でコンパイルするには、Tomcat\lib\servlet-api.jarまたはGlassFish上のクラスパスを含める必要があります。glassfish\lib\j2ee.jar

しかしどちらか一方が両方で動作します。サーブレットをweb.xmlに設定する必要もあります。

0
mljm

PDFファイルの開き方を知っているプラ​​グインがブラウザ内にある場合は、直接開きます。画像やHTMLコンテンツの場合と同じです。

そのため、代わりのアプローチはあなたのMIMEタイプをレスポンスで送ることではありません。このようにして、ブラウザはどのプラグインがそれを開くべきかを決して知りません。したがって、Save/Openダイアログボックスが表示されます。

0
sushil bharwani