Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Laravel从Web服务器流式传输AmazonS3对象_Laravel_Amazon S3_Laravel 5_Flysystem - Fatal编程技术网

使用Laravel从Web服务器流式传输AmazonS3对象

使用Laravel从Web服务器流式传输AmazonS3对象,laravel,amazon-s3,laravel-5,flysystem,Laravel,Amazon S3,Laravel 5,Flysystem,在我使用Laravel5.1构建的web应用程序中,用户可以上传我存储在AmazonS3中的一些敏感文件。稍后,我希望有权下载此文件的用户。因为我希望这个身份验证检查到位,所以我不能使用传统的方法下载该文件,而是让它们直接链接到S3中的文件 我的做法: 当用户请求下载时,我的服务器会在本地下载文件,然后流式传输给用户问题:需要很长时间,因为有时文件太大 为用户提供一个预签名的URL,以便直接从S3下载。URL仅在5分钟内有效问题:如果该URL是共享的,任何人都可以在5分钟内下载 ,将数据直接从S

在我使用Laravel5.1构建的web应用程序中,用户可以上传我存储在AmazonS3中的一些敏感文件。稍后,我希望有权下载此文件的用户。因为我希望这个身份验证检查到位,所以我不能使用传统的方法下载该文件,而是让它们直接链接到S3中的文件

我的做法:

  • 当用户请求下载时,我的服务器会在本地下载文件,然后流式传输给用户问题:需要很长时间,因为有时文件太大

  • 为用户提供一个预签名的URL,以便直接从S3下载。URL仅在5分钟内有效问题:如果该URL是共享的,任何人都可以在5分钟内下载

  • ,将数据直接从S3流式传输到客户端。这看起来很有希望,但我不知道如何实现

  • 根据本文,我需要:

  • 注册流包装器-这是我的第一个问题,因为我不知道如何获取
    S3Client
    对象,因为laravel使用flysystem,我不知道调用什么方法来获取此对象。也许我需要在composer.json中单独包含S3包
  • 禁用输出缓冲-我需要在laravel中执行此操作,还是laravel已经处理好了

  • 我相信其他开发人员以前也看到过这样的问题,希望得到一些帮助。如果有人已经使用laravel
    Response::download($pathToFile,$name,$headers)
    直接从S3流式传输到客户端,那么我很想听听你的方法。

    通过评论中的讨论,我得出了一些我想分享的要点

    预签名URL

    正如@ceejayoz所指出的,
    预签名
    URL不是一个坏主意,因为:

  • 我可以保持低至10秒的时间,这是任何重定向和开始下载的完美选择,但不足以共享链接
  • 我之前的理解是,下载必须在给定的时间内完成。因此,如果链接在10秒内过期,下载必须在10秒内完成。但@ceejayoz指出情况并非如此。允许已开始的下载完成
  • 使用
    云前端
    ,我还可以限制IP地址,以增加安全性

  • IAM角色

    他还指出了另一个不太好的方法,即创建临时IAM用户。如果没有正确执行,这将是一场维护噩梦,因此只有在您知道自己在做什么的情况下才能执行


    来自S3的流

    这就是我现在选择的方法。也许以后我会转向第一种方法

    警告:如果流式传输,则服务器仍然是中间人,所有数据都将通过服务器传输。所以,如果它失败了,或者速度慢了,你的下载速度就会慢

    我的第一个问题是
    如何注册流包装器

    由于我使用的是Laravel,Laravel使用flysystem进行S3管理,所以我没有简单的方法获得S3客户端。因此,我在我的
    composer.json

    "aws/aws-sdk-php-laravel" : "~3.0"
    
    然后我编写了如下代码:

    class FileDelivery extends Command implements SelfHandling
    {
        private $client;
        private $remoteFile;
        private $bucket;
    
        public function __construct($remoteFile)
        {
            $this->client = AWS::createClient('s3');
            $this->client->registerStreamWrapper();
            $this->bucket = 'mybucket';
            $this->remoteFile = $remoteFile;
        }
    
        public function handle()
        {
            try
            {
                // First get the meta-data of the object.
                $headers = $this->client->headObject(array(
                    'Bucket' => $this->bucket,
                    'Key' => $this->remoteFile
                ));
    
                $headers = $headers['@metadata'];
                if($headers['statusCode'] !== 200)
                {
                    throw new S3Exception();
                }
            }
            catch(S3Exception $e)
            {
                return 404;
            }
    
            // return appropriate headers before the stream starts.
            http_response_code($headers['statusCode']);
            header("Last-Modified: {$headers['headers']['last-modified']}");
            header("ETag: {$headers['headers']['etag']}");
            header("Content-Type: {$headers['headers']['content-type']}");
            header("Content-Length: {$headers['headers']['content-length']}");
            header("Content-Disposition: attachment; filename=\"{$this->filename}\"");
    
            // Since file sizes can be too large,
            // buffers can suffer because they cannot store huge amounts of data.
            // Thus we disable buffering before stream starts.
            // We also flush anything pending in buffer.
            if(ob_get_level())
            {
                ob_end_flush();
            }
            flush();
    
            // Start the stream.
            readfile("s3://{$this->bucket}/{$this->remoteFile}");
        }
    }
    
    我的第二个问题是
    我需要在laravel中禁用输出缓冲吗


    答案是肯定的。缓冲允许数据立即从缓冲区刷新,从而降低内存消耗。由于我们没有使用任何laravel函数将数据卸载到客户端,这不是laravel完成的,因此需要由我们完成。

    不是从S3->user流式传输的,是streams S3->laravel->user。您的服务器仍然处于循环中,因此您会占用带宽,并且错过了直接提供S3的大部分好处。@ceejayoz我理解,但我还有什么选择呢。我不能直接访问S3中的文件。另外,为了让其他人下载,我必须使这些文件公开可见。你可能可以拼凑一些东西来限制签名URL在特定IP上的使用。@ceejayoz谢谢你的链接。但是,如果我的用户被授予IAM角色,他们必须是AWS/Amazon的一部分还是必须登录?只要请求开始,就可以完成。顺便说一句,如果您将CloudFront放在S3前面,那么您的签名URL可以限制为IP地址。请参阅-
    “IpAddress”:{“AWS:SourceIp:“可选IP地址”}
    -这将为您的方案增加一些额外的安全性。