Serve large file with PHP and nginx X-Accel-Redirect

前端 未结 2 1878
隐瞒了意图╮
隐瞒了意图╮ 2020-12-14 05:18

Hi I want user to be able to download PDF file from my server (Windows) configured with nginx PHP. This is my nginx.conf (server block)

http {
    include            


        
相关标签:
2条回答
  • 2020-12-14 05:37

    Ok - there's a couple of issues here:

    1) Puting root inside of a location is a BAD IDEA according to the nginx developers.

    2) The internal URL used for telling Nginx that this is an internal redirect shouldn't be exposed to users.

    3) I can't see where your download.php file is being served from, so I changed your root location block to use try_files so a request to /download.php would be served by that file rather than index.php.

    Your project should be laid out as:

    project\
        html - this is the root of your website
        protected  - this directory is not accessible directly
    

    And your Nginx conf should look like:

    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile      on;
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  localhost;
    
            root   /path/to/project/html;
    
            location / {
                try_files $uri /index.php?$args;
            }
    
            location /protected_files {
                internal;
                alias /path/to/project/protected;
            }
        }
    }
    

    It's a good idea not to re-use the same names to mean different things as it's quite confusing. I've changed them so that now protected just refers to the actual physical directory that holds the files you want to serve. protected_files is just a string that allows Nginx to match the request from the x-accel header.

    The only thing that needs changing in your PHP code is to use the correct string to allow Nginx to pickup the internal location:

    $aliasedFile = '/download/real-pdf-file.pdf'; //this is the nginx alias of the file path
    $realFile = '/path/to/project/protected/real-pdf-file.pdf'; //this is the physical file path
    $filename = 'user-pdf-file.pdf'; //this is the file name user will get
    header('Cache-Control: public, must-revalidate');
    header('Pragma: no-cache');
    header('Content-Type: application\pdf');
    header('Content-Length: ' .(string)(filesize($realFile)) );
    header('Content-Disposition: attachment; filename='.$filename.'');
    header('Content-Transfer-Encoding: binary');
    header('X-Accel-Redirect: '. $aliasedFile);
    exit(0);
    
    0 讨论(0)
  • 2020-12-14 05:42

    Based from recommendation and solution from Danack and some clarification from Carsten, I found that in Windows Serve, we need to set the full path in the alias like this:

    location /protected_files {
                internal;
                alias C:/absolute/path/to/project/protected/;
            }
    

    Please note that the extra forward slash is needed (in my case, Windows 7 Pro on development, Windows Server 2008 for deployment). The only issue is now I need to test concurrent downloads to see if server resources is hogging.

    I'm new with nginx, since it seem really faster that I switch from Apache. Thanks guy for the enlightenment! I'am glad to be part of Stackoverflow community :)

    0 讨论(0)
提交回复
热议问题