Laravel S3 检索视频以流式传输

2024-05-20

我通过 Laravel 应用程序将视频存储到 Amazon S3。效果很好。但我无法“流式传输”它们。

这是例如 URL:https://website.com/video/342.qt?api_token=a5a18c9f-f5f6-5d66-85e3-aaaaaaa https://website.com/video/342.qt?api_token=a5a18c9f-f5f6-5d66-85e3-aaaaaaa,应该从 S3 返回这部电影“212.DdsqoK1PlL.qt”

It returns this output when calling the URL: Output of Video URL That's the video, but I was expecting it to run directly in the browser, like this video does: https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4

该路由调用此函数,从 S3 磁盘检索非公开文件:

public function document(Document $document)
{
    return Storage::disk('s3')->get($document->path);
}

有效的示例 URL 与我的示例 URL 之间的唯一区别是,示例是 MP4 和我的 .QT,但我也尝试了 MP4,并在浏览器中进行相同的输出;所以没有自动播放视频。

我猜直接播放的电影是流媒体视频?...

我的网站在 Ubuntu 上运行并且也安装了sudo apt-get install vlc.


我个人反对重定向到 S3 URL 的想法。我通过 Laravel php 包装服务器端屏蔽所有 URL。如果其他人遇到类似问题,这是我用来执行此操作的代码。此代码是为使用 Laravel 5.6 从 S3 流式传输视频而编写的(并且包括 HTTP_RANGE 支持,因此它也适用于 iOS)。

我使用下面的类,放置在 App/Http/Responses 中。要使用此类,请创建一个执行此操作的方法(这类似于 getFile 方法):

$filestream = new \App\Http\Responses\S3FileStream('file_path_and_name_within_bucket', 'disk_bucket_name', 'output_file_name_when_downloaded');
return $filestream->output();

运气好的话,您应该可以立即进行流式传输(无需泄露 S3 URL)!

S3FileStream.php:

namespace Http\Responses;

use Exception;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Http\Response;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Storage;
use Symfony\Component\HttpFoundation\StreamedResponse;

class S3FileStream
{
    /**
     * @var \League\Flysystem\AwsS3v3\AwsS3Adapter
     */
    private $adapter;

    /**
     * Name of adapter
     *
     * @var string
     */
    private $adapterName;

    /**
     * Storage disk
     *
     * @var FilesystemAdapter
     */
    private $disk;

    /**
     * @var int file end byte
     */
    private $end;

    /**
     * @var string
     */
    private $filePath;

    /**
     * Human-known filename
     *
     * @var string|null
     */
    private $humanName;

    /**
     * @var bool storing if request is a range (or a full file)
     */
    private $isRange = false;

    /**
     * @var int|null length of bytes requested
     */
    private $length = null;

    /**
     * @var array
     */
    private $returnHeaders = [];

    /**
     * @var int file size
     */
    private $size;

    /**
     * @var int start byte
     */
    private $start;

    /**
     * S3FileStream constructor.
     * @param string $filePath
     * @param string $adapter
     * @param string $humanName
     */
    public function __construct(string $filePath, string $adapter = 's3', ?string $humanName = null)
    {
        $this->filePath    = $filePath;
        $this->adapterName = $adapter;
        $this->disk        = Storage::disk($this->adapterName);
        $this->adapter     = $this->disk->getAdapter();
        $this->humanName   = $humanName;
        //Set to zero until setHeadersAndStream is called
        $this->start = 0;
        $this->size  = 0;
        $this->end   = 0;
    }

    /**
     * Output file to client.
     */
    public function output()
    {
        return $this->setHeadersAndStream();
    }

    /**
     * Output headers to client.
     * @return Response|StreamedResponse
     */
    protected function setHeadersAndStream()
    {
        if (!$this->disk->exists($this->filePath)) {
            report(new Exception('S3 File Not Found in S3FileStream - ' . $this->adapterName . ' - ' . $this->disk->path($this->filePath)));
            return response('File Not Found', 404);
        }

        $this->start   = 0;
        $this->size    = $this->disk->size($this->filePath);
        $this->end     = $this->size - 1;
        $this->length  = $this->size;
        $this->isRange = false;

        //Set headers
        $this->returnHeaders = [
            'Last-Modified'       => $this->disk->lastModified($this->filePath),
            'Accept-Ranges'       => 'bytes',
            'Content-Type'        => $this->disk->mimeType($this->filePath),
            'Content-Disposition' => 'inline; filename=' . ($this->humanName ?? basename($this->filePath) . '.' . Arr::last(explode('.', $this->filePath))),
            'Content-Length'      => $this->length,
        ];

        //Handle ranges here
        if (!is_null(request()->server('HTTP_RANGE'))) {
            $cStart = $this->start;
            $cEnd   = $this->end;

            $range = Str::after(request()->server('HTTP_RANGE'), '=');
            if (strpos($range, ',') !== false) {
                return response('416 Requested Range Not Satisfiable', 416, [
                    'Content-Range' => 'bytes */' . $this->size,
                ]);
            }
            if (substr($range, 0, 1) == '-') {
                $cStart = $this->size - intval(substr($range, 1)) - 1;
            } else {
                $range  = explode('-', $range);
                $cStart = intval($range[0]);

                $cEnd = (isset($range[1]) && is_numeric($range[1])) ? intval($range[1]) : $cEnd;
            }

            $cEnd = min($cEnd, $this->size - 1);
            if ($cStart > $cEnd || $cStart > $this->size - 1) {
                return response('416 Requested Range Not Satisfiable', 416, [
                    'Content-Range' => 'bytes */' . $this->size,
                ]);
            }

            $this->start                           = intval($cStart);
            $this->end                             = intval($cEnd);
            $this->length                          = min($this->end - $this->start + 1, $this->size);
            $this->returnHeaders['Content-Length'] = $this->length;
            $this->returnHeaders['Content-Range']  = 'bytes ' . $this->start . '-' . $this->end . '/' . $this->size;
            $this->isRange                         = true;
        }

        return $this->stream();
    }

    /**
     * Stream file to client.
     * @throws Exception
     * @return StreamedResponse
     */
    protected function stream(): StreamedResponse
    {
        $this->adapter->getClient()->registerStreamWrapper();
        // Create a stream context to allow seeking
        $context = stream_context_create([
            's3' => [
                'seekable' => true,
            ],
        ]);
        // Open a stream in read-only mode
        if (!($stream = fopen("s3://{$this->adapter->getBucket()}/{$this->filePath}", 'rb', false, $context))) {
            throw new Exception('Could not open stream for reading export [' . $this->filePath . ']');
        }
        if (isset($this->start) && $this->start > 0) {
            fseek($stream, $this->start, SEEK_SET);
        }

        $remainingBytes = $this->length ?? $this->size;
        $chunkSize      = 100;

        $video = response()->stream(
            function () use ($stream, $remainingBytes, $chunkSize) {
                while (!feof($stream) && $remainingBytes > 0) {
                    $toGrab = min($chunkSize, $remainingBytes);
                    echo fread($stream, $toGrab);
                    $remainingBytes -= $toGrab;
                    flush();
                }
                fclose($stream);
            },
            ($this->isRange ? 206 : 200),
            $this->returnHeaders
        );

        return $video;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Laravel S3 检索视频以流式传输 的相关文章

  • Laravel 5.4 合并两个集合

    所以我有两个收藏 sales and costs 现在我需要将它们合并为我的一个集合foreach状况 我不确定是否可以在一个集合中使用两个集合foreach 原始查询 Raw MySQL Queries for Sales total s
  • 使用 asp.net MVC 拖放上传到 aws s3

    我在我正在处理的基本 mvc 项目上上传文件时遇到一些问题 我有一个拖 放功能 我想连接到 aws s3 我可以使用当前应用程序将文件放入本地文件夹中 并按照此处的步骤操作 gt 使用 c Sharp 将文件上传到亚马逊 s3 非常简单 h
  • 仅针对 Laravel 中的生产添加自定义 500 错误页面

    我想要一个自定义 500 错误页面 这可以简单地通过创建一个视图来完成errors 500 blade php 这对于生产模式来说很好 但在调试模式下我不再获得默认的异常 调试页面 看起来是灰色的 并显示 哎呀出了问题 因此 我的问题是 如
  • Laravel 集合包含

    我正在使用 Laravelcontains集合上的方法https laravel com docs 5 3 collections method contains https laravel com docs 5 3 collections
  • 在 Laravel 上将百万行数据从一个数据库复制到另一个数据库

    使用 Laravel Eloquent 我从旧 Mysql 数据库的一张表中复制 700 万行数据 并将这些行放在新 Mysql 数据库的不同表中 问题是 执行此操作花费了几乎一天的时间 并且我需要对近 80M 行重新执行此操作 我一次使用
  • Laravel 5 清除视图缓存

    我注意到 Laravel 缓存视图存储在 storage framework views 随着时间的推移 他们会吃掉我的空间 我该如何删除它们 有什么命令可以吗 我试过php artisan cache clear 但它并没有清除视图缓存
  • Laravel 模型访问器从缓存中获取 - 性能增强

    我在数据库中有一个项目列表 每个项目都可以选择被否决或赞成 这些投票与其他项目字段一起存储在 MySql 中 例如这样的事情 Schema create items function table table gt increments id
  • 在 Laravel 中获取身份验证用户 ID

    如果用户登录 Laravel 5 1 我们可以访问用户 ID Auth user gt id 在我以前的应用程序 不是 laravel 中 当用户登录时 我正在为 userid 注册一个会话 我正在检查 SESSION user id 是否
  • Eloquent 准备查询但不执行

    我有一个 客户 表 我正在尝试使用 Laravel Eloquent 使用客户的 id 获取记录 Customer where customer id customer id gt get 然而 当执行此操作时 我检查 MySQL 日志并得
  • “stream_socket_enable_crypto():对等证书 CN=`gains.nanosupercloud.com' 与共享托管中预期的 CN=`smtp.sendgrid.net' 不匹配”

    我在 laravel 从事邮件工作 我有以下配置 MAIL DRIVER smtp MAIL HOST smtp sendgrid net MAIL PORT 587 MAIL USERNAME MAIL PASSWORD MAIL ENC
  • Laravel 自定义授权

    我在这里进行登录验证 LoginData Input except array token if Auth attempt LoginData return success 我的表不同 所以这里我更改表名称auth php table gt
  • Laravel 5.3 如何在通知电子邮件中显示用户名

    我正在尝试在通知电子邮件中添加用户的名字 目前 Laravel 通知电子邮件的开头如下 Hello 我想将其更改为 Hello Donald 现在 我有这样的设置 此示例适用于密码重置通知电子邮件 用户型号 public function
  • AWSS3GetObjectRequest ifModifiedSince 不起作用

    建设为iOS 7 建立在Xcode 6 1 使用亚马逊SDKAWSiOSSDKv2 2 0 12 测试于iPhone 5s 和 iPad 2 我正在使用适用于 iOS 的 Amazon SDK 从我的 Amazon S3 存储桶下载图像 下
  • 如何在通过 Laravel Eloquent 方法连接的元素上使用 orderby

    问题是查询无法找到应该与 Laravel Eloquent 中的方法WITH 连接的特定方法 特定方法 特定模型 特定模型 特定方法等 有什么想法如何解决吗 我的代码 SpecificModel
  • Laravel Mongo 多对多关系在哪里不起作用

    我有两个以多对多关系相互关联的 mongo 文档 一个称为律师 另一个称为律师 我的律师模型有 public function cases return this gt belongsToMany App LawCase 我的 LawCas
  • node npm run watch 退出状态 3221225725

    我必须格式化我的驱动器 但我的一个项目不再工作 所有其他相同类型的项目都运行良好 这是 Laravel Vue JS 问题是我无法运行 npm run watch dev 或 production 他们都给出了错误 拉拉维尔 5 7 npm
  • 特定文件夹的 .htaccess 例外

    这是我的 htaccess 代码 位于根文件夹中
  • Laravel 集合到数组

    我有两个模型 Post and Comment 许多评论属于一个帖子 我正在尝试以数组形式访问与帖子相关的所有评论 我有以下内容 它提供了一个集合 comments collection post gt comments gt get 我该
  • Laravel 5 Auth 注销不起作用

    当我使用内置身份验证并尝试在以下位置注销用户时 auth logout 它没有像希望的那样工作 它似乎让用户保持登录状态 但是当我清除浏览器缓存时 我可以看到实际上已经将用户注销了 我在页面上没有收到任何错误 在日志文件中也没有收到任何错误
  • Angular2 + Laravel 与实时和 WebSockets

    我构建了一个应用程序 并计划与 Angular 2 和 laravel 进行实时战斗 例如 你按下 攻击 按钮 你的对手就会实时看到他的生命在下降 我的应用程序构建有 前端 角2 Backend PHP Laravel 5 2 现在我正在寻

随机推荐

  • 在网格中查找具有相同值的相邻单元格。想法如何改进这个功能?

    我是 Python 新手 学习了 1 个多月 我尝试创建 Tic Tac Toe 然而 一旦我完成了它 我决定扩展棋盘 从 3x3 到 9x9 具体取决于客户的输入 并通过在棋盘上的任意位置连接 4 个行 列或对角线来获胜 因此 我需要一个
  • VBA 架构技巧 - 宏封装

    我拼凑了 Excel 的概念证明 以从数据库获取数据 并需要将其打包 以便可以将其分发给我们的客户 我的第一次尝试只是将所有代码放入代码模块中 但随后在 Excel 中我可以看到宏列表中的所有模块 而我实际上只想要列表中的主要模块 我猜想我
  • 具有多个实体查找器的通用 spring jpa 存储库

    我的应用程序有超过 250 个表 每个表都有 ID 和名称列 我正在尝试将我们的应用程序从 hibernate 3 迁移到带有 hibernate 5 的 Spring JPA 4 3 在我当前的休眠层中 我有 选项 1 public cl
  • C++ 静态初始化顺序失败

    我目前正在学习C 但遇到了一些麻烦 我开发了一个程序 使用了很多 define 但我想用static const相反 碰撞 类型 范围 所以 我现在有类似的东西 file1 hpp class A public static const s
  • 设置浏览器窗口最小化的最小尺寸限制?

    有没有办法在所有浏览器中手动设置浏览器窗口的最小尺寸 你可以试试 body min width 600px 一旦视口小于 600 像素 您将得到一个水平滚动条 这仅适用于支持 min width CSS 属性的现代浏览器 我认为不可能限制用
  • Linux 上哪个版本的 C++ 库符合“ISO C++ 11”标准?

    目前我的计算机上有 Debian Squeeze AMD64 linux libstdc 5 和 libstdc 6 这些 C 库符合 ISO 标准 C 11 吗 不 它们并不完全符合 但它们有一些元素 stdlibc 上的 C 11 支持
  • 使用 JavaScript 将时间戳 UTC 转换为 IST

    我正在寻找一种合适的方法 使用 JavaScript DateTimeStamp 20160108120040 将时间戳从 UTC 转换为 IST 时间戳来自我的正文请求中的 XML 首先 看一下JavaScript 日期格式 http w
  • 我们可以从 LinkPresentation 框架中的 LPLinkView 中提取图像吗?

    我想在我的应用程序中呈现丰富的链接 并将这些数据发送到我的服务器 我需要访问视图内的图像LPLinkView https developer apple com documentation linkpresentation lplinkvi
  • 如何动态地将 sliderInput 添加到闪亮的应用程序中?

    使用闪亮 我上传一个 csv 文件 并根据列名称 我需要向 ui 添加滑块 sidebarPanel fileInput file1 Upload CSV File to Create a Model accept c text csv t
  • 迭代 NSOrderedSet

    我正在尝试迭代 NSOrderedSet 的实例 像这样的事情 func myFunc var orderedSet NSOrderedSet array 42 43 44 for n in orderedSet NSLog i n 但是
  • 应用内结算切换活动

    啊 应用内结算问题永无止境 我一切正常 可以显示应用内购买的交易页面 如果我完成购买 它会返回到我的应用程序 大约 10 秒后它会验证购买 我会收到该商品 另一方面 如果我在返回应用程序后按后退按钮并切换到另一个活动 它永远不会处理事务 即
  • C++ 概念与 Haskell 类型类有何不同?

    Concepts TS 中的 C 概念最近已合并到 GCC 主干中 概念允许人们通过要求类型满足概念的条件 例如 可比较 来约束通用代码 Haskell 有类型类 我对 Haskell 不太熟悉 概念和类型类如何相关 概念 由概念 TS 定
  • MongoDb 注册类映射

    我有以下代码 我希望 MiscellaneousData 覆盖抽象的 MiscellaneousDataBase 然而 IdMemberMap 总是出现空值 使用独立的 正常 类是可行的 if BsonClassMap IsClassMap
  • 下载Xcode? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我刚刚升级到 OS X Mavericks 我很高兴能够使用所有新的 Mavericks 技术 我只有
  • 应用程序图标不显示在操作栏上

    我按照构建新 Android 项目的说明进行操作 除了操作栏出现问题外 我得到了一个可运行的项目 问题是应用程序图标未显示在操作栏上的应用程序标题旁边 我使用以下配置创建了项目 最低要求 SDK API 8 Android 2 2 Froy
  • 使用 su 和 Expect 脚本登录用户时遇到问题

    我正在为一个班级制作一个网站 您可以使用用户名和密码登录 然后它会将您带到一个显示您在班级中的成绩的页面 该网站正在运行bash脚本 https github com jduga002 rapache 并将托管在用户已有用户名和密码登录的计
  • 如何保护 Chrome 扩展

    Chrome 扩展程序被打包为 zip 存档 设置完成后 它将安装在文件夹中 用户可以访问它 他还可以重写扩展 甚至克隆到新的扩展 如何保护扩展免受用户修改和克隆 我发现了 dll 文件的可能性 可以编译 但它不是很好 如果您有一些专有代码
  • Powershell - 在不安装 Excel 的情况下将 CSV 转换为 XLS

    我有一台自动生成报告的服务器 报告采用 CSV 格式 我需要能够直接加密文件 无需第三方压缩 无 WinZIP 或 WinRAR 我认为最好的想法是将 CSV 转换为 XLS 然后通过 Powershell 密码保护 XLS 文件 不幸的是
  • JSF 2.1 中的 HTML 4 <按钮>

    我想使用以下命令 The JSF
  • Laravel S3 检索视频以流式传输

    我通过 Laravel 应用程序将视频存储到 Amazon S3 效果很好 但我无法 流式传输 它们 这是例如 URL https website com video 342 qt api token a5a18c9f f5f6 5d66