简体   繁体   English

如何使用 PHP 强制下载文件

[英]How to force file download with PHP

I want to require a file to be downloaded upon the user visiting a web page with PHP. I think it has something to do with file_get_contents , but am not sure how to execute it.我想要求在用户访问带有 PHP 的 web 页面时下载一个文件。我认为它与file_get_contents有关,但我不确定如何执行它。

$url = "http://example.com/go.exe";

After downloading a file with header(location) it is not redirecting to another page.下载带有header(location)的文件后,它不会重定向到另一个页面。 It just stops.它只是停止。

Read the docs about built-in PHP function readfile阅读有关内置 PHP 函数readfile的文档

$file_url = 'http://www.myremoteserver.com/file.exe';
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary"); 
header("Content-disposition: attachment; filename=\"" . basename($file_url) . "\""); 
readfile($file_url); 

Also make sure to add proper content type based on your file application/zip, application/pdf etc. - but only if you do not want to trigger the save-as dialog.还要确保根据您的文件应用程序/zip、应用程序/pdf 等添加正确的内容类型 - 但前提是您不想触发另存为对话框。

<?php
$file = "http://example.com/go.exe"; 

header("Content-Description: File Transfer"); 
header("Content-Type: application/octet-stream"); 
header("Content-Disposition: attachment; filename=\"". basename($file) ."\""); 

readfile ($file);
exit(); 
?>

Or, when the file is not openable with the browser, you can just use the Location header:或者,当文件无法用浏览器打开时,您可以只使用Location标头:

<?php header("Location: http://example.com/go.exe"); ?>
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"file.exe\""); 
echo readfile($url);

is correct是正确的

or better one for exe type of files或更好的exe类型文件

header("Location: $url");

Display your file first and set its value into url.首先显示您的文件并将其值设置为 url。

index.php索引.php

<a href="download.php?download='.$row['file'].'" title="Download File">

download.php下载.php

<?php
/*db connectors*/
include('dbconfig.php');

/*function to set your files*/
function output_file($file, $name, $mime_type='')
{
    if(!is_readable($file)) die('File not found or inaccessible!');
    $size = filesize($file);
    $name = rawurldecode($name);
    $known_mime_types=array(
        "htm" => "text/html",
        "exe" => "application/octet-stream",
        "zip" => "application/zip",
        "doc" => "application/msword",
        "jpg" => "image/jpg",
        "php" => "text/plain",
        "xls" => "application/vnd.ms-excel",
        "ppt" => "application/vnd.ms-powerpoint",
        "gif" => "image/gif",
        "pdf" => "application/pdf",
        "txt" => "text/plain",
        "html"=> "text/html",
        "png" => "image/png",
        "jpeg"=> "image/jpg"
    );

    if($mime_type==''){
        $file_extension = strtolower(substr(strrchr($file,"."),1));
        if(array_key_exists($file_extension, $known_mime_types)){
            $mime_type=$known_mime_types[$file_extension];
        } else {
            $mime_type="application/force-download";
        };
    };
    @ob_end_clean();
    if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');
    header('Content-Type: ' . $mime_type);
    header('Content-Disposition: attachment; filename="'.$name.'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    if(isset($_SERVER['HTTP_RANGE']))
    {
        list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
        list($range) = explode(",",$range,2);
        list($range, $range_end) = explode("-", $range);
        $range=intval($range);
        if(!$range_end) {
            $range_end=$size-1;
        } else {
            $range_end=intval($range_end);
        }

        $new_length = $range_end-$range+1;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range-$range_end/$size");
    } else {
        $new_length=$size;
        header("Content-Length: ".$size);
    }

    $chunksize = 1*(1024*1024);
    $bytes_send = 0;
    if ($file = fopen($file, 'r'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

        while(!feof($file) &&
            (!connection_aborted()) &&
            ($bytes_send<$new_length)
        )
        {
            $buffer = fread($file, $chunksize);
            echo($buffer);
            flush();
            $bytes_send += strlen($buffer);
        }
        fclose($file);
    } else
        die('Error - can not open file.');
    die();
}
set_time_limit(0);

/*set your folder*/
$file_path='uploads/'."your file";

/*output must be folder/yourfile*/

output_file($file_path, ''."your file".'', $row['type']);

/*back to index.php while downloading*/
header('Location:index.php');
?>

In case you have to download a file with a size larger than the allowed memory limit ( memory_limit ini setting), which would cause the PHP Fatal error: Allowed memory size of 5242880 bytes exhausted error, you can do this:如果您必须下载大小大于允许的内存限制( memory_limit ini 设置)的文件,这将导致PHP Fatal error: Allowed memory size of 5242880 bytes exhausted错误,您可以这样做:

// File to download.
$file = '/path/to/file';

// Maximum size of chunks (in bytes).
$maxRead = 1 * 1024 * 1024; // 1MB

// Give a nice name to your download.
$fileName = 'download_file.txt';

// Open a file in read mode.
$fh = fopen($file, 'r');

// These headers will force download on browser,
// and set the custom file name for the download, respectively.
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');

// Run this until we have read the whole file.
// feof (eof means "end of file") returns `true` when the handler
// has reached the end of file.
while (!feof($fh)) {
    // Read and output the next chunk.
    echo fread($fh, $maxRead);

    // Flush the output buffer to free memory.
    ob_flush();
}

// Exit to make sure not to output anything else.
exit;

A modification of the accepted answer above, which also detects the MIME type in runtime:上面接受的答案的修改,它也检测运行时的 MIME 类型:

$finfo = finfo_open(FILEINFO_MIME_TYPE);
header('Content-Type: '.finfo_file($finfo, $path));

$finfo = finfo_open(FILEINFO_MIME_ENCODING);
header('Content-Transfer-Encoding: '.finfo_file($finfo, $path)); 

header('Content-disposition: attachment; filename="'.basename($path).'"'); 
readfile($path); // do the double-download-dance (dirty but worky)

The following code is a correct way of implementing a download service in php as explained in the following tutorial以下代码是在 php 中实现下载服务的正确方法,如以下教程中所述

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();
}

try this:尝试这个:

header('Content-type: audio/mp3'); 
header('Content-disposition: attachment; 
filename=“'.$trackname'”');                             
readfile('folder name /'.$trackname);          
exit();

http://php.net/manual/en/function.readfile.php http://php.net/manual/en/function.readfile.php

That's all you need.这就是你所需要的。 "Monkey.gif" change to your file name. “Monkey.gif”更改为您的文件名。 If you need to download from other server, "monkey.gif" change to " http://www.exsample.com/go.exe "如果需要从其他服务器下载,将“monkey.gif”改为“ http://www.exsample.com/go.exe

You can stream download too which will consume significantly less resource.您也可以流式下载,这将消耗更少的资源。 example:例子:

$readableStream = fopen('test.zip', 'rb');
$writableStream = fopen('php://output', 'wb');

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="test.zip"');
stream_copy_to_stream($readableStream, $writableStream);
ob_flush();
flush();

In the above example, I am downloading a test.zip (which was actually the android studio zip on my local machine).在上面的例子中,我正在下载一个 test.zip(它实际上是我本地机器上的 android studio zip)。 php://output is a write-only stream (generally used by echo or print). php://output 是一个只写流(通常由 echo 或 print 使用)。 after that, you just need to set the required headers and call stream_copy_to_stream(source, destination).之后,您只需要设置所需的标头并调用 stream_copy_to_stream(source, destination)。 stream_copy_to_stream() method acts as a pipe which takes the input from the source stream (read stream) and pipes it to the destination stream (write stream) and it also avoid the issue of allowed memory exhausted so you can actually download files that are bigger than your PHP memory_limit . stream_copy_to_stream() 方法充当管道,从源流(读取流)获取输入并将其通过管道传输到目标流(写入流),它还避免了允许内存耗尽的问题,因此您可以实际下载更大的文件比你的 PHP memory_limit

The answers above me works.我上面的答案有效。 But, I'd like to contribute a method on how to perform it using GET但是,我想贡献一种关于如何使用 GET 执行它的方法

on your html/php page在您的 html/php 页面上

$File = 'some/dir/file.jpg';
<a href="<?php echo '../sumdir/download.php?f='.$File; ?>" target="_blank">Download</a>

and download.php containsdownload.php包含

$file = $_GET['f']; 

header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

$ext = pathinfo($file, PATHINFO_EXTENSION);
$basename = pathinfo($file, PATHINFO_BASENAME);

header("Content-type: application/".$ext);
header('Content-length: '.filesize($file));
header("Content-Disposition: attachment; filename=\"$basename\"");
ob_clean(); 
flush();
readfile($file);
exit;

this should work on any file types.这应该适用于任何文件类型。 this is not tested using POST, but it could work.这不是使用 POST 测试的,但它可以工作。

您可以使用下载属性强制下载文件:

 <a href="https://test.com/aaa.exe" download>click here to download</a>

不错,但不适用于受限区域中的文件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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