I need to deliver big files like file.zip
(~2 GB) to customers, with a unique URL for each customer. Then I will redirect (with .htaccess
) a customer download link example.com/download/f6zDaq/file.zip
to something like
example.com/download.php?id=f6zDaq&file=file.zip
But as the files are big, I don't want the fact that PHP processes the downloading (instead of just letting Apache handle it) to be a CPU / RAM performance issue for my server. After all, asking PHP to do it involves a new layer, so it might cause such an issue, if not done properly.
Question: among the following solutions, which one(s) are the best practice? (in particular, in terms of CPU/RAM)?
1: PHP solution with application/download
header('Content-Type: application/download');
header('Content-Disposition: attachment; filename=file.zip');
readfile("/path/to/file.zip");
CPU usage measured while downloading: 13.6%.
1bis: PHP solution with application/octet-stream
(coming from Example #1 of this page)
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=file.zip');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('file.zip'));
readfile("/path/to/file.zip");
1ter: PHP solution with application/octet-stream
(coming from here):
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=file.zip');
header('Content-Transfer-Encoding: binary'); // additional line
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); // additional line
header('Pragma: public');
header('Content-Length: ' . filesize('file.zip'));
readfile("/path/to/file.zip");
1quater: Another PHP variant with application/force-download
(edited; coming from here):
header("Content-Disposition: attachment; filename=file.zip");
header("Content-Type: application/force-download");
header("Content-Length: " . filesize($file));
header("Connection: close");
2: Apache solution, no PHP involved: let Apache serve the file, and use .htaccess
to provide different URL for the same file (many ways to do it can be written). In terms of performance, it's similar to let the customer download example.com/file.zip
, served by Apache server.
3: Another PHP solution. This would probably work:
$myfile = file_get_contents("file.zip");
echo $myfile;
but wouldn't this ask PHP to load the whole content in memory? (which would be bad in terms of performance!)
4: Just do a header("Location: /abcd/file.zip");
redirection as explained in File with a short URL downloaded with original filename.
Problem with this solution: this discloses the actual location of the file
example.com/abcd/file.zip
to the end user (who can then use or share this URL without authentification) which is not wanted...
But on the other hand, it is much lighter for the CPU since PHP just redirects the request and doesn't deliver the file itself.
CPU usage measured while downloading: 10.6%.
Note: the readfile doc says:
readfile() will not present any memory issues, even when sending large files, on its own. If you encounter an out of memory error ensure that output buffering is off with ob_get_level().
but I wanted to be 100% sure that it won't be slower / more CPU/RAM hungry than pure Apache solution.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…