📜  laravel 从带有进度条的存储中下载文件 - PHP (1)

📅  最后修改于: 2023-12-03 14:43:46.683000             🧑  作者: Mango

Laravel 从带有进度条的存储中下载文件

在 Laravel 开发中,我们经常需要实现文件下载的功能。而有些文件可能会比较大,因此需要考虑到下载进度的显示。在本文中,我们将介绍如何使用 Laravel 和进度条库来实现带有进度条的文件下载功能。

1. 安装进度条库

我们可以使用 Symfony Progress Bar 来实现进度条的功能。由于 Laravel 默认使用 Composer 管理依赖,因此我们可以使用 Composer 来安装进度条库。在 Laravel 项目根目录下运行以下命令:

composer require symfony/console
composer require symfony/progress-bar
2. 下载文件

在下载文件之前,我们需要确保文件存储在服务器上。首先,我们需要为文件创建一个存储路径,可以在 config/filesystems.php 文件中配置:

'disks' => [
    // ...

    'downloads' => [
        'driver' => 'local',
        'root' => public_path('downloads'),
    ],

    // ...
],

在上面的配置中,我们创建了一个名为 downloads 的磁盘,它的驱动类型是本地存储,并指定了文件保存的根目录为 public/downloads。接下来,我们可以将文件保存到该磁盘中:

use Illuminate\Support\Facades\Storage;

$url = 'https://example.com/large_file.zip';

$fileName = 'large_file.zip';

Storage::disk('downloads')->put($fileName, file_get_contents($url));

在上面的代码中,我们使用了 Laravel 的 Storage 门面和 file_get_contents 函数,将文件从远程服务器下载到本地,并保存到我们之前创建的 downloads 磁盘中。

3. 下载带有进度条

现在,我们已经可以下载文件并将其保存到磁盘中了。接下来,我们将添加进度条来显示下载进度。要使用进度条,我们需要在控制台中输出进度条信息,在 Laravel 中我们可以使用 Symfony Console 组件的控制台类来实现。在控制台输出进度条时,我们需要知道下载的文件大小以及已下载的文件大小。我们可以使用 PHP 的 filesize 函数来获取文件大小。

use Symfony\Component\Console\Helper\ProgressBar;

$fileSize = Storage::disk('downloads')->size($fileName);

$progressBar = new ProgressBar($this->output, $fileSize);

$progressBar->start();

$bytesWritten = 0;

Storage::disk('downloads')->getDriver()->readStream($fileName);

while (!feof($stream)) {
    $buffer = fread($stream, 1024);

    $bytesWritten += strlen($buffer);

    $progressBar->setProgress($bytesWritten);
}

$progressBar->finish();

在上面的代码中,我们使用 StoragereadStream 方法来获得一个可以读取文件的流对象,之后我们通过循环读取文件内容,并将已下载的文件大小传递给进度条对象,进度条就可以动态地显示下载的进度情况了。最后,我们需要手动调用 finish 方法结束进度条的显示。

4. 完整代码

下面是完整的代码实现,请仔细阅读并调整其中的路径等参数以适应您的项目:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Symfony\Component\Console\Helper\ProgressBar;

class DownloadFileCommand extends Command
{
    protected $signature = 'download:file {url} {fileName}';

    protected $description = 'Download a file with progress bar.';

    public function handle()
    {
        $url = $this->argument('url');

        $fileName = $this->argument('fileName');

        $fileSize = $this->getFilesize($url);

        $progressBar = new ProgressBar($this->output, $fileSize);

        $progressBar->start();

        $bytesWritten = 0;

        $stream = fopen($url, 'r');

        Storage::disk('downloads')->put($fileName, $stream);

        $stream = Storage::disk('downloads')->getDriver()->readStream($fileName);

        while (!feof($stream)) {
            $buffer = fread($stream, 1024);

            $bytesWritten += strlen($buffer);

            $progressBar->setProgress($bytesWritten);
        }

        $progressBar->finish();

        fclose($stream);

        $this->info(PHP_EOL.'File '.$fileName.' downloaded!');
    }

    protected function getFilesize($url)
    {
        $curl = curl_init($url);

        curl_setopt($curl, CURLOPT_HEADER, true);
        curl_setopt($curl, CURLOPT_NOBODY, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        $header = curl_exec($curl);

        curl_close($curl);

        $size = null;

        preg_match('/Content-Length:\s*(\d+)/i', $header, $matches);

        if (isset($matches[1])) {
            $size = (int) $matches[1];
        }

        return $size;
    }
}
5. 结论

在本文中,我们介绍了如何使用 Laravel 和进度条库来实现带有进度条的文件下载功能。通过实现该功能,我们可以更加详细地了解 Laravel 的文件存储和控制台操作,并且可以为我们的应用程序添加更加友好的体验。