Laravel保护亚马逊s3存储桶文件

iCo*_*ers 5 php amazon-s3 laravel laravel-4 laravel-5.2

我正在使用亚马逊s3,但在这里我遇到了两个问题

1.当我提交表格时,我无法直接将文件上传到亚马逊服务器.我的意思是我必须上传图片到上传文件夹,从那里我必须检索并上传到.s3 server有没有办法在我们点击提交时直接上传图片?

2.如果我通过'public's3 put object那么只有我才能访问或查看文件,但如果我把它公开每个人都可以查看文件,但我需要的所有文件和查看保护只对通过认证的用户.可以任何一个建议我如何解决这个问题?

try {           
    $s3 = \Storage::disk('s3');
    $s3->put($strFileName, file_get_contents($img_path.$strFileName), 'public');
} catch (Aws\Exception\S3Exception $e) {
    echo "There was an error uploading the file.\n"+$e;
}
Run Code Online (Sandbox Code Playgroud)

在提问之前我已经从stackoverflow读了这么多答案,但它没有帮我修复我的问题.谢谢

小智 5

对于你的第一个问题,可以直接将图像上传到AWS S3。

$s3 = \Storage::disk('s3')->getDriver();
$s3->put($filePath, file_get_contents($file), array('ContentDisposition' => 'attachment; filename=' . $file_name . '', 'ACL' => 'public-read'));
Run Code Online (Sandbox Code Playgroud)

您应该指定您的文件路径和从表单中获取的文件。


Pit*_*ate 2

我最近解决了这个问题。首先,是的,您可以直接上传到 s3,这是我用于获取有关此内容的一些信息的内容:http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html

首先,您需要创建一个策略和签名服务器端以添加到您的 html 表单中以上传文件。

$policy = base64_encode(json_encode([
            "expiration" => "2100-01-01T00:00:00Z",
            "conditions" => [
                ["bucket"=> "bucketname"],
                ["starts-with", '$key', "foldername"],
                ["acl" => "public-read"],
                ["starts-with", '$Content-Type', "image/"],
                ["success_action_status" => '201'],
            ]
        ]));
$signature = base64_encode(hash_hmac('sha1',$policy,getenv('S3_SECRET_KEY'),true));
Run Code Online (Sandbox Code Playgroud)

现在,在前端我的表单上,我不使用提交按钮,您可以使用提交按钮,但您需要捕获提交并防止表单实际提交,直到上传完成。

当我们点击保存时,它会生成一个md5(使用npm安装)文件名,这样文件名就不能真正被随机猜测,然后它使用ajax将文件上传到S3。完成后,它将文件数据和返回的 aws 数据放入隐藏输入中并提交表单。它应该看起来像这样:

<form action="/post/url" method="POST" id="form">
    <input type="text" name="other_field" />
    <input type="file" class="form-control" id="image_uploader" name="file" accept="image/*" />
    <input type="hidden" id="hidden_medias" name="medias" value="[]" />
</form>
<input type="button" value="save" id="save" />
<script>
$(document).ready(function(){
    $('#save').click(function(){
            uploadImage(function () {
                $('#form').submit();
            });
    });
});
var uploadImage = function(callback) {
    var file = $('#image_uploader')[0].files[0];
    if(file !== undefined) {
        var data = new FormData();
        var filename = md5(file.name + Math.floor(Date.now() / 1000));
        var filenamePieces = file.name.split('.');
        var extension = filenamePieces[filenamePieces.length - 1];
        data.append('acl',"public-read");
        data.append('policy',"{!! $policy !!}");
        data.append('signature',"{!! $signature !!}");
        data.append('Content-type',"image/");
        data.append('success_action_status',"201");
        data.append('AWSAccessKeyId',"{!! getenv('S3_KEY_ID') !!}");
        data.append('key',filename + '.' + extension);
        data.append('file', file);

        var fileData = {
            type: file.type,
            name: file.name,
            size: file.size
        };

        $.ajax({
            url: 'https://{bucket_name}.s3.amazonaws.com/',
            type: 'POST',
            data: data,
            processData: false,
            contentType: false,

            success: function (awsData) {
                var xmlData = new XMLSerializer().serializeToString(awsData);
                var currentImages = JSON.parse($('#hidden_medias').val());
                currentImages.push({
                    awsData: xmlData,
                    fileData: fileData
                });
                $('#hidden_medias').val(JSON.stringify(currentImages));
                callback();
            },
            error: function (errorData) {
                console.log(errorData);
            }
        });
    }
};
</script>
Run Code Online (Sandbox Code Playgroud)

然后,监听提交的控制器解析该输入字段中的 JSON,并创建一个 Media 实例(我创建的模型),并存储每个图像的awsData和。fileData

然后,不要将 html 图像标签指向 s3 文件,如下所示:

<img src="https://{bucketname}.s3.amazonaws.com/filename.jpg" />
Run Code Online (Sandbox Code Playgroud)

我做了这样的事情:

<img src="/medias/{id}" />
Run Code Online (Sandbox Code Playgroud)

然后该路由可以通过普通的auth中间件以及您在 Laravel 中需要做的所有事情。最后,该路由指向执行此操作的控制器:

public function getResponse($id)
{
    $media = Media::find($id);
    return (new Response('',301,['Location' => $media->info['aws']['Location']]));
}
Run Code Online (Sandbox Code Playgroud)

因此,它所做的只是使用 301 重定向并将标头位置设置为实际的 aws 文件。由于我们在将文件上传到 aws 时会生成 md5 文件名,因此每个文件名都是 md5,因此人们无法随机搜索存储桶中的 aws 文件。