之前做项目遇到这样一个问题,就是在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. Unity3D 多人协作开发 环境搭建 笔记(场景合并)

    http://www.cnblogs.com/zhaoqingqing/p/3371120.html 说到多人协作开发,大家都会想到要使用版本控制工具来管理项目,当然最常用的要数SVN和Git了,但是 ...

  2. GameCenter 使用指南

    原地址:http://www.cocoachina.com/gamedev/misc/2010/1022/2229.html GameCenter 为单机游戏为主的 iPhone 游戏平台引入了社会化 ...

  3. vue 1.x 总结

    1.Vuejs组件 vuejs构建组件使用 Vue.component('componentName',{ /*component*/ }): 这里注意一点,组件要先注册再使用,也就是说: Vue.c ...

  4. ML 与 DM 工具 Weka 的使用

    1.关于Weka Weka 的全名是怀卡托智能分析环境(Waikato Environment for Knowledge Analysis),是一款免费的.非商业化(与之对应的是SPSS公司商业数据 ...

  5. 加解密(校验哈希值、MD5值)

    1.计算文本哈希值: public static string ComputeHash(string password) { byte[] buffer = System.Text.Encoding. ...

  6. Python isdecimal() 方法

    描述 Python isdecimal() 方法检查字符串是否只包含十进制字符.这种方法只存在于unicode对象. 注意:定义一个十进制字符串,只需要在字符串前添加 'u' 前缀即可. 语法 isd ...

  7. Java中RunTime类介绍

    Runtime 类代表着Java程序的运行时环境,每个Java程序都有一个Runtime实例,该类会被自动创建,我们可以通过Runtime.getRuntime() 方法来获取当前程序的Runtime ...

  8. Spring Boot中使用Spring-data-jpa

    在实际开发过程中,对数据库的操作无非就“增删改查”.就最为普遍的单表操作而言,除了表和字段不同外,语句都是类似的,开发人员需要写大量类似而枯燥的语句来完成业务逻辑. 为了解决这些大量枯燥的数据操作语句 ...

  9. Atitit.404错误解决标准流程and url汉字中文路径404错误resin4 resin chinese char path 404 err解决

    Atitit.404错误解决标准流程and 错误resin4 resin chinese char path 404 err解决 1. #原因解析 1 2. #解决方式 2 3. 输出图片流... 2 ...

  10. **alon_MM DMA Interface for PCIe使用详解

    在所从事的项目中需要用到PCIE和DMA,经过再三研究,反复查看相关资料,终于弄懂了**alon_MM DMA Interface for PCIe的使用方法. PCIE在fpga和上位机之间起着中间 ...