文件下载,在我们的项目中,基本都会用到,记得写过好多次了,但每次写,只有个大概印象,又需要重新找。今天项目中,涉及到了 "多图下载",点击按钮,同时下载多张图片。好好总结下下载,避免以后每次要写了,需要来回找资料!
1.前端下载
我们可以直接通过 <a> 来下载文件
<a href="downloads/test.jpg">下载 .jpg 图片</a>
<a href="downloads/test.pdf">下载 .pdf 文件</a>
<a href="downloads/test.zip">下载 .zip 文件</a>
<a href="downloads/test.exe">下载 .exe 文件</a>
上面 4 种不同类型的文件,.jpg 和 .pdf,会直接通过浏览器打开文件,而 .zip 和 .exe 会直接下载下来。
为什么会出现这种区别?
没怎么了解,应该是浏览器直接能解析,这类型的文件,所以就不会下载!
如何下载浏览器也可以解析的,类似 .jpg 和 .pdf 的文件?
<a> 标签还支持一个 download 属性
1>不传值
<a href="downloads/test.jpg" download>下载 .jpg 图片</a>
2>传值,允许修改文件名
<a href="downloads/test.jpg" download="test1.jpg">下载 .jpg 图片</a>
切记!!!
通过 <a> 链接的方式,来下载文件,必须是 "同源 URL",不可跨域!!!
此外:
还可以使用 href 还可以是:blob:URLs 和 data:URLs,让我们可以下载 javascript 生成的内容(例如:使用 canvas 生成的dataUrl)
/*
var link = document.createElement('a');
link.innerHTML = 'download image';
link.addEventListener('click', function(ev) {
link.href = canvas.toDataURL();
link.download = "mypainting.png";
}, false);
document.body.appendChild(link);
*/
参考文章:
https://www.tutorialrepublic.com/php-tutorial/php-file-download.php
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a
2.后端PHP下载
前端,用户在页面上点击一个 <a>,href 指向到我们的 PHP 处理文件,PHP 文件里通过设置 header 头,然后输出文件内容,从而达到下载的目的
<a href="/download.php?file=test.jpg">下载 .jpg 图片</a>
download.php
<?php
$file = $_GET['file'];
$file = urldecode($_REQUEST["file"]); // Decode URL-encoded string
$filepath = "images/" . $file;
if(file_exists($file)){
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
flush(); // Flush system output buffer
readfile($filepath);
}
参考文章:
https://www.tutorialrepublic.com/php-tutorial/php-file-download.php
PHP 这种下载方式,基本是个通用方法,网上这方面资料太多了,大同小异,只是 header() 头配置略微不同。我们在 PHP 官方文档中,也可以参考:
http://php.net/manual/zh/function.header.php // 搜索 download 关键字
http://php.net/manual/en/function.readfile.php // 搜索 download 关键字
3.点击下载按钮,同时下载多个文件
起先是网上,搜了好多篇,都是说的是将多个文件,打包为 .zip 文件,然后下载!
这尼玛明显不是我想要的啊,可能是我自己的搜索关键字描述有问题!
我是没仔细看,看到了:
1>zip 打包技术
2>还有组装 <iframe></iframe> 嵌套 <form>
3>也有比较合理的方法,和我自己想的一样,接下来描述
比较合理的方法:
既然我们可以使用 <a href="" download> 来下载单个文件,能不能我们通过点击一个按钮,然后让它来触发多个我们要下载的 <a href="" download> 链接?
代码:
<a id="one" href="downloads/test.jpg" style="display: none;">下载 .jpg 图片</a>
<a id="two" href="downloads/test.pdf" style="display: none;">下载 .pdf 文件</a>
<button id="download">下载</button>
<script>
$('#download').click(function(){
$('#one').click();
$('#two').click();
});
</script>
结果,可以完美下载!!
对于 "跨域文件",和之前讲到的方法一样,只要 href 改为 PHP 请求即可:
<a id="one" href="/test/test?file=test.jpg" style="display: none;">下载 .jpg 图片</a>
<a id="two" href="/test/test?file=test.pdf" style="display: none;">下载 .pdf 文件</a>
代码优化:
原理就是这个,过程的话,我们稍微优化下写法:
<button onClick="download(window.downloadFiles)">下载</button>
<script>
var downloadFiles = [
{'link': 'downloads/test.jpg', 'name': 'test1.jpg'},
{'link': 'downloads/test.pdf', 'name': 'test1.pdf'},
{'link': 'downloads/test.zip', 'name': 'test1.zip'},
{'link': 'downloads/test.exe', 'name': 'test1.exe'},
];
function download(files){
var link = document.createElement('a');
link.style.display = 'none';
document.body.appendChild(link);
for(var i = 0; i < files.length; i++){
link.setAttribute('href', files[i].link)
link.setAttribute('download', (files[i].name ? files[i].name : null));
link.click();
}
document.body.removeChild(link);
}
</script>
参考文章:
https://www.cnblogs.com/hustskyking/p/multiple-download-with-javascript.html(貌似很不错!我是写完了,才发现的)
https://segmentfault.com/q/1010000012322615
https://stackoverflow.com/questions/16390601/make-multiple-files-to-force-download
https://stackoverflow.com/questions/1754352/download-multiple-files-as-a-zip-file-using-php
https://stackoverflow.com/questions/18451856/how-can-i-let-a-user-download-multiple-files-when-a-button-is-clicked
https://stackoverflow.com/questions/2339440/download-multiple-files-with-a-single-action/9425731#9425731
4.文件下载时,我们可能需要判断文件是否存在
is_file()
file_exists()
这 2 个函数,都不能检测到 "远程文件" 是否存在
同样的实现方式很多,这里先写上几种:
1>fopen
$url = '';
$handle = @fopen($url, 'r');
if($handle){
// 存在
}else{
// 不存在
}
2>curl
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_NOBODY, true); // 注意:不请求内容,优化
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$res = curl_exec($ch);
if ($res !== false){
// 存在
}else{
// 不存在
}
curl_close($ch);
3>get_headers
$header_response = @get_headers($url, 1);
if ( strpos( $header_response[0], "404" ) !== false ){
// 不存在
}else{
// 存在
}
3个都测试了下,速度差不了多少...