简体   繁体   中英

Serving downloadable files with php

It is common to server downloadable files which are located outside the public folder by PHP:

$fp = fopen($file,"r") ;
header("Content-Type: application/msword");
header('Content-Disposition: attachment; filename="'.$filename.'"');

while (! feof($fp)) {
    $buff = fread($fp,4096);
    echo $buff;
}

I have two questions:

  1. Comparing with static files served by web server (direct file URL); does this method needs more resources (memory and cpu), as PHP needs to read the file and deliver?

  2. How we can display some text on the page? As we defined header , we do not have html output of the php script.

  1. Yes, reading a file with PHP and writing it to a user will use more memory and CPU, of course depending on how big the file is.
  2. Show a page first, and have a button/link on the page that takes the user to the actual download script.

Also I'd suggest using the Content Length Header as well.

header('Content-Length: '. filesize($path));
  1. Slightly more overhead than serving up the file directly, since you're now involving PHP
  2. No, you cannot. If you output a (say) application/msword header, then ANYTHING you output AT ALL will be considered part of the .doc file and cause it to become corrupted. If you want to output some text, you have to do the download in two parts - output a standard HTML page with the text, and include a timed <meta> (or javascript) redirect to forward the user to the actual download url.

1 Since you have to process the file with this script it require more resources than just normal download link. However this is depend on your needs. If you think these files need more security. Let's say only authenticated users can download the file and only the file belongs to him. Then you need to validate those. In such situation you need the code you have put in your question. If your files are open to the public then you can display direct link to the file may be locating them somewhere in public temporarily.

2 I can suggest you two methods to perform this.

Method 1 :

You need javascript support to perform this kind of requirement in handy way. Assume you need to display some HTML on the page where the download is possible. You can create a page with the HTML you want and you can put a download button.

<input type="button" name="cmdDownload" id="cmdDownload" value="Download" onclick="downloadFile('<?php echo $pathToTheFile; ?>');" />

And you can keep hidden iframe to process the download.

<iframe id="downloadFrame" style="display:none"></iframe>

Assume your PHP download page is download.php.

Then you can have a javascript function like this.

<script type="text/javascript">
function downloadFile(filepath) 
{
    var ifrme = document.getElementById("downloadFrame");
    ifrme.src = "download.php?filepath="+filepath;
}
</script>

Method 2:

Other than above method you can use META Refresh as well.

<meta http-equiv="Refresh" content="3;URL=<?php echo $fullHTTPathToYourFile ?>" />

You can have HTML display with this too.

If output buffering is active, serving a file using PHP will consume a lot of memory, and performance will be much worse than in the case of regular files served by apache.

So to add something to the answers already given:

  • when done sending headers, end output buffering using ob_end_flush() , so the file contents will not be cached in memory before starting output
  • readfile() might stream a file from disk to the web more efficiently than your loop

It has been said but cannot be stressed enough: do include the Content-Length header, since it will allow the downloader to measure progress.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM