php 为什么我下载的文件总是损坏或损坏?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10145067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:29:43  来源:igfitidea点击:

Why is my downloaded file is always damaged or corrupted?

phpfiledownload

提问by max

I have a very weird problem with my download script

我的下载脚本有一个非常奇怪的问题

it basically

它基本上

1.gets a file id with "GET" method

2.gets the name and location of that file from database

3.sends it to the client with the headers and readfile

1.使用“GET”方法获取文件ID

2.从数据库中获取该文件的名称和位置

3.将其与标头和读取文件一起发送给客户端

but strangely that file always comes out as corrupted or damaged

但奇怪的是,该文件总是以损坏或损坏的形式出现

like if it's a zip or rar file file size is right and it opens ok

就像它是一个 zip 或 rar 文件文件大小是否正确并且打开正常

but i cant open compressed files inside of it and that's when i get the file damaged error

但我无法打开其中的压缩文件,那是我收到文件损坏错误的时候

which is weird cuz if the code had a problem i shouldn't even be able to open the zip file(or at least i think i shouldn't)

这很奇怪,因为如果代码有问题,我什至不能打开 zip 文件(或者至少我认为我不应该)

another thing is i've printed out the file with it's path right before sending the headers just to be sure everything is ok

另一件事是我在发送标头之前打印出带有路径的文件,以确保一切正常

I've put the file address on the url and download the file , file was ok with no errors

我已经把文件地址放在url上并下载文件,文件没问题,没有错误

so everything is fine before sending the headers

所以在发送标头之前一切都很好

here is my code

这是我的代码

        $file_id = isset($_GET['id']) && (int)$_GET['id'] != 0 ? (int)$_GET['id'] : exit;


        //////// finging file info
        $file = comon::get_all_by_condition('files' , 'id' , $file_id );
        if(!$file) exit;
        foreach($file as $file){
        $location = $file['location'];
        $filename = $file['file_name'];
        }
        /////////////


        $site = comon::get_site_domian();

        $ext = trim(end(explode('.' , $filename )));
        $abslout_path = 'http://'.$site.'/'.$location.'/'.$filename;
        $relative = $location.'/'.$filename;



    ////////////////// content type 
            switch($ext) {
            case 'txt':
                $cType = 'text/plain'; 
            break;              
            case 'pdf':
                $cType = 'application/pdf'; 
            break;

            case 'zip':
                $cType = 'application/zip';
            break;

            case 'doc':
                $cType = 'application/msword';
            break;

            case 'xls':
                $cType = 'application/vnd.ms-excel';
            break;

            case 'ppt':
                $cType = 'application/vnd.ms-powerpoint';
            break;
            case 'gif':
                $cType = 'image/gif';
            break;
            case 'png':
                $cType = 'image/png';
            break;
            case 'jpeg':
            case 'jpg':
                $cType = 'image/jpg';
            break;

            default:
                $cType = 'application/force-download';
            break;
        }
   //////////////// just checking 

   if(!file_exists($relative)){
        echo $relative;
        echo '<br />';
        exit;
        }

    if( !is_readable( $relative ) )
    exit('its not redable');



    if( headers_sent() )
    exit('headers ? already sent !! ');



    header( 'Pragma: public' ); 
    header( 'Expires: 0' );
    header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
    header( 'Cache-Control: private', false ); // required for certain browsers 
    header( 'Content-Description:File Transfer' );
    header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
    header( 'Content-Type:'.$cType);
    header( 'Content-Disposition: attachment; filename="'. basename($filename) . '";' );
    header( 'Content-Transfer-Encoding: binary' );
    header( 'Content-Length: ' . filesize($relative) );
    readfile($abslout_path);
    exit;

I've checked the headers couple times and they are fine(i think) , I've also add every headers known to man just to be sure !

我已经检查了几次标题,它们很好(我认为),我还添加了人类已知的每个标题,只是为了确定!

I'm starting to think maybe it's something other than script like char encoding or folder permission ! or something like that !!

我开始认为它可能不是像字符编码或文件夹权限这样的脚本!或类似的东西 !!

am i missing something ?

我错过了什么吗?

回答by Lawrence Cherone

That seems allot of code just to force-download, here is a nice function I use all the time. It will handle files over 2GB too.

这似乎是为了强制下载而分配的代码,这是我一直使用的一个很好的功能。它也可以处理超过 2GB 的文件。

<?php 
$file_id = (isset($_GET['id']) && (int)$_GET['id'] != 0) ? (int)$_GET['id'] : exit;

/*finding file info*/
$file = comon::get_all_by_condition('files', 'id', $file_id);
$path = $file['location'] . '/' . $file['file_name'];

if (!is_file($path)) {
    echo 'File not found.('.$path.')';
} elseif (is_dir($path)) {
    echo 'Cannot download folder.';
} else {
    send_download($path);
}

return;

//The function with example headers
function send_download($file) {
    $basename = basename($file);
    $length   = sprintf("%u", filesize($file));

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $basename . '"');
    header('Content-Transfer-Encoding: binary');
    header('Connection: Keep-Alive');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . $length);

    set_time_limit(0);
    readfile($file);
}
?>

回答by Altair CA

    if (file_exists($file)) {
set_time_limit(0);
        header('Connection: Keep-Alive');
    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));
            ob_clean();
            flush();
            readfile($file);


}

回答by Ahsanul Kabir

Very nice, helpful also...

非常好,也很有帮助...

but there is a problem in your code -

但是你的代码有问题 -

header('Content-Disposition: attachment;
filename="'.basename($file).'"';

please change it with this following -

请使用以下内容进行更改 -

header('Content-Disposition: attachment;
filename="'.basename($file).'"');

you are forgot to close it.

你忘了关闭它。

回答by Superbiji

Your script may contain NOTICE or WARNING, try disabling error reporting on top of your script:

您的脚本可能包含 NOTICE 或 WARNING,请尝试在脚本之上禁用错误报告:

error_reporting(0);

回答by AamirR

Make sure you do not have any code executed after the last line readfile(FILE_NAME)

确保在最后一行之后没有执行任何代码 readfile(FILE_NAME)

I had to add die();or exit();as the last line, because MVC framework continues to render the view after readfile

我不得不添加die();exit();作为最后一行,因为MVC框架在之后继续渲染视图readfile