Downloading large files reliably in PHP

2019-01-02 18:04发布

I have a php script on a server to send files to recipents: they get a unique link and then they can download large files. Sometimes there is a problem with the transfer and the file is corrupted or never finishes. I am wondering if there is a better way to send large files

Code:

$f = fopen(DOWNLOAD_DIR.$database[$_REQUEST['fid']]['filePath'], 'r');
while(!feof($f)){
    print fgets($f, 1024);
}
fclose($f);

I have seen functions such as

http_send_file
http_send_data

But I am not sure if they will work.

What is the best way to solve this problem?

Regards
erwing

标签: php download
13条回答
若你有天会懂
2楼-- · 2019-01-02 18:37

This is tested on files of a size 200+ MB on a server that has 256MB memory limit.

header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename=\"$file_name\"");
set_time_limit(0);
$file = @fopen($filePath, "rb");
while(!feof($file)) {
  print(@fread($file, 1024*8));
  ob_flush();
  flush();
}
查看更多
后来的你喜欢了谁
3楼-- · 2019-01-02 18:38

For downloading files the easiest way I can think of would be to put the file in a temporary location and give them a unique URL that they can download via regular HTTP.

As part generating these links you could also remove files that were more than X hours old.

查看更多
人间绝色
4楼-- · 2019-01-02 18:39

Best solution would be to rely on lighty or apache, but if in PHP, I would use PEAR's HTTP_Download (no need to reinvent the wheel etc.), has some nice features, like:

  • Basic throttling mechanism
  • Ranges (partial downloads and resuming)

See intro/usage docs.

查看更多
何处买醉
5楼-- · 2019-01-02 18:44

If you are sending truly large files and worried about the impact this will have, you could use the x-sendfile header.

From the SOQ using-xsendfile-with-apache-php, an howto blog.adaniels.nl : how-i-php-x-sendfile/

查看更多
高级女魔头
6楼-- · 2019-01-02 18:48

When I have done this in the past I've used this:

set_time_limit(0); //Set the execution time to infinite.
header('Content-Type: application/exe'); //This was for a LARGE exe (680MB) so the content type was application/exe
readfile($fileName); //readfile will stream the file.

These 3 lines of code will do all the work of the download readfile() will stream the entire file specified to the client, and be sure to set an infinite time limit else you may be running out of time before the file is finished streaming.

查看更多
笑指拈花
7楼-- · 2019-01-02 18:49

Create a symbolic link to the actual file and make the download link point at the symbolic link. Then, when the user clicks on the DL link, they'll get a file download from the real file but named from the symbolic link. It takes milliseconds to create the symbolic link and is better than trying to copy the file to a new name and download from there.

For example:

<?php

// validation code here

$realFile = "Hidden_Zip_File.zip";
$id = "UserID1234";

if ($_COOKIE['authvalid'] == "true") {
    $newFile = sprintf("myzipfile_%s.zip", $id); //creates: myzipfile_UserID1234.zip

    system(sprintf('ln -s %s %s', $realFile, $newFile), $retval);

    if ($retval != 0) {
        die("Error getting download file.");
    }

    $dlLink = "/downloads/hiddenfiles/".$newFile;
}

// rest of code

?>

<a href="<?php echo $dlLink; ?>Download File</a>

That's what I did because Go Daddy kills the script from running after 2 minutes 30 seconds or so....this prevents that problem and hides the actual file.

You can then setup a CRON job to delete the symbolic links at regular intervals....

This whole process will then send the file to the browser and it doesn't matter how long it runs since it's not a script.

查看更多
登录 后发表回答