文件下载

418 阅读2分钟

文件下载,在我们的项目中,基本都会用到,记得写过好多次了,但每次写,只有个大概印象,又需要重新找。今天项目中,涉及到了 "多图下载",点击按钮,同时下载多张图片。好好总结下下载,避免以后每次要写了,需要来回找资料!

1.前端下载 我们可以直接通过 来下载文件 下载 .jpg 图片 下载 .pdf 文件 下载 .zip 文件 下载 .exe 文件

上面 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下载 前端,用户在页面上点击一个 ,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个都测试了下,速度差不了多少...