簡體   English   中英

如何通過PHP從URL復制非常大的文件到服務器?

[英]How to copy very large files from URL to server via PHP?

我使用以下代碼將文件從外部服務器(通過 URL 的任何服務器)復制/下載到我托管的 web 服務器(默認設置為 Dreamhost 共享主機)。

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<form method="post" action="copy.php">
    <input type="submit" value="click" name="submit">
</form>
</body>
</html>
<!-- copy.php file contents -->
<?php
function chunked_copy() {
    # 1 meg at a time, adjustable.
    $buffer_size = 1048576; 
    $ret = 0;
    $fin = fopen("http://www.example.com/file.zip", "rb");
    $fout = fopen("file.zip", "w");
    while(!feof($fin)) {
        $ret += fwrite($fout, fread($fin, $buffer_size));
    }
    fclose($fin);
    fclose($fout);
    return $ret; # return number of bytes written
}
if(isset($_POST['submit']))
{
   chunked_copy();
} 
?>

然而,function 大約在下載完 2.5GB(有時是 2.3GB,有時是 2.7GB 等)文件后停止運行。 每次執行此 function 時都會發生這種情況。較小的文件 (<2GB) 很少出現此問題。 我相信源沒有問題,因為我單獨將文件完美地下載到我的家用電腦上。

有人可以解決這個問題並向我解釋嗎? 我對編程很陌生。

還,

file_put_contents("Tmpfile.zip", fopen("http://example.com/file.zip", 'r')); 

也表現出類似的症狀。

我認為問題可能是許多運行PHP腳本的服務器上的30秒超時。

通過cron或shell運行的PHP腳本不會有此問題,因此也許您可以找到一種方法來實現。

或者,您可以將set_time_limit([desired time])添加到代碼的開頭。

也許您可以嘗試curl下載文件。

function downloadUrlToFile($url, $outFileName)
{
    //file_put_contents($xmlFileName, fopen($link, 'r'));
    //copy($link, $xmlFileName); // download xml file

    if(is_file($url)) {
        copy($url, $outFileName); // download xml file
    } else {
        $options = array(
          CURLOPT_FILE    => fopen($outFileName, 'w'),
          CURLOPT_TIMEOUT =>  28800, // set this to 8 hours so we dont timeout on big files
          CURLOPT_URL     => $url
        );

        $ch = curl_init();
        curl_setopt_array($ch, $options);
        curl_exec($ch);
        curl_close($ch);
    }
}

說明:也許。 Remidy:可能不會。

這可能是由於PHP的限制所致: 關於文件大小函數的手冊在返回值部分中提到:

注意:因為PHP的整數類型是帶符號的,並且許多平台使用32位整數,所以某些文件系統函數可能會為大於2GB的文件返回意外結果。

看來, fopen功能可能會引起問題,因為兩點意見( 12 )加入(雖然改裝成向下)關於這個問題。

似乎您需要從源代碼編譯PHP(帶有CFLAGS="-D_FILE_OFFSET_BITS=64"標志)以啟用大文件(> 2GB),但是這可能會破壞其他功能。

由於您使用的是共享的查詢:我想您很走運。

抱歉...

由於問題是在(尚)未知且未定義的文件大小下發生的,因此最好嘗試解決方法。 如果您只是關閉並在一定數量的字節后重新打開輸出文件,該怎么辦?

function chunked_copy() {
    # 1 meg at a time, adjustable.
    $buffer_size = 1048576; 
    # 1 GB write-chuncks
    $write_chuncks = 1073741824;
    $ret = 0;
    $fin = fopen("http://www.example.com/file.zip", "rb");
    $fout = fopen("file.zip", "w");
    $bytes_written = 0;
    while(!feof($fin)) {
        $bytes = fwrite($fout, fread($fin, $buffer_size));
        $ret += $bytes;
        $bytes_written += $bytes;
        if ($bytes_written >= $write_chunks) {
            // (another) chunck of 1GB has been written, close and reopen the stream
            fclose($fout);
            $fout = fopen("file.zip", "a");  // "a" for "append"
            $bytes_written = 0;  // re-start counting
        }
    }
    fclose($fin);
    fclose($fout);
    return $ret; # return number of bytes written
}

重新打開應該使用附加模式,它將在文件末尾放置寫指針(沒有讀指針),而不覆蓋先前寫的字節。

這不會解決任何操作系統級別或文件系統級別的問題,但可以解決寫入文件時PHP內部的任何計數問題。

也許這個技巧也可以(或應該)應用於閱讀端,但是我不確定您是否可以在下載中執行搜索操作。

請注意,任何整數溢出(如果您使用的是32位,則超出2147483647)都應通過強制轉換為float來透明解決,因此這不是問題。

編輯 :計算實際寫入的字節數,而不是塊大小

30秒后您可能會超時,這可能是由PHP引起的(默認情況下max_execution_time = 30s)。 您可以嘗試將其設置為更長的時間:

ini_set('max_execution_time', '300');

但是,有一些警告:

  • 如果腳本在安全模式下運行,則無法使用ini_set設置max_execution_time (我無法找到Dreamhost在共享主機中是打開還是關閉安全模式,您需要詢問它們,或者只是嘗試一下)。

  • Web服務器也可能具有執行限制。 Apache的默認值為300s(也有IIS,但考慮到Dreamhost提供了“完整的unix外殼”,Apache比IIS更有可能)。 但是,如果文件大小為5GB,這應該會對您有所幫助。

這是我找到的下載超大文件的最佳方式:快速且不需要大量 memory。

public function download_large_file(string $url, string $dest)
{
    ini_set('memory_limit', '3000M');
    ini_set('max_execution_time', '0');

    try { 
        $handle1 = fopen($url, 'r');
        $handle2 = fopen($dest, 'w');

        stream_copy_to_stream($handle1, $handle2);

        fclose($handle1);
        fclose($handle2);

        return true;
        } 
    catch(\Exception $e) {
        return $e->getMessage();
        }

    return true;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM