• 让php更快提供文件下载


    一般来说我们可以通过直接让URL指向一个位于Document Root下面的文件来引导用户下载文件.

    但是这样做就没办法做一些统计权限检查等等的工作于是很多时候我们采用让PHP来做转发为用户提供文件下载. 

    1 <?php
    2     $file = "/tmp/dummy.tar.gz";
    3     header("Content-type: application/octet-stream");
    4     header('Content-Disposition: attachment; filename="' . basename($file) . '"');
    5     header("Content-Length: ". filesize($file));
    6     readfile($file);

    但是这个有一个问题就是如果文件是中文名的话有的用户可能下载后的文件名是乱码.

    于是我们做一下修改(参考: :

     1 <?php
     2     $file = "/tmp/中文名.tar.gz";
     3  
     4     $filename = basename($file);
     5  
     6     header("Content-type: application/octet-stream");
     7  
     8     //处理中文文件名
     9     $ua = $_SERVER["HTTP_USER_AGENT"];
    10     $encoded_filename = rawurlencode($filename);
    11     if (preg_match("/MSIE/", $ua)) {
    12      header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
    13     } else if (preg_match("/Firefox/", $ua)) {
    14      header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
    15     } else {
    16      header('Content-Disposition: attachment; filename="' . $filename . '"');
    17     }
    18  
    19     header("Content-Length: ". filesize($file));
    20     readfile($file);

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

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

    那么能不能不经过PHP这层直接让Webserver直接把文件发送给用户呢?

    我们可以使用Apachemodule mod_xsendfileApache直接发送这个文件给用户:

     

     1 <?php
     2     $file = "/tmp/中文名.tar.gz";
     3  
     4     $filename = basename($file);
     5  
     6     header("Content-type: application/octet-stream");
     7  
     8     //处理中文文件名
     9     $ua = $_SERVER["HTTP_USER_AGENT"];
    10     $encoded_filename = rawurlencode($filename);
    11     if (preg_match("/MSIE/", $ua)) {
    12      header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
    13     } else if (preg_match("/Firefox/", $ua)) {
    14      header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
    15     } else {
    16      header('Content-Disposition: attachment; filename="' . $filename . '"');
    17     }
    18  
    19     //让Xsendfile发送文件
    20     header("X-Sendfile: $file");

     

    X-Sendfile头将被Apache处理并且把响应的文件直接发送给Client. 

     

  • 相关阅读:
    【Caffe代码解析】Layer网络层
    Codeforces Round #276 (Div. 2)
    深入一点 让细节帮你和Fragment更熟络
    C-IDE使用指南
    14.11 隔离事务
    【工具类】遍历扫描目录下全部文件并列出
    Cocos2d-x源代码解析(1)——地图模块(1)
    【Android实战】----基于Retrofit实现多图片/文件、图文上传
    RabbitMQ基本使用
    Spring 4 中重定向RedirectAttributes的使用
  • 原文地址:https://www.cnblogs.com/lpfuture/p/2931676.html
Copyright © 2020-2023  润新知