如何使用PHP下载大文件(内存使用率低)

如何使用PHP下载大文件(内存使用率低),php,file,download,Php,File,Download,我必须使用PHP下载大文件(1x MB) 如何下载此文件而不为临时文件浪费内存(RAM) 当我使用 $something=file_get_contents('http://somehost.example/file.zip'); file_put_contents($something,'myfile.zip'); 我需要有足够大的内存来存储那个文件 也许可以用其他方式下载 例如,在部件(例如1024b)中,写入磁盘,然后重复下载另一个部件,直到文件完全下载为止?您可以使用exec()将其转

我必须使用PHP下载大文件(1x MB)

如何下载此文件而不为临时文件浪费内存(RAM)

当我使用

$something=file_get_contents('http://somehost.example/file.zip');
file_put_contents($something,'myfile.zip');
我需要有足够大的内存来存储那个文件

也许可以用其他方式下载


例如,在部件(例如1024b)中,写入磁盘,然后重复下载另一个部件,直到文件完全下载为止?

您可以使用
exec()
将其转换为
wget
,这将导致最低的内存使用率

<?php
 exec("wget -o outputfilename.tar.gz http://pathtofile/file.tar.gz")
?>


您还可以尝试使用
fopen()
fread()
fwrite()
。这样,一次只需将x字节下载到内存中

一次复制一小块文件

/**
 * Copy remote file over HTTP one small chunk at a time.
 *
 * @param $infile The full URL to the remote file
 * @param $outfile The path where to save the file
 */
function copyfile_chunked($infile, $outfile) {
    $chunksize = 10 * (1024 * 1024); // 10 Megs

    /**
     * parse_url breaks a part a URL into it's parts, i.e. host, path,
     * query string, etc.
     */
    $parts = parse_url($infile);
    $i_handle = fsockopen($parts['host'], 80, $errstr, $errcode, 5);
    $o_handle = fopen($outfile, 'wb');

    if ($i_handle == false || $o_handle == false) {
        return false;
    }

    if (!empty($parts['query'])) {
        $parts['path'] .= '?' . $parts['query'];
    }

    /**
     * Send the request to the server for the file
     */
    $request = "GET {$parts['path']} HTTP/1.1\r\n";
    $request .= "Host: {$parts['host']}\r\n";
    $request .= "User-Agent: Mozilla/5.0\r\n";
    $request .= "Keep-Alive: 115\r\n";
    $request .= "Connection: keep-alive\r\n\r\n";
    fwrite($i_handle, $request);

    /**
     * Now read the headers from the remote server. We'll need
     * to get the content length.
     */
    $headers = array();
    while(!feof($i_handle)) {
        $line = fgets($i_handle);
        if ($line == "\r\n") break;
        $headers[] = $line;
    }

    /**
     * Look for the Content-Length header, and get the size
     * of the remote file.
     */
    $length = 0;
    foreach($headers as $header) {
        if (stripos($header, 'Content-Length:') === 0) {
            $length = (int)str_replace('Content-Length: ', '', $header);
            break;
        }
    }

    /**
     * Start reading in the remote file, and writing it to the
     * local file one chunk at a time.
     */
    $cnt = 0;
    while(!feof($i_handle)) {
        $buf = '';
        $buf = fread($i_handle, $chunksize);
        $bytes = fwrite($o_handle, $buf);
        if ($bytes == false) {
            return false;
        }
        $cnt += $bytes;

        /**
         * We're done reading when we've reached the conent length
         */
        if ($cnt >= $length) break;
    }

    fclose($i_handle);
    fclose($o_handle);
    return $cnt;
}
根据需要调整$chunksize变量。这只是经过了温和的测试。由于多种原因,它很容易破裂

用法:

copyfile_chunked('http://somesite.com/somefile.jpg', '/local/path/somefile.jpg');

代码看起来不错,但不可能允许用户以这种方式打开远程文件。也许您使用fsockopen也有类似的代码?如果在PHP中启用了allow\u url\u fopen指令,它应该可以工作。但我将更新我的示例以显示套接字的使用。相当确定您的
$errorcode
$errorstr
fsockopen
中是向后的。可能存在重复的