Many times users need to download files from the Web site, if the file can be publicly obtained through a fixed link, then we simply store the file in the directory under Webroot. But in most cases, we need to do permission control, such as downloading a PDF bill, or downloading a file from a Web-disk. At this point, we usually use scripting code to implement, which will undoubtedly increase the burden on the server.
For example, the following code:
<?php
//user identity authentication, if validation fails to jump
authenticate ();
Get files that need to be downloaded, if the file does not exist jump
$file = Determine_file ();
Read the contents of the file
$content =file_get_contents ($file);
Send the appropriate HTTP header header
("Content-type:application/octet-stream");
Header (' Content-disposition:attachment filename= '. basename ($file). '"');
Header ("Content-length:"). FileSize ($file));
Echo $content; or ReadFile ($file);
? >
What's wrong with doing this?
This means that our program needs to cycle the contents of the file from disk through a fixed buffer to read the memory, and then send it to the front-end Web server, the last to reach the user. This approach consumes a lot of memory when you need to download a large file, or even triggers a PHP process to timeout or crash. The Cache is also a headache, not to mention the interruption of the heavy connection.
An ideal solution should be, by the PHP program, such as the right to check the logic of the decision, all through the front of the Web server directly to send the file to the user-like Nginx such as the front desk is better at handling static files. This way, the PHP script will not be blocked by I/O.
Second, what is X-sendfile?
X-sendfile is a mechanism for transferring file download requests from back-end applications to front-end Web server processing, which eliminates the pressure of the backend program to read both the file and the send, thereby significantly improving server efficiency, especially with large file downloads.
X-sendfile is implemented through a specific HTTP header: Specify the address of a file in the X-sendfile header to advertise the front-end Web server. When the Web server detects the header sent by the backend, it ignores the other output from the backend, and sends the file to the user using its own components, including the caching header and the breakpoint reset optimization mechanism.
However, before using x-sendfile, we must understand that this is not a standard feature, and by default it is disabled by most Web servers. The implementation of different Web servers is not the same, including a different X-sendfile header format. If improperly configured, the user may download to a 0-byte file.
Using X-sendfile will allow downloads of files in non-web directories, such as/root/, to be downloaded even if the files are not accessed under. htaccess protection.
Different Web servers implement different HTTP headers
SENDFILE Head |
the WEB device used |
X-sendfile |
Apache, Lighttpd v1.5, Cherokee |
X-lighttpd-send-file |
LIGHTTPD v1.4 |
X-accel-redirect |
Nginx, Cherokee |
The disadvantage of using x-sendfile is that you lose control of the file transfer mechanism. For example, if you want to do something after the file is downloaded, such as allowing the user to download the file only once, this x-sendfile is not possible because the background PHP script does not know if the download was successful.
Third, how to use?
Apache please refer to the Mod_xsendfile module. Let me introduce the usage of Nginx.
Nginx supports this feature by default and does not require additional modules to be loaded. Just to implement some difference, you need to send an HTTP header for X-accel-redirect. In addition, you need to make the following settings in the configuration file
location/protected/{
internal;
Root /some/path;
}
Indicates that the path can only be accessed within Nginx and cannot be accessed directly from the browser to prevent unauthorized downloads.
So PHP sends X-accel-redirect to Nginx:
]<?php
$filePath = '/protected/iso.img ';
Header (' Content-type:application/octet-stream ');
Header (' Content-disposition:attachment filename= '. basename ($file). '"');
Let xsendfile send file
header (' X-accel-redirect: '. $filePath);
? >
This allows the user to download the files under the/some/path/protected/iso.img path.
If you want to send a/some/path/iso.img file, then the Nginx configuration should be
location/protected/{
internal;
Alias /some/path/; # Pay attention to the last slash
}