如何使 PDF 文件可在 HTML 链接中下载?
Posted
技术标签:
【中文标题】如何使 PDF 文件可在 HTML 链接中下载?【英文标题】:How to make PDF file downloadable in HTML link? 【发布时间】:2010-09-26 18:27:12 【问题描述】:我在我的网页上提供一个 pdf 文件的链接以供下载,如下所示
<a href="myfile.pdf">Download Brochure</a>
问题是当用户点击此链接时
如果用户安装了 Adobe Acrobat,则它会在 Adobe Reader 的同一浏览器窗口中打开文件。 如果未安装 Adobe Acrobat,则会弹出用户下载文件。但我希望它始终弹出给用户下载,无论是否安装了“Adobe acrobat”。
请告诉我该怎么做?
【问题讨论】:
【参考方案1】:这是一个常见问题,但很少有人知道有一个简单的 html 5 解决方案:
<a href="./directory/yourfile.pdf" download="newfilename">Download the pdf</a>
其中newfilename
是用户保存文件的建议文件名。或者,如果您将其留空,它将默认为服务器端的文件名,如下所示:
<a href="./directory/yourfile.pdf" download>Download the pdf</a>
兼容性:我在 Firefox 21 和 Iron 上进行了测试,都运行良好。它可能不适用于不兼容 HTML5 或过时的浏览器。我测试的唯一没有强制下载的浏览器是IE...
在此处检查兼容性:http://caniuse.com/#feat=download
【讨论】:
这是一个简单的解决方案,但不幸的是没有得到广泛的支持,尤其是。不支持 IE caniuse.com/#feat=download 是的,我知道的没错。这就是为什么我有关于兼容性的旁注。根据您的消息来源,IE 和 Safari 都不支持这种方法,或者至少还不支持 :) 无论如何,如果您希望所有浏览器都强制下载,我建议您检查其他一些答案... 与 chrome 版本 39.0.2171.65(64 位)一起工作就像一个魅力! 解决方法很简单,可惜IE和Safari不支持。 说没有访问权限【参考方案2】:不要链接到 .PDF 文件,而是执行类似
的操作<a href="pdf_server.php?file=pdffilename">Download my eBook</a>
它输出一个自定义标题,打开 PDF(二进制安全)并将数据打印到用户的浏览器,然后他们可以选择保存 PDF,尽管他们的浏览器设置。 pdf_server.php 应该如下所示:
header("Content-Type: application/octet-stream");
$file = $_GET["file"] .".pdf";
header("Content-Disposition: attachment; filename=" . urlencode($file));
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush(); // this doesn't really matter.
$fp = fopen($file, "r");
while (!feof($fp))
echo fread($fp, 65536);
flush(); // this is essential for large downloads
fclose($fp);
PS:显然对“文件”变量运行一些健全性检查,以防止人们窃取您的文件,例如不接受文件扩展名、拒绝斜杠、将 .pdf 添加到值中
【讨论】:
我面临另一个问题,我的文件位于 /products/brochure/myfile.pdf 我将 $file 变量作为 $file_path = $_SERVER['DOCUMENT_ROOT'].'/产品/手册/' . $文件;但它将文件下载为“%2Fvar%2Fwww%2Fweb15%2Fweb%2Fproducts%2Fbrochure%2myfile.pdf” @TravisO"Content-type: application/force-download"
未在此处列出:iana.org/assignments/media-types/application 这是一个完全伪造的标题。请不要编标题并发送它们。你能更新你的答案吗?谢谢。
不过,在逐字使用此代码时要小心。这引入了一个严重的 LFI 漏洞,因为您将 GET 变量直接传递到 fopen
。
这段代码在其他方面可能很危险。如果您将 HTTP 链接传递给 fopen,我认为它会从另一台服务器检索文件。攻击者可能会使用它来尝试扫描您的内部网络以查找暴露的 PDF 文件。
更不用说绕过您认为将对“文件”参数执行的任何“健全性检查”是多么容易。路径注入/目录遍历攻击极有可能发生。【参考方案3】:
不要循环遍历每个文件行。 请改用 readfile,它更快。这是关闭 php 网站: http://php.net/manual/en/function.readfile.php
$file = $_GET["file"];
if (file_exists($file))
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Type: application/force-download");
header('Content-Disposition: attachment; filename=' . urlencode(basename($file)));
// header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
确保清理您的 get 变量,因为有人可能会下载一些 php 文件...
【讨论】:
readfile 函数确实更快。我个人建议使用这个答案而不是接受的答案【参考方案4】:不是使用 PHP 脚本来读取和刷新文件,而是使用 .htaccess
重写标题更简洁。这将保留一个“不错”的 URL(myfile.pdf
而不是 download.php?myfile
)。
<FilesMatch "\.pdf$">
ForceType applicaton/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
【讨论】:
这不会让你所有的 PDF 文件都被强制下载吗? @TecBrat 是的,但这就是 OP 的要求。如果您只想限制几个 PDF,请编辑^\.pdf$
正则表达式。
@TecBrat 或仅将 .htaccess 文件放在需要此行为的子文件夹中。【参考方案5】:
我找到了一种使用普通旧 HTML 和 javascript/jQuery 优雅降级的方法。在 IE7-10、Safari、Chrome 和 FF 中测试:
下载链接的HTML:
<p>Thanks for downloading! If your download doesn't start shortly,
<a id="downloadLink" href="...yourpdf.pdf" target="_blank"
type="application/octet-stream" download="yourpdf.pdf">click here</a>.</p>
jQuery(纯 JavaScript 代码会更冗长)模拟在一小段延迟后点击链接:
var delay = 3000;
window.setTimeout(function()$('#downloadLink')[0].click();,delay);
为了使其更加健壮,您可以添加 HTML5 功能检测,如果不存在,则使用 window.open()
打开包含该文件的新窗口。
【讨论】:
【参考方案6】:这是关键:
header("Content-Type: application/octet-stream");
在发送 PDF 文件时发送内容类型 application/x-pdf-document 或 application/pdf。 Adobe Reader 通常会为此 MIME 类型设置处理程序,以便浏览器在收到任何 PDF MIME 类型时将文档传递给 Adobe Reader。
【讨论】:
【参考方案7】:我知道我很晚才回答这个问题,但我发现了一个在 javascript 中执行此操作的技巧。
function downloadFile(src)
var link=document.createElement('a');
document.body.appendChild(link);
link.href= src;
link.download = '';
link.click();
【讨论】:
【参考方案8】:这可以使用 HTML 来实现。
<a href="myfile.pdf">Download Brochure</a>
为其添加下载属性: 这里的文件名是 myfile.pdf
<a href="myfile.pdf" download>Download Brochure</a>
为下载属性指定一个值:
<a href="myfile.pdf" download="Brochure">Download Brochure</a>
这里的文件名是 Brochure.pdf
【讨论】:
对不起,不起作用,它将浏览器的当前URL替换为pdf url【参考方案9】:试试这个:
<a href="pdf_server_with_path.php?file=pdffilename&path=http://myurl.com/mypath/">Download my eBook</a>
pdf_server_with_path.php里面的代码是:
header("Content-Type: application/octet-stream");
$file = $_GET["file"] .".pdf";
$path = $_GET["path"];
$fullfile = $path.$file;
header("Content-Disposition: attachment; filename=" . Urlencode($file));
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . Filesize($fullfile));
flush(); // this doesn't really matter.
$fp = fopen($fullfile, "r");
while (!feof($fp))
echo fread($fp, 65536);
flush(); // this is essential for large downloads
fclose($fp);
【讨论】:
【参考方案10】:这是一种不同的方法。我更喜欢使用 Web 服务器逻辑,而不是依赖浏览器支持或在应用程序层解决这个问题。
如果您使用的是 Apache,并且可以将 .htaccess 文件放在相关目录中,您可以使用下面的代码。当然,你也可以把它放在 httpd.conf 中,如果你可以访问的话。
<FilesMatch "\.(?i:pdf)$">
Header set Content-Disposition attachment
</FilesMatch>
FilesMatch 指令只是一个正则表达式,因此可以根据需要进行精细设置,也可以添加其他扩展。
Header 行与上述 PHP 脚本中的第一行执行相同的操作。如果您还需要设置 Content-Type 行,您可以以相同的方式进行,但我认为没有必要。
【讨论】:
【参考方案11】:我使用 PDF 文件的整个 url 解决了我的问题(而不是将文件名或位置放在 href 中): a href="域.com/pdf/filename.pdf"
【讨论】:
【参考方案12】:如果您需要限制下载速率,请使用此代码!
<?php
$local_file = 'file.zip';
$download_file = 'name.zip';
// set the download rate limit (=> 20,5 kb/s)
$download_rate = 20.5;
if(file_exists($local_file) && is_file($local_file))
header('Cache-control: private');
header('Content-Type: application/octet-stream');
header('Content-Length: '.filesize($local_file));
header('Content-Disposition: filename='.$download_file);
flush();
$file = fopen($local_file, "r");
while(!feof($file))
// send the current file part to the browser
print fread($file, round($download_rate * 1024));
// flush the content to the browser
flush();
// sleep one second
sleep(1);
fclose($file);
else
die('Error: The file '.$local_file.' does not exist!');
?>
更多信息click here
【讨论】:
【参考方案13】:<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>File Uploader</title>
<script src="../Script/angular1.3.8.js"></script>
<script src="../Script/angular-route.js"></script>
<script src="../UserScript/MyApp.js"></script>
<script src="../UserScript/FileUploder.js"></script>
<>
.percent
position: absolute;
width: 300px;
height: 14px;
z-index: 1;
text-align: center;
font-size: 0.8em;
color: white;
.progress-bar
width: 300px;
height: 14px;
border-radius: 10px;
border: 1px solid #CCC;
background-image: -webkit-gradient(linear, left top, left bottom, from(#6666cc), to(#4b4b95));
border-image: initial;
.uploaded
padding: 0;
height: 14px;
border-radius: 10px;
background-image: -webkit-gradient(linear, left top, left bottom, from(#66cc00), to(#4b9500));
border-image: initial;
</>
</head>
<body ng-app="MyApp" ng-controller="FileUploder">
<div>
<table ="width:100%;border:solid;">
<tr>
<td>Select File</td>
<td>
<input type="file" ng-model-instant id="fileToUpload" onchange="angular.element(this).scope().setFiles(this)" />
</td>
</tr>
<tr>
<td>File Size</td>
<td>
<div ng-repeat="file in files.slice(0)">
<span ng-switch="file.size > 1024*1024">
<span ng-switch-when="true">file.size / 1024 / 1024 | number:2 MB</span>
<span ng-switch-default>file.size / 1024 | number:2 kB</span>
</span>
</div>
</td>
</tr>
<tr>
<td>
File Attach Status
</td>
<td>AttachStatus</td>
</tr>
<tr>
<td>
<input type="button" value="Upload" ng-click="fnUpload();" />
</td>
<td>
<input type="button" value="DownLoad" ng-click="fnDownLoad();" />
</td>
</tr>
</table>
</div>
</body>
</html>
【讨论】:
您应该解释您在代码中提供的内容。如果无法详细说明或不需要详细说明,即使是简短的形式。【参考方案14】:在 Ruby on Rails 应用程序中(尤其是使用 Prawn gem 和 Prawnto Rails 插件之类的东西),您可以比完整的脚本(如前面的 PHP 示例)更简单地完成此操作。
在您的控制器中:
def index
respond_to do |format|
format.html # Your HTML view
format.pdf render :layout => false
end
end
render :layout => false 部分告诉浏览器打开“你想下载这个文件吗?”提示而不是尝试呈现 PDF。然后就可以正常链接到文件了:http://mysite.com/myawesomepdf.pdf
【讨论】:
这段代码在哪里写的?哪个控制器,我是 PHP 新手,请解释一下。 @Prashant 这不是 PHP,而是 Ruby on Rails。 @Prashant:如果您需要 PHP 示例,请查看线程后面的示例,但请阅读 cmets 了解它们如何不安全。以上是关于如何使 PDF 文件可在 HTML 链接中下载?的主要内容,如果未能解决你的问题,请参考以下文章