之前做项目遇到这样一个问题,就是在php环境下,用a标签的href链接到一个资源,比如是mp3或者lrc文件时,点击之后不是出现保存文件的提示,而是调用本地程序打开文件或者直接在浏览器上解析。网上说可以全部做成rar格式的文件,这个一方面不方便,有些情况下也不可能完全这样做,还有实际上,做过测试会发现,在content-type:text/html的情况下,即时是rar有时也会被浏览器直接解析,无法实现下载的功能,那这个问题是不是就无解了呢?答案是否定的,几番搜索+测试,终于发现了一个可行的解决方案,就是在点击a标签的链接之后,不是直接请求资源,而是对header做一下预处理,再去readfile就可以了。下面附上相关的测试代码:

一、

index.php中:

<?php
echo "<a href='process.php?filename=halo.mp3'>下载</a>"
?>

process.php中:

<?php
header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="'. basename($_GET['filename']).'"'); header("Content-Length: ". filesize($_GET['filename'])); readfile($_GET['filename']);
?>

这是最简单的方法,但是有个问题:如果请求的路径中包含中文,那么下载的文件名有可能就是乱码。

二、

针对上面问题的解决方案,

index.php中:

<?php
echo "<a href='process.php?filename=halo光环.mp3'>下载</a>"
?>

process.php中:

<?php
header("Content-type: application/octet-stream"); //处理中文文件名 $ua = $_SERVER["HTTP_USER_AGENT"]; $encoded_filename = urlencode($_GET['filename']); $encoded_filename = str_replace("+", "%20", $encoded_filename); if (preg_match("/MSIE/", $ua)) { header('Content-Disposition: attachment; filename="' . $encoded_filename . '"'); } else if (preg_match("/Firefox/", $ua)) { header("Content-Disposition: attachment; filename*=\"utf8''" . $_GET['filename'] . '"'); } else { header('Content-Disposition: attachment; filename="' . $_GET['filename'] . '"'); } header("Content-Length: ". filesize($_GET['filename'])); readfile($_GET['filename']);
?>

输出的时候,如果是Apache+PHP,那么还需要发送到Apache的输出缓冲区,最后才发送给用户。而对于Nginx+fpm,如果它们分开部署的话,那还会带来额外的网络IO。

三、

现在貌似没有问题了,但是readfile还是有问题的,虽然PHP的readfile尝试实现的尽量高效,不占用PHP本身的内存,但是实际上它还是需要采用MMAP(如果支持),或者是一个固定的buffer去循环读取文件,直接输出。

那么能不能绕过PHP这层呢,直接由webserver把文件发送给用户呢?可以的,我们可以使用Apache的module mode_xsendfile,让Apache直接发送这个文件给用户。

代码实现如下:(process.php)

header("Content-type: application/octet-stream");

//处理中文文件名

$ua = $_SERVER["HTTP_USER_AGENT"];

$encoded_filename = urlencode($_GET['filename']);

$encoded_filename = str_replace("+", "%20", $encoded_filename);

if (preg_match("/MSIE/", $ua)) {

header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');

} else if (preg_match("/Firefox/", $ua)) {

header("Content-Disposition: attachment; filename*=\"utf8''" . $_GET['filename'] . '"');

} else {

header('Content-Disposition: attachment; filename="' . $_GET['filename'] . '"');

}

//让Xsendfile发送文件
header("X-Sendfile: $_GET['filename']");

最后,如果愿意的话,可以先判断后缀,因为有时候图片当成文件下载也会引起一些不方便的:

 $type = strrchr($_GET['filename'], "."); //获取后缀
if($type == "jpg" || "png" || "gif"){
header("Content-Disposition: filename=$_GET['filename']"); //这里我试过,加引号的话,下载时会加到文件名中
header("Content-Type: image/$type");
}

转自:http://m.blog.csdn.net/blog/nkliming/8536311

php -- PHP实现点击a标签的href做链接时,直接保存文件(任何类型),而不是通过浏览器直接打开下载的文件的更多相关文章

  1. 微信下载app需要点击右上角在浏览器中打开下载的问题

    很多朋友是不是遇到过这样的问题,自家的app通过微信推广没办法直接下载,而是需要通过一个遮罩层来提示用户下载. 点击下载按钮提示点击右上角在浏览器中打开 这样的方式下载一个app是不是需要点击下载按钮 ...

  2. 阻止点击<a>标签链接跳转

      我们常用的在a标签中有点击事件(<a href="地址">链接</a>),其中“href”参数只要不为空,点击该链接时,页面会自动跳转:如果指定的“hr ...

  3. 移动端页面点击a标签会有半透明的阴影或红色边框的bug

    好久没有更新了,今天来一发 ^_^ 最近在写移动端页面,测试时发现一个a标签的bug:无论是iOS端还是Android端都存在,当点击a标签,会有一个矩形的透明的阴影闪一下(不同的浏览器阴影的颜色还不 ...

  4. 点击a标签,跳转到iframe中,并在iframe中显示指定的页面

    点击a标签,跳转到iframe中,并在iframe中显示指定的页面 1.用a标签的target属性 <iframe id="myFrameId" name="myF ...

  5. 鼠标模拟点击a标签

    今天写程序遇到的,想要用鼠标模拟点击a标签 html代码如下: <a id="jump"></a> js代码如下: var page = ....; $(' ...

  6. ie8下jquery读取当前点击的标签位置错误,原因是里面有内容写了text-indent:-9999px

    今天写一地图的效果,鼠标点击对应的区域,弹出所点击区域的名字. 因为设计的区域名字有特殊效果,所以,在点击区域里面套了个标签写上区域名字用来识别,但是这个文字呢不同显示在页面上,所以就给 em 加个了 ...

  7. 对Ul下的li标签执行点击事件——如何获取你所点击的标签

    问题所来:做项目时,一般的数据都是用循环动态加载出来的,结构都是一样的,只是绑定的值不同,如何对相同的标签做处理的问题就来了. 例如:点谁就显示谁的数值 <ul > <li id=& ...

  8. 使用JS或jQuery模拟鼠标点击a标签事件代码

    原文 使用JS或jQuery模拟鼠标点击a标签事件代码 这篇文章主要介绍了使用JS或jQuery模拟鼠标点击a标签事件代码,需要的朋友可以参考下 <a id="alink" ...

  9. 微信浏览器返回刷新,监听微信浏览器返回事件,网页防复制,移动端禁止图片长按和vivo手机点击img标签放大图片

    以下代码都经过iphone7,华为MT7 ,谷歌浏览器,微信开发者工具,PC端微信验证.如有bug,还请在评论区留言. demo链接:https://pan.baidu.com/s/1c35mbjM ...

随机推荐

  1. OpenJudge百炼习题解答(C++)--题4010:2011

    题: 总时间限制:  1000ms  内存限制:  65536kB 描写叙述 已知长度最大为200位的正整数n.请求出2011^n的后四位. 输入 第一行为一个正整数k,代表有k组数据,k<=2 ...

  2. ACM 刷题错误总结 持续更新并持续回想中o(╯□╰)o

    一.段错误/RE 1.& 变量取地址 2.数组越界 3.爆栈, 非常可能是死循环,ruturn的边界没有处理好,或者是递归的内容里有死循环的部分. 4.线段树 逢写必错,都是build(i*2 ...

  3. Generator [ˈdʒenəreɪtə(r)] 函数结构

    Generator函数是ES6新增的一种异步编程方案. 说明:Generator函数指的是一种新的语法结构,是一个遍历器对象生成器,它内部可以封装多个状态,非常适合用于异步操作. Generator函 ...

  4. [Done]com.aerospike.client.AerospikeException: Error Code 12: Bin type error

    今天遇到了一个问题:com.aerospike.client.AerospikeException: Error Code 12: Bin type error 异常栈: 网上找了一些资料:https ...

  5. vmware-Binary translation is incompatible with long mode on this platform

    解决方法:Binary translation is incompatible with long mode on this platform. Disabling long mode. Withou ...

  6. 真正的PHP多线程(绝非fork或者用http再开进程)

    转载:http://blog.csdn.net/leinchu/article/details/8012640 我写了一个扩展打算放到pecl,但是,进过交流发现有人已经做了两个php的多线程扩展 1 ...

  7. js解决跨站点脚本编制问题

    1.前台处理(容易绕过): <script type="text/javascript"> $(document).ready(function(){ var url= ...

  8. Linux更改Apache网站目录出错:Document root must be a directory解决

    Linux更改Apache网站目录出错:Document root must be a directory解决   修改   DocumentRoot     <Directory " ...

  9. [Jobdu] 题目1373:整数中1出现的次数(从1到n整数中1出现的次数)

    题目描述: 亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他.问题是:求出1~13的整数中1出现的次数,并算出100~130 ...

  10. jquery判断元素的子元素是否存在

    jquery判断元素的子元素是否存在的示例代码. jquery判断子元素是否存在 一.判断子元素是否存在 //一级子元素 if($("#specialId>img").len ...