先上代码,看懂的可直接方便复制php
public function download(){ $file_url = $_REQUEST('file_url'); //file_url参数多是个url,也多是文件相对路径 $file = '...对$file_url进行处理找到文件绝对路径'; $file_realname = $_REQUEST('file_realname'); //file_realname参数是js通过encodeURIComponent()函数编码过的,提交以后,nginx通常都自动对url进行urldecode()解码,因此直接接收就OK(若是发现没自动解码,就须要咱们手动urldecode) $file_realname = rawurlencode($file_realname); //由于file_realname要传回浏览器,因此还须要url编码,才能保证不乱吗,且这里应该用rawurlencode()而不是urlencode() if(!file_exists($file)){ echo "<script>alert('文件不存在')</script>"; return; }else{ header("Content-type:application/octet-stream"); header("Content-Disposition:attachment; filename = $file_realname; filename*=utf-8''$file_realname"); header("Accept-ranges:bytes"); header("Accept-length:".filesize($file)); readfile($file); } }
分割线下面是详细原理和过程html
-----------------------------------------------------------------------------------------------------------html5
实现文件上传(文件名为:≈你好;123.rar),且上传后要求马上展现文件名(js插件在选择完文件后默认会马上调用文件上传接口),并能够点击文件名直接进行下载,点击肯定提交保存到数据库。(说明:上传后不能马上刷新页面,由于此时还未点击肯定提交,并且服务器上的文件名已是时间戳编码后的格式1526019720.rar)nginx
1.文件上传数据库
2.上传后文件名展现后端
3.上传后按原文件名直接下载浏览器
4.提交后,再次打开页面时的原文件名展现服务器
5.提交后,再次打开页面时按原文件名下载app
上传的问题好解决,网上的js插件不少,这里用的是Layui函数
因为咱们项目里用的是Layui的文件上传插件,因此展现文件名须要本身处理,该插件中没有对file对象的name属性进行html实体编码,因此若是文件名中有&等特殊字符(若是使用原生的<input type='file'>就不会有这个问题),直接展现会有乱码,所以必须先对文件名file.name进行实体编码(并且file对象是js生成的,没有通过后端php,因此也只能用js对其进行html实体编码),网上找到了js的html编码相关函数:http://www.jb51.net/article/93623.htm,为了方便复制,我直接贴出代码:
function HTMLEncode ( input ) { var converter = document.createElement("DIV"); converter.innerText = input; var output = converter.innerHTML; converter = null; return output; } function HTMLDecode ( input ) { var converter = document.createElement("DIV"); converter.innerHTML = input; var output = converter.innerText; converter = null; return output; }
-----重点来了------
因为服务器上的文件名已变成1526019720.rar,因此要使用url直接下载的话,下载后文件名也会是1526019720.rar,因此只能去请求PHP文件,用PHP设置header的方式改变文件名,并把文件路径和文件名经过参数传给PHP文件(此时还没办法只传个id,经过id查询数据库获取文件路径和文件名,由于尚未提交到数据库!!!),参数传递一种是GET,一种是POST(强烈建议使用POST方式,这样就省去了对url进行编码,若是使用GET方式...大家懂的,下面会讲到使用GET方式)
先讲一下使用php的header方式进行文件下载,通常相似以下这种方式
<?php public function download(){ $file = '....具体的文件路径'; $file_realname = '....具体的文件名'; header("Content-type:application/octet-stream"); header("Content-Disposition:attachment; filename = $file_realname;) header("Accept-ranges:bytes"); header("Accept-length:".filesize($file)); readfile($file); }
可是使用这种写法,会发现若是文件名中有特殊字符(好比;等),则下载后的文件名会显示不正确,由于“;”分号是 header("Content-Disposition:attachment; filename = $file_realname;)的分隔符
通过一番查找,终于找到一篇博客解惑了:https://www.cnblogs.com/hihtml5/p/7220188.html?utm_source=itdadao&utm_medium=referral
最终肯定使用php的自带函数rawurlencode(),并把Content-Disposition:attachment改成:
$file_realname = rawurlencode($file_realname); header("Content-Disposition:attachment; filename = $file_realname; filename*=utf-8''$file_realname");
接下来就是使用GET方式传递文件路径和文件名给这个PHP函数,由于文件名中有“&”符号,url中&是有特殊意义的,因此必须进行url编码(这里只须要对file_realname编码便可,file_url在上传时重命名变成了时间戳格式),并且这里是文件上传后没有刷新页面,直接就能够下载,所以不能用PHP的函数,只能是js端使用encodeURIComponent()进行编码(由于是url局部编码,不能用encodeURI(),参见:http://www.w3school.com.cn/jsref/jsref_encodeURIComponent.asp)
特别说明:以前刚开始写这篇博客的时候,说的是js端用base64编码方式对file_realname编码,后来发现是有瑕疵的,由于base64编码后有可能会产生+等特殊符号,url提交后得到的参数是空格,所以,在这里特别更正一下,仍是要用标准的url局部编码encodeURIComponent()
js生成的下载url大体以下
$('#download').attr('href','www.xxx.com/download?file_url='+res.data.src+'&file_realname='+new Base64().encode($('#file_realname').val()));
通常状况下,nginx等Web服务器都会自动对url解码(不管是get仍是post),因此php端无需手动解码,最终的download函数为:
public function download(){ $file_url = $_REQUEST('file_url'); //file_url参数多是个url,也多是文件相对路径 $file = '...对$file_url进行处理找到文件绝对路径'; $file_realname = $_REQUEST('file_realname'); //file_realname参数是js通过encodeURIComponent()函数编码过的,提交以后,nginx通常都自动对url进行urldecode()解码,因此直接接收就OK(若是发现没自动解码,就须要咱们手动urldecode) $file_realname = rawurlencode($file_realname); //由于file_realname要传回浏览器,因此还须要url编码,才能保证不乱吗,且这里应该用rawurlencode()而不是urlencode() if(!file_exists($file)){ echo "<script>alert('文件不存在')</script>"; return; }else{ header("Content-type:application/octet-stream"); header("Content-Disposition:attachment; filename = $file_realname; filename*=utf-8''$file_realname"); header("Accept-ranges:bytes"); header("Accept-length:".filesize($file)); readfile($file); } }
关于中文乱码,这里强烈建议先后端统一使用UTF8
数据库中我设置了两个字段,file_url和file_realname,这样就能够将文件路径和文件名分开保存,直接将原始文件名存入file_realname,由于是从新打开的页面,因此就可使用php的htmlspecialchars函数进行实体编码了(若是要使用htmlspecialchars过滤单引号和双引号,还需加上第二个参数ENT_QUOTES)
file_realname直接用rawurlencode编码便可
<a style="color:#0b76e8" id="download" href="<?php echo (!empty($file_url)?"www.xxx.com/download?file_url=$file_url&file_realname=".rawurlencode($file_realname):'');?>"><?php echo htmlspecialchars($file_realname);?></a>
终于写完了,文字纯手打+代码复制,若是以为对你有些许帮助,求手抖给个赞
1.js 实体编码
2.php 实体编码(htmlspecialchars)
3.js url编码(encodeURIComponent())
4.php url编码(rawurlencode)
5.本篇最关键的:
$file_realname = rawurlencode($file_realname); header("Content-Disposition:attachment; filename = $file_realname; filename*=utf-8''$file_realname");