Laravel 保护 Amazon s3 存储桶文件
我正在使用 Amazon s3,但在这里我面临两个问题
I am using Amazon s3 but here i am facing two problems
1.当我提交表单时,我无法直接将文件上传到亚马逊服务器.我的意思是我必须将图像上传到我的 PHP 服务器上的 upload 文件夹
,然后我必须从那里检索和将它们上传到 s3 服务器
.有没有办法在我们点击提交的时候直接上传图片到s3
?
1.I can't directly upload files to amazon server when i submit form.I mean i have to upload images to an upload folder
on my PHP server and from there i have to retrieve and upload them to s3 server
. Is there a way to upload images directly to s3
when we click on submit?
2.如果我在 s3 put object
中传递 'public'
则我可以访问或查看文件,但如果我将其公开,则每个人都可以查看文件.但我需要保护所有文件并只查看经过身份验证的用户.谁能建议我如何解决这个问题?
2.If i pass 'public'
in s3 put object
then i can access or view files, but if i make it public every one can view files. But i need to protect all files and view only to the authenticated user. Can any one suggest me how to fix this issue?
try {
$s3 = Storage::disk('s3');
$s3->put($strFileName, file_get_contents($img_path.$strFileName), 'public');
} catch (AwsExceptionS3Exception $e) {
echo "There was an error uploading the file.
"+$e;
}
在提问之前,我已经阅读了许多来自 stackoverflow 的答案,但它并没有帮助我解决我的问题.谢谢.
Before asking questions i have read many answers from stackoverflow but it didnt helped me to fix my issue. Thanks.
推荐答案
我最近解决了这个问题.首先是的,您可以直接上传到 s3,这是我用来获取一些信息的:http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html
I recently tackled this problem. First off yes you can upload directly to s3 here is what I used for some info on this: http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html
首先,您需要创建一个策略和签名服务器端以添加到您的 html 表单以上传文件.
First off you need to create a policy and signature server side to add to your html form for uploading files.
$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));
现在在我的表单前端我不使用提交按钮,您可以使用提交按钮,但您需要捕获提交并阻止表单实际提交,直到上传完成.
Now on the frontend my form I don't use a submit button, you could use a submit button but you will need to catch the submit and prevent the form from actually submitting till after the upload finishes.
当我们点击保存时,它会生成一个 md5(使用 npm 安装)文件名,这样文件名就不会被随机猜测,然后它使用 ajax 将文件上传到 S3.完成后,它将文件数据和返回的 aws 数据放入隐藏输入并提交表单.它应该看起来像这样:
When we click save, it generates an md5 (use npm to install) filename so that file names can't really be guessed randomly, it then uses ajax to upload the file up to S3. After this is finished it puts the file data and returned aws data in a hidden input and submits the form. It should look something like this:
<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>
监听提交的控制器然后解析来自该输入字段的 JSON 并创建一个 Media 实例(我创建的一个模型)并存储 awsData
和 fileData
对于每个图像.
The controller listening for the submit then parses the JSON from that input field and creates an instance of Media (a model I created) and it stores the awsData
and fileData
for each image.
然后不是像这样将html图像标签指向s3文件:
Then instead of pointing html image tags to the s3 file like this:
<img src="https://{bucketname}.s3.amazonaws.com/filename.jpg" />
我会这样做:
<img src="/medias/{id}" />
然后路由就可以通过普通的 auth
中间件和你在 Laravel 中需要做的所有事情.最后,该路由指向执行此操作的控制器:
Then the route can go through the normal auth
middleware and all you need to do in Laravel. Finally, that route points to a controller that does this:
public function getResponse($id)
{
$media = Media::find($id);
return (new Response('',301,['Location' => $media->info['aws']['Location']]));
}
所以这只是使用 301 重定向并将标头位置设置为实际的 aws 文件.由于我们在将文件上传到 aws 时会生成一个 md5 文件名,因此每个文件名都是一个 md5,因此人们无法在存储桶中随机搜索 aws 文件.
So what this does is simply uses a 301 redirect and sets the header location to the actual aws file. Since we generate an md5 filename when we upload the file to aws each filename is an md5 so people couldn't randomly search for aws files in the bucket.
相关文章