我最近解决了这个问题。首先,你可以直接上传到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文件。