【问题标题】:PHP only half of file is downloadedPHP只下载了一半文件
【发布时间】:2011-10-07 12:24:44
【问题描述】:

我有一些较大的文件需要与人们共享并让他们更容易(以及开发它的乐趣)我正在开发一个基于浏览器的小型 FTP 客户端。只不过是 PHP 中的standard functions

Yesterday I made a question here about how to download AVI files to the client 和我发现 this function 这样做:

<?php 

/* Tutorial by AwesomePHP.com -> www.AwesomePHP.com */ 
/* Function: download with resume/speed/stream options */ 

/* 
    Parametrs: downloadFile(File Location, File Name, 
    max speed, is streaming   
    If streaming - movies will show as movies, images as images 
    instead of download prompt 
*/ 
     
function downloadFile($fileLocation,$fileName,$maxSpeed = 100,$doStream =
false){ 
    if (connection_status()!=0) return(false); 
    $extension = strtolower(end(explode('.',$fileName))); 

    /* List of File Types */ 
    $fileTypes['swf'] = 'application/x-shockwave-flash'; 
    $fileTypes['pdf'] = 'application/pdf'; 
    $fileTypes['exe'] = 'application/octet-stream'; 
    $fileTypes['zip'] = 'application/zip'; 
    $fileTypes['doc'] = 'application/msword'; 
    $fileTypes['xls'] = 'application/vnd.ms-excel'; 
    $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; 
    $fileTypes['gif'] = 'image/gif'; 
    $fileTypes['png'] = 'image/png'; 
    $fileTypes['jpeg'] = 'image/jpg'; 
    $fileTypes['jpg'] = 'image/jpg'; 
    $fileTypes['rar'] = 'application/rar';     
     
    $fileTypes['ra'] = 'audio/x-pn-realaudio'; 
    $fileTypes['ram'] = 'audio/x-pn-realaudio'; 
    $fileTypes['ogg'] = 'audio/x-pn-realaudio'; 
     
    $fileTypes['wav'] = 'video/x-msvideo'; 
    $fileTypes['wmv'] = 'video/x-msvideo'; 
    $fileTypes['avi'] = 'video/x-msvideo'; 
    $fileTypes['asf'] = 'video/x-msvideo'; 
    $fileTypes['divx'] = 'video/x-msvideo'; 

    $fileTypes['mp3'] = 'audio/mpeg'; 
    $fileTypes['mp4'] = 'audio/mpeg'; 
    $fileTypes['mpeg'] = 'video/mpeg'; 
    $fileTypes['mpg'] = 'video/mpeg'; 
    $fileTypes['mpe'] = 'video/mpeg'; 
    $fileTypes['mov'] = 'video/quicktime'; 
    $fileTypes['swf'] = 'video/quicktime'; 
    $fileTypes['3gp'] = 'video/quicktime'; 
    $fileTypes['m4a'] = 'video/quicktime'; 
    $fileTypes['aac'] = 'video/quicktime'; 
    $fileTypes['m3u'] = 'video/quicktime'; 

    $contentType = $fileTypes[$extension]; 
     
     
    header("Cache-Control: public"); 
    header("Content-Transfer-Encoding: binary\n"); 
    header('Content-Type: $contentType'); 

    $contentDisposition = 'attachment'; 
     
    if($doStream == true){ 
        /* extensions to stream */ 
        $array_listen = array('mp3','m3u','m4a','mid','ogg','ra','ram','wm', 
        'wav','wma','aac','3gp','avi','mov','mp4','mpeg','mpg','swf','wmv','divx','asf'); 
        if(in_array($extension,$array_listen)){  
            $contentDisposition = 'inline'; 
        } 
    } 

    if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { 
        $fileName= preg_replace('/\./', '%2e', $fileName, substr_count($fileName,
'.') - 1); 
        header("Content-Disposition: $contentDisposition;
filename=\"$fileName\""); 
    } else { 
        header("Content-Disposition: $contentDisposition;
filename=\"$fileName\""); 
    } 
     
    header("Accept-Ranges: bytes");    
    $range = 0; 
    $size = filesize($fileLocation); 
     
    if(isset($_SERVER['HTTP_RANGE'])) { 
        list($a, $range)=explode("=",$_SERVER['HTTP_RANGE']); 
        str_replace($range, "-", $range); 
        $size2=$size-1; 
        $new_length=$size-$range; 
        header("HTTP/1.1 206 Partial Content"); 
        header("Content-Length: $new_length"); 
        header("Content-Range: bytes $range$size2/$size"); 
    } else { 
        $size2=$size-1; 
        header("Content-Range: bytes 0-$size2/$size"); 
        header("Content-Length: ".$size); 
    } 
         
    if ($size == 0 ) { die('Zero byte file! Aborting download');} 
    set_magic_quotes_runtime(0);  
    $fp=fopen("$fileLocation","rb"); 
     
    fseek($fp,$range); 
   
    while(!feof($fp) and (connection_status()==0)) 
    { 
        set_time_limit(0); 
        print(fread($fp,1024*$maxSpeed)); 
        flush(); 
        ob_flush(); 
        sleep(1); 
    } 
    fclose($fp); 
            
    return((connection_status()==0) and !connection_aborted()); 
}  

/* Implementation */ 
downloadFile('fileLocation','fileName.ext',900,false); 

?>

现在我的问题是,当下载大文件(大约 800 MB)时,我只得到一半的文件(大约 440 MB),我不知道这是为什么。谁能告诉我我做错了什么,或者有人知道我可以做些什么不同的事情吗?

如前所述,我将this function 与下面的脚本结合使用。

    require_once 'func_downloadFile.php';

    // Get filename
    $filename = explode("/", $_GET['file']);
    $filename = $filename[count($filename)-1];

    $file_path = "downloads/" . $filename;

    if(file_exists($file_path)) {
        downloadFile($file_path, $filename, 900, false);
    }
    else {
        echo "File does not exist.";
    }

首先,文件从我的 NAS 下载到我的网络服务器,然后发送到客户端。如果我使用我的脚本下载到客户端,我只会得到一半的文件,但是如果我将文件从我的 NAS 下载到我的网络服务器,然后通过 FTP 客户端登录到 tmy 网络服务器并下载文件,我会得到整个文件。所以问题是从网络服务器发送到客户端时(这是downloadFile() 所做的)

编辑:我尝试检查 safe_mode 是否在使用 if(ini_get('safe_mode')){ 返回错误。因此我尝试添加以下两行以将超时设置为无限制,但结果是相同的。

ini_set('max_execution_time', 0);
set_time_limit(0);

【问题讨论】:

  • @cularis,听起来可能,但有办法改变吗?据我所知,我将不得不更改 ini 文件中的一些属性,对吧?

标签: php file download client attachment


【解决方案1】:

您是否有可能达到脚本执行时间限制? (默认 30 秒)

你可以编辑你的函数来重置循环中的时间限制...

while(!feof($fp) and (connection_status()==0)) {
    set_time_limit(30); 
    ...
}

你不能在不编辑 php.ini 的情况下将限制设置得更高,但是将它放在循环中会在循环的每次迭代中重置它。

httpd 错误日志中是否有任何条目?

【讨论】:

  • if($doStream == true) { 中使用set_time_limit 不应该工作,因为我没有流式传输文件,这意味着$doStreamfalse
  • 我的错,我的意思是主循环while(!feof($fp) and (connection_status()==0)) {
  • 我不相信您可以在脚本中使用ini_set 使脚本的总时间长于php.ini 中设置的时间。您可以增加 php.ini 中的限制或在脚本执行期间使用set_time_limit 定期重置计时器。每次拨打set_time_limit,都会重置计时器。
  • 恕我直言期刊set_time_limit 是一种更安全的方式。如果您增加 php.ini 中的时间,这意味着您的服务器上进入尾部旋转的每个 php 脚本都将旋转更长的时间。但是,如果您定期重置计时器,您仍然可以避免愚蠢的小错误,即使在同一脚本的其他部分也会导致意外旋转。
  • 这很好。将其设置在循环中而不是更改 php.ini 中的值应该更安全。我刚刚检查了主循环中的脚本,结果发现set_time_limit 已经被0 用作值。所以应该是无限的吧?看来set_time_limit(30) 不会有什么不同。
【解决方案2】:

尝试更改您的超时设置。 该条目名为max_execution_time,您可以在 php.ini 文件中找到它。 标准是 30 秒。 (set_time_limit 在安全模式下不起作用)

【讨论】:

  • 我尝试检查 safe_mode 是否在使用 if(ini_get('safe_mode')){ 并返回 false。因此,我尝试在原始帖子中添加这两行,但结果是一样的。
【解决方案3】:

set_time_limit 将允许您调整脚本的最大执行时间 见http://php.net/manual/en/function.set-time-limit.php

【讨论】:

  • 我尝试检查 safe_mode 是否正在使用 if(ini_get('safe_mode')){ 并返回 false。因此,我尝试在原始帖子中添加这两行,但结果是一样的。
  • 它是否告诉您下载开始时文件大小是多少,我正在使用我的服务器和我拥有的一些随机文件进行尝试。当 DL 启动时,它告诉我下载(在这种情况下)为 350MB,然后下载完整文件(没有超时没有什么)你发送的文件有多大?
  • 文件为 830 MB,下载时显示正确的大小,但在 300-400 MB 之间停止。
  • 它确实在您的原始帖子中说(我应该学会阅读),您的网络服务器正在运行什么(操作系统明智的不是它有什么不同,我只是在耗尽一切)?您的文件如何从 NAS 传输到网络服务器(如果它是即时完成的,那么有可能只有一半的文件到达网络服务器)
  • 我的网络服务器应该运行 Linux。这不是真正的我的网络服务器 - 它只是一个 webhotel。使用ftp_get() 将文件从 NAS 下载到 webhotel。我检查了整个文件是否已传输到 webhotel 并且已经传输。我使用 FTP 客户端登录到我的 webhotel,下载了文件,它就在那里。
猜你喜欢
  • 1970-01-01
  • 2015-06-07
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
  • 2020-09-03
相关资源
最近更新 更多