我正在使用Amazon s3,但这里我面临两个问题
1。当我提交表单时,我不能直接上传文件到亚马逊服务器。我的意思是我必须将图像上传到我的PHP服务器上的upload folder
,从那里我必须检索并将它们上传到s3 server
。是否有办法上传图像直接到s3
时,我们点击提交?
2。如果我在s3 put object
中通过'public'
,那么我可以访问或查看文件,但如果我将其公开,每个人都可以查看文件。但我需要保护所有的文件和视图,只有通过身份验证的用户。谁能建议我如何解决这个问题?
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.n"+$e;
}
在问问题之前,我已经从stackoverflow读了很多答案,但它没有帮助我解决我的问题。谢谢。
对于您的第一个问题,可以直接将图片上传到AWS S3。
$s3 = Storage::disk('s3')->getDriver();
$s3->put($filePath, file_get_contents($file), array('ContentDisposition' => 'attachment; filename=' . $file_name . '', 'ACL' => 'public-read'));
您应该指定您的文件路径和您从表单中获得的文件。
1。当我们点击提交
时,有没有办法直接上传图像?是的
如何:
您需要使用JavaScript(带AJAX)分两部分完成此操作;
a)当用户单击"提交"时,捕获此事件,首先上传文件(参见http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-examples.html示例),并且b)然后通过AJAX提交表单并处理响应。
然而:
这允许用户上传任何东西,并可能导致问题。有提示(就在示例下面)创建15分钟(变量)的经过身份验证的url,但是如果用户花费超过15分钟,或试图在15分钟内上传100个文件,或上传图像文件以外的东西,或格式错误的图像文件等,会发生什么?
这是更安全的拉到你的服务器,并确认他们是图像和你需要的类型/大小,然后从服务器上传。
当然,如果这是一个简单的管理工具,你可以控制谁可以访问代码,那么就使用它吧——希望你只会上传你期望的内容。
2。我需要保护所有的文件,并且只查看经过认证的用户
通过"认证的用户":如果你指的是"上传图像的用户",那么s3单独不提供该功能,但CloudFront可以。您可以发布预先授权的url或签名的cookie: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html
如果"认证用户"是指上传文件的人,那么根据文档,如果没有访问底层客户端,这在Laravel类中是不可能的。默认情况下,public
和private
是您唯一的可见性选项,它们被转换为public-read
,但您需要authenticated-read
, bucket-owner-read
或其他罐装ACL授予之一(参考:http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl)如果authenticated-read
或其他罐装ACL授予不能提供您需要的权限配置文件,您可以创建自己的权限配置文件(在同一页面上进一步了解详细信息)。
解决方案是获取底层客户端,然后直接执行put-object。(然后如果你走了那么远,你也可以放弃Laravel库并拉入s3并自己完成-然后你可以完全控制一切)。
$client = $disk->getDriver()->getAdapter()->getClient();
$client->putObject([
'Bucket' => $bucket,
'Key' => $fileName,
'Body' => $fileBody,
'ACL' => 'authenticated-read' /* Or which ACL suits */
]);
我最近解决了这个问题。首先,是的,你可以直接上传到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文件。
解决你的问题,我也在使用,但没有laravel。
1。要将任何文件直接上传到Amazon AWS S3 Bucket的特定文件夹中,您可以这样做: