我最近解决了这个问题。首先是的,您可以直接上传到 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));
现在在我的表单前端我不使用提交按钮,您可以使用提交按钮,但您需要捕获提交并阻止表单实际提交,直到上传完成。
当我们点击保存时,它会生成一个 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>
监听提交的控制器然后解析来自该输入字段的 JSON 并创建一个 Media 实例(我创建的一个模型)并为每个图像存储 awsData 和 fileData。
然后不是像这样将html图像标签指向s3文件:
<img src="https://{bucketname}.s3.amazonaws.com/filename.jpg" />
我会这样做:
<img src="/medias/{id}" />
然后路由就可以通过普通的auth中间件和你在Laravel中需要做的所有事情。最后,该路由指向执行此操作的控制器:
public function getResponse($id)
{
$media = Media::find($id);
return (new Response('',301,['Location' => $media->info['aws']['Location']]));
}
所以这只是使用 301 重定向并将标头位置设置为实际的 aws 文件。由于我们在将文件上传到 aws 时会生成一个 md5 文件名,因此每个文件名都是一个 md5,因此人们无法在存储桶中随机搜索 aws 文件。