PHP 如何下载文件
在日常网站开发中,用户点击按钮就能下载文件是很常见的功能——比如下载文档、图片、安装包,很多人可能不知道,这个简单的操作背后,PHP扮演了关键角色。对于新手来说,不用怕复杂的技术术语,咱们用生活化的例子一步步讲明白,PHP到底怎么实现文件下载。
先搞懂最基础的“文件读取”
很多人第一次接触PHP下载功能,其实是从“读取本地文件”开始的。就像你要从书房的书架上拿一本书,得先知道书放在哪、怎么把它拿出来。PHP里也是一样,首先要确定你要下载的文件路径——比如你网站根目录里有个叫“年度总结.pdf”的文件,路径就是./files/年度总结.pdf。

举个简单的例子:如果只是想把文件内容读出来,PHP可以用readfile()函数,就像你把书的内容一页页念出来。代码大概是这样:
`php
// 先指定文件路径
$filePath = './files/年度总结.pdf';
// 检查文件存在,避免出错
if (file_exists($filePath)) {
readfile($filePath);
}
`
但这时候你会发现,浏览器只是把文件内容显示出来,根本没触发下载——就像你站在书架前直接念内容,旁边的人看不到“保存”按钮,自然没法把内容存到自己手里。这时候就需要第二个关键步骤:告诉浏览器“这是要下载的文件,不是网页内容”。
核心:告诉浏览器“这是要下载的文件”
要让浏览器弹出“保存/打开”的提示,就得设置HTTP响应头,相当于给浏览器发个明确的指令:“别把这个文件当网页显示,赶紧让用户下载存起来”。这就好比你把书递给旁边的人,说“这是给你的,请保存好”,而不是“我念给你听”。
常用的响应头有三个,咱们逐个说清楚:
第一个是Content-Type,它告诉浏览器文件的类型,比如PDF是application/pdf,图片JPG是image/jpeg,压缩包是application/zip——就像你告诉对方“这是一本书,不是一张画”。
第二个是Content-Disposition,这是最关键的指令,值设为attachment; filename="你的文件名.后缀",就是明确告诉浏览器“这是附件,请下载保存,文件名就用这个”——相当于你把文件递过去时,直接说“请下载这个叫‘年度总结.pdf’的文件”。
第三个是Content-Length,用来告诉浏览器文件的大小,这样下载进度条才能准确显示进度——就像你告诉对方“这本书有200页,你能看到读了多少”。
把这些指令结合起来,完整的PHP下载代码就出来了。比如下载刚才的PDF:
`php
$filePath = './files/年度总结.pdf';
$fileName = '年度总结.pdf';
// 检查文件是否存在
if (!file_exists($filePath)) {
die('文件不存在');
}
// 获取文件大小
$fileSize = filesize($filePath);
// 设置响应头,触发下载
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . $fileSize);
// 输出文件内容,完成下载
readfile($filePath);
`
处理常见的小问题
实际用的时候,很容易遇到两个小坑,咱们用例子说怎么解决:
第一个是文件名乱码。如果文件名是中文,比如“2024年度工作总结.pdf”,直接写在代码里可能会显示乱码——就像你给对方递书,名字写得模糊不清。这时候可以把文件名转成浏览器能识别的编码,比如header('Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($fileName));,就像把书名写得清晰工整,对方一眼能看懂。
第二个是大文件下载。如果文件是1G的安装包,直接用readfile()可能会卡住,就像你要搬一大箱书,一次搬不动,得分批次。这时候可以用fopen()和fread()分块读取,每次只读一部分,避免服务器内存占用过高。
这样一来,从基础的文件读取到设置响应头,再到解决常见问题,PHP实现文件下载的逻辑就清晰了——本质就是两步:先准备好要下载的文件,再给浏览器发指令让它保存文件。