在网页上,如果要通过php实现下载功能,我们可以在超链接里访问这个php,然后由php返回下载的文件。
php端主要是通过设置header来实现,基础的示例如下:
$filename = "test.gif"; header("Content-Type:imge/gif"); //发送指定文件MIME类型的头信息 header("Content-Disposition:attachment; filename=".$filename); //发送描述文件的头信息,附件和文件名 header("Content-Length:".filesize($filename)); //发送指定文件大小的信息,单位字节 readfile($filename); //将文件内容读取出来并直接输出,以便下载
如果遇到文件名里有中文,则有点麻烦,用上面的代码的话可能有的浏览器下载后,文件名是乱码。这里要在Content-Disposition:attachment里设置文件名时加以处理。具体代码如下:
//生成支持中文的filename,兼容IE11 $ua = $_SERVER["HTTP_USER_AGENT"]; $encoded_filename = urlencode($filename); $encoded_filename = str_replace("+", "%20", $encoded_filename); if(preg_match("/MSIE/", $ua) || preg_match("/Trident\/7.0/", $ua)){ header('Content-Disposition: attachment; filename="' . $encoded_filename . '"'); } else if (preg_match("/Firefox/", $ua)) { header('Content-Disposition: attachment; filename*="utf8\'\'' . $filename . '"'); } else { header('Content-Disposition: attachment; filename="' . $filename . '"'); }
参考来源:PHP下载文件名中文乱码解决方法
上面文章里还提到了向浏览器流式输出内容。主要是把Content-Type设置为流式:
header('Content-Type: application/octet-stream');
之后当然也没有读取本地文件的过程,而是直接输出内容。例子里是输出了一个字符串,实际上也可以直接输出包含有文件内容的变量。比如我最近做的ikanman下载器里的一部分:
// 获取图片 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_REFERER, "http://www.ikanman.com"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); $cexecute = curl_exec($ch); curl_close($ch); // 设置header header('Content-Type: image/webp'); header('Content-Disposition: attachment; filename="' . $filename . '"'); Header("Accept-Ranges: bytes"); header('Content-Length:'.strlen($cexecute)); // 输出图片 echo $cexecute;
远程获取一个图片,然后把图片直接发送给浏览器。这样也是可以的。
注意:这种方式没有先把文件存到服务器,而是直接输出到浏览器,这种情况下比较推荐模拟a标签点击来发送请求,用ajax的话可能获取的是乱码内容,也不会引发下载。
上面说了php如何向浏览器发送文件来下载,下面说下浏览器里怎么向php发送下载文件的请求,并成功实现下载。
这里有一个我栽过的坑,就是用ajax发起下载请求。这是不行的,因为ajax接收的数据只会是纯字符串形式,就算php成功发送过来一个文件,这个文件也只会以字符串形式保存在ajax的返回内容里,而不会引起浏览器的下载。
用img标签的src也不行,接收到的文件会被解析为一个损坏的图片(因为文件内容不是图片url的形式),也不会引起浏览器的下载。
那么我们可以用那些方式让浏览器发起文件下载呢?
比较简单的是创建一个a标签,设置其href为php的链接。点击这个超链接就可以下载图片了(或者js模拟鼠标点击),很方便。
此外我们还可以构建一个form,将form的action地址设置为php的链接,然后提交这个form,一样可以进行下载。
不太推荐的是创建一个iframe,然后将其src设置为php的链接,设置之后会马上发起请求,下载图片。在不刷新页面又要下载多个文件时,尽量避免使用iframe。