【问题标题】:How to stream an large file from S3 to a laravel view如何将大文件从 S3 流式传输到 laravel 视图
【发布时间】:2019-01-08 09:26:16
【问题描述】:

我大部分时间都在工作,但很难完成它。

现在我有一个简单的路线:

Route::get('file/{id}/', 'FileController@fileStream')->name('file');

这个路由连接到 FileController 中的一个动作:

public function fileStream($id){

    $audio = \App\Audio::where('id', $id)->first();

    $client = S3Client::factory([
        'credentials' => [
            'key'    => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
        ],
        'region' => env('S3REGION'),
        'version' => 'latest',
    ]);


    // Register the stream wrapper from an S3Client object
    $client->registerStreamWrapper();

    if ($stream = fopen('s3://[bucket_name]/'. $audio->audio_url, 'r')) {
        while (!feof($stream)) {
            echo fread($stream, 1024);
        }
        fclose($stream);
    }    
}

这适用于浏览器:如果我转到一个 url: /file/1 它会查找正确的文件,然后在一个干净的浏览器窗口中我得到:

然后在我看来,我试图输出如下音频:

   <audio>
      <source src="{{ url('file', ['id' => $section->id]) }}" type="{{ $section->audio_mime_type}}"></audio>
   </audio>

但是没有玩家将输出输出到屏幕上。

TIA

【问题讨论】:

  • 不是答案。一条建议。 PHP 中的 feof 似乎存在错误/问题。为什么不使用 laravel 响应函数? laravel.com/docs/5.6/responses
  • 你使用的是什么版本的 Laravel 和 PHP
  • 使用 L5.6。我会查看回复文档
  • 这将“通过”文件通过您的服务器占用带宽等。生成 S3 签名链接并将其直接提供给客户端不是更容易吗?另外,大文件不会超时吗?

标签: php laravel-5 stream


【解决方案1】:
//Get Url from s3 using 
$fileUrl = \Storage::disk('s3')->url($filePath);
$fileName = 'name_of_file.extension';
//Set headers
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.$fileName);

if (!($stream = fopen($response, 'r'))) {
  throw new \Exception('Could not open stream for reading file: 
   ['.$fileName.']');
}
// Check if the stream has more data to read
while (!feof($stream)) {
  // Read 1024 bytes from the stream
  echo fread($stream, 1024);
}
// Be sure to close the stream resource when you're done with it
fclose($stream);

【讨论】:

    【解决方案2】:

    你应该使用 Laravel 流式响应

    return response()->streamDownload(function () use ($audio) {
        if ($stream = fopen('s3://[bucket_name]/'. $audio->audio_url, 'r')) {
            while (!feof($stream)) {
                echo fread($stream, 1024);
                flush();
            }
            fclose($stream);
        }    
    }, 'file-name.ext');
    

    【讨论】:

      【解决方案3】:

      使用 Laravel/Symfony Response 类。响应响应无法设置正确的标头。

      即使标题设置正确,您仍依赖于控制器操作中的echo,因此您应该在控制器末尾执行exit(0);。请记住,这是相当丑陋的,它会杀死脚本,您应该始终以使用上述Response 类为目标。

      【讨论】:

        猜你喜欢
        • 2023-02-23
        • 2018-06-08
        • 1970-01-01
        • 2018-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-19
        相关资源
        最近更新 更多