您现在的位置是:烟消火灭网 > 知识
php 服务器下载
烟消火灭网2026-10-17 07:40:42【知识】9人已围观
简介 php 服务器下载 凌晨两点,我盯着屏幕上那个转圈的进度条,第无数次诅咒PHP的下载功能。客户要的是50MB的压缩包,服务器跑的是共享主机,内存限制死死卡在128MB——readfile()刚执行到
php 服务器下载
凌晨两点,下载我盯着屏幕上那个转圈的下载进度条,第无数次诅咒PHP的下载下载功能。客户要的下载是50MB的压缩包,服务器跑的下载是共享主机,内存限制死死卡在128MB——readfile()刚执行到一半,下载PHP直接白屏,下载连个错误提示都不给。下载这破事我遇过不下十回,下载每次都得靠分段读取来救场。下载
PHP做下载,下载最坑人的下载地方在于它默认把整个文件塞进内存。小文件没事,下载一上GB就原形毕露。下载你写个readfile($file),下载看起来挺美,实际上PHP先得把文件内容全读进缓冲区,再一股脑吐给客户端。服务器内存不够?直接崩给你看。共享主机尤其惨,连个调memory_limit的权限都不给,你只能干瞪眼。
后来我学乖了,改用fopen()+fpassthru()的组合。这俩函数配合起来,像用吸管喝珍珠奶茶——一次吸一口,不噎着。代码长这样:
header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.basename($file).'"'); header('Content-Length: '.filesize($file)); $fp = fopen($file, 'rb'); fpassthru($fp); fclose($fp); 看着简单,但有个致命细节——你得在fpassthru()之前把ob_clean()和flush()都调一遍。否则PHP输出缓冲区里残留的HTML或者空格,会污染下载文件。我第一次没注意,客户下载的ZIP文件打开全是乱码,还以为是压缩包坏了,排查了半天才发现是模板里多了一个换行符。那感觉,就像你精心打包的快递,封箱前被人塞了张废纸。
还有个坑是文件名编码。中文文件名在IE里显示正常,到了Chrome就变成一串百分号。后来我统一用rawurlencode()处理,再拼上RFC 5987的filename*参数,才算彻底解决。代码长这样:
$filename = '项目报告.zip'; header('Content-Disposition: attachment; filename="'.rawurlencode($filename).'"; filename*=UTF-8\'\''.rawurlencode($filename)); 这段代码救了我好几次。上个月给一个政府项目做系统,他们的文件服务器在Windows上,文件名全是中文。要不是提前处理了编码,光下载这环节就能被验收方打回三次。
说到断点续传,PHP原生支持起来非常麻烦。HTTP_RANGE头你得自己解析,fseek()定位文件指针,还得处理304状态码。我见过有人用X-Sendfile模块,但那玩意儿Apache和Nginx配置不一样,共享主机基本没戏。如果你用的是Nginx,倒是可以试试X-Accel-Redirect,让Nginx直接接管文件传输,PHP只负责验证权限和拼URL。这招能把大文件下载的服务器负载降一个量级,但前提是你有权限改Nginx配置——反正我常驻的那些虚拟主机,没一个让碰的。
最后说个邪门但实用的技巧。有一次客户要下载的文件在OSS上,本地服务器只有个外链。我直接header('Location: '.$signedUrl)跳转,完事。PHP都没碰文件内容,服务器内存占用为零。虽然这不算真正的“服务器下载”,但业务上用户感知不到区别。有时候,解决问题比坚持技术纯洁性更重要。
所以你看,PHP做下载这事,说难也难,说简单也简单。关键是你得清楚自己服务器的底细——内存多大、是否允许改配置、Nginx还是Apache。摸清了这些,再配合分段读取和正确的头信息,基本就能应付九成场景。剩下那一成,要么是你运气不好遇到奇葩环境,要么是该考虑换Go或者Node.js写下载接口了。但在这之前,先把fpassthru()用熟,比啥都强。
很赞哦!(67)
上一篇: 网站存在
下一篇: 土方渗透系数多少方检测一组合适







