如何使用PHP强制下载文件

joh*_*ohn 112 php file download

我想要在用户使用PHP访问网页时下载文件.我认为它与某些事情有关file_get_contents,但我不确定如何执行它.

$url = "http://example.com/go.exe";
Run Code Online (Sandbox Code Playgroud)

下载文件后,header(location)它不会重定向到另一个页面.它就停止了.

Pit*_*ger 215

阅读有关内置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); // do the double-download-dance (dirty but worky)
Run Code Online (Sandbox Code Playgroud)

还要确保根据文件application/zip,application/pdf等添加适当的内容类型 - 但仅当您不想触发另存为对话框时.

  • 为什么需要这个? (6认同)
  • 别忘了冲洗;-) ob_clean(); 冲洗();/*在*/readfile之前($ file_url); (6认同)

Mar*_*era 39

<?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(); 
?>
Run Code Online (Sandbox Code Playgroud)

或者,当文件无法通过浏览器打开时,您只需使用Location标题:

<?php header("Location: http://example.com/go.exe"); ?>
Run Code Online (Sandbox Code Playgroud)

  • 没有 *application/force-download* 媒体类型;使用 *application/octet-stream* 代替。 (2认同)

gen*_*sis 39

header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"file.exe\""); 
echo readfile($url);
Run Code Online (Sandbox Code Playgroud)

是正确的

或更好的一个exe类型的文件

header("Location: $url");
Run Code Online (Sandbox Code Playgroud)

  • 只需删除'readfile()'之前的'echo',因为返回值指定为"返回从文件读取的字节数.如果发生错误,则返回FALSE,除非函数被调用为@readfile(),打印出错误信息." 因此,您最终会得到内容末尾的文件内容+整数. (10认同)

小智 19

首先显示您的文件并将其值设置为url.

的index.php

<a href="download.php?download='.$row['file'].'" title="Download File">
Run Code Online (Sandbox Code Playgroud)

的download.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');
?>
Run Code Online (Sandbox Code Playgroud)

  • 你从哪里得到这个?看起来很强大 (2认同)

Par*_*hal 16

如果您必须下载大小超过允许的内存限制(memory_limitini设置)的文件,这会导致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;
Run Code Online (Sandbox Code Playgroud)


小智 9

对上面接受的答案的修改,它还检测运行时的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)
Run Code Online (Sandbox Code Playgroud)


Sau*_*shi 6

您也可以流式下载,这将消耗更少的资源。例子:

$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();
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,我正在下载 test.zip(实际上是我本地计算机上的 android studio zip)。php://output 是只写流(通常由 echo 或 print 使用)。之后,您只需设置所需的标头并调用stream_copy_to_stream(source,destination)。Stream_copy_to_stream() 方法充当管道,从源流(读取流)获取输入并将其传送到目标流(写入流),它还避免了允许内存耗尽的问题,因此您实际上可以下载更大的文件比你的 PHP memory_limit.


小智 6

我上面的答案有效。但是,我想提供一种如何使用 GET 执行它的方法

在你的 html/php 页面上

$File = 'some/dir/file.jpg';
<a href="<?php echo '../sumdir/download.php?f='.$File; ?>" target="_blank">Download</a>
Run Code Online (Sandbox Code Playgroud)

download.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;
Run Code Online (Sandbox Code Playgroud)

这应该适用于任何文件类型。这没有使用 POST 进行测试,但它可以工作。


علی*_*رضا 5

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

<a href="https://test.com/aaa.exe" download>click here to download</a>
Run Code Online (Sandbox Code Playgroud)