zoukankan      html  css  js  c++  java
  • 让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. 

     

  • 相关阅读:
    MVC4中常用的短句及配置归结(部分)
    结合EF5.0讲MVC4(四)将我们的程序改成数据库优先模式
    结合EF5.0讲MVC4(二)为先前程序添加查询及主外键关系
    【译】《Pro ASP.NET MVC4 4th Edition》第二章(一)
    XtraReport应用(1)(XtraReport From File)
    结合EF5.0讲MVC4(一)创建一个MVC4应用程序
    Scrum实际应用(一)
    结合EF5.0讲MVC4(三)为我们的程序添加过滤器
    C# LINQ详解(一)
    如何在 Windows Server 2008 上打开 SQL Server 防火墙端口
  • 原文地址:https://www.cnblogs.com/lpfuture/p/2931676.html
Copyright © 2011-2022 走看看