【问题标题】:PHP - Safe way to download large files?PHP - 下载大文件的安全方式?
【发布时间】:2013-06-06 18:02:19
【问题描述】:

信息

在 PHP 中有多种下载文件的方法,file_get_contents + file_put_contentsfopenreadfile 和 cURL。

问题?

  • 当有一个大文件时,比方说从另一个服务器/域有 500 MB,安全下载它的“正确”方法是什么?如果连接失败,它应该找到位置并继续,或者如果文件包含错误,请重新下载。
  • 它将在网站上使用,而不是在 php.exe shell 中。

到目前为止我发现了什么

  • 我已阅读有关带有进度条的 AJAX 解决方案,但我真正想要的是 PHP 解决方案。
  • 我不需要像 file_get_contents 那样将文件缓冲到字符串中。这可能也会使用内存。
  • 我还阅读了有关内存问题的信息。可能首选不使用那么多内存的解决方案。

概念

如果结果为假,这就是我想要的。

function download_url( $url, $filename ) {
    // Code
    $success['success'] = false;
    $success['message'] = 'File not found';
    return $success;
}

【问题讨论】:

  • 我个人使用 cURL 取得了不错的效果,您是从远程位置下载,还是从与您的脚本相同的服务器下载?
  • 我也总是使用 cURL。我知道其他人,但考虑到 cURL 扩展的功能集,使用它们似乎总是很愚蠢。 Aslo 在处理 http 请求的上下文中执行此下载操作,还是从命令行调用或以其他方式在进程中产生的东西?
  • 另外,还有很多其他SOanswersforthis
  • @FDL 来自另一个服务器/域。
  • @prodigitalson 它将用于网站(后端)。我现在用这个信息更新了我的问题。

标签: php curl download fopen file-get-contents


【解决方案1】:

复制大文件的最简单方法可以在这里演示Save large files from php stdin,但没有显示如何复制具有 http 范围的文件

$url = "http://REMOTE_FILE";
$local = __DIR__ . "/test.dat";

try {
    $download = new Downloader($url);
    $download->start($local); // Start Download Process
} catch (Exception $e) {
    printf("Copied %d bytes\n", $pos = $download->getPos());
}

当出现异常时,您可以恢复最后一点的文件下载

$download->setPos($pos);

使用的类

class Downloader {
    private $url;
    private $length = 8192;
    private $pos = 0;
    private $timeout = 60;

    public function __construct($url) {
        $this->url = $url;
    }

    public function setLength($length) {
        $this->length = $length;
    }

    public function setTimeout($timeout) {
        $this->timeout = $timeout;
    }

    public function setPos($pos) {
        $this->pos = $pos;
    }

    public function getPos() {
        return $this->pos;
    }

    public function start($local) {
        $part = $this->getPart("0-1");

        // Check partial Support
        if ($part && strlen($part) === 2) {
            // Split data with curl
            $this->runPartial($local);
        } else {
            // Use stream copy
            $this->runNormal($local);
        }
    }

    private function runNormal($local) {
        $in = fopen($this->url, "r");
        $out = fopen($local, 'w');
        $pos = ftell($in);
        while(($pos = ftell($in)) <= $this->pos) {
            $n = ($pos + $this->length) > $this->length ? $this->length : $this->pos;
            fread($in, $n);
        }
        $this->pos = stream_copy_to_stream($in, $out);
        return $this->pos;
    }

    private function runPartial($local) {
        $i = $this->pos;
        $fp = fopen($local, 'w');
        fseek($fp, $this->pos);
        while(true) {
            $data = $this->getPart(sprintf("%d-%d", $i, ($i + $this->length)));

            $i += strlen($data);
            fwrite($fp, $data);

            $this->pos = $i;
            if ($data === - 1)
                throw new Exception("File Corupted");

            if (! $data)
                break;
        }

        fclose($fp);
    }

    private function getPart($range) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->url);
        curl_setopt($ch, CURLOPT_RANGE, $range);
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
        $result = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // Request not Satisfiable
        if ($code == 416)
            return false;

            // Check 206 Partial Content
        if ($code != 206)
            return - 1;

        return $result;
    }
}

【讨论】:

  • 我无法使用您的下载器下载以下文件biart7.com/dh_demo.zip。我收到“文件损坏”异常。
  • 很可能您的服务器不支持范围
  • 这种方法有效.. 但它很慢。 $length 是做什么的?反正有没有超级加速这个?我正在使用共享服务器。它有大约 1GB 内存
【解决方案2】:

您希望分块下载远程文件。这个答案有一个很好的例子:

How download big file using PHP (low memory usage)

【讨论】:

  • 这应该是一个评论和/或作为重复投票结束。
  • 你能详细说明为什么总是要分块下载吗?
猜你喜欢
  • 2022-08-03
  • 2012-06-18
  • 2013-11-14
  • 1970-01-01
  • 2020-04-08
  • 2019-03-13
  • 2012-06-05
  • 1970-01-01
相关资源
最近更新 更多