Sending file to a browser as attachment

2019-04-23 12:33发布

问题:

How to send a file to the browser as attachment if the meant file resides on a 3rd party server (without prior downloading or streaming)?

回答1:

From another server without downloading to your server:

header('Location: http://thirdparty.com/file.ext');

Without downloading the file locally you have no authorization in the external server, so you have to tell the browser what to do, thus the redirect header, it will tell the server to go directly to the url provided, thus loading the download.

From your server you would do:

if (file_exists($file))
{
    if(false !== ($handler = fopen($file, 'r')))
    {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='.basename($file));
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file)); //Remove

        //Send the content in chunks
        while(false !== ($chunk = fread($handler,4096)))
        {
            echo $chunk;
        }
    }
    exit;
}
echo "<h1>Content error</h1><p>The file does not exist!</p>";

Taken from another question I have answered



回答2:

http://php.net/manual/en/function.header.php#example-3655

If you want the user to be prompted to save the data you are sending, such as a generated PDF file, you can use the » Content-Disposition header to supply a recommended filename and force the browser to display the save dialog.

<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>


回答3:

As the others have said, you have to set the Content-disposition header of the response to the file download request. However, you've said the file's on a 3rd party server. Unless you have control over how that server sends out the file, you can't change how the browser retrieves from that server.

You can, however, proxy the file so that your server downloads the file, then passes it on to the client with the appropriate headers. This means you've doubled your bandwidth bill, though, as you're having to both download the file AND upload it at the same time.



回答4:

Just a note for those who face problems on names containing spaces (e.g. "test test.pdf").

In the examples (99% of the time) you can find header('Content-Disposition: attachment; filename='.basename($file));

but the correct way to set the filename is quoting it (double quote): header('Content-Disposition: attachment; filename="'.basename($file).'"' );

Some browsers may work without quotation, but for sure not Firefox and as Mozilla explains, the quotation of the filename in the content-disposition is according to the RFC http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download



回答5:

If you want to provide files that are regularly handled by the browser (images, html, ...), you will have add a header to change the MIME type with something like:

header("Content-Type: application/force-download; name=filename");

If you don't have access to the third party server, you have no choice but to download the file yourself to provide it to the user by adding the header