我正在使用亚马逊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;
}
在提问之前我已经从stackoverflow读了这么多答案,但它没有帮我修复我的问题。谢谢
答案 0 :(得分:4)
对于您的第一个问题,可以直接将图像上传到AWS S3。
$s3 = \Storage::disk('s3')->getDriver();
$s3->put($filePath, file_get_contents($file), array('ContentDisposition' => 'attachment; filename=' . $file_name . '', 'ACL' => 'public-read'));
您应该指定文件路径和从表单中获取的文件。
答案 1 :(得分:2)
<强> 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
或其他一个罐装赠款(参考: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 */
]);
答案 2 :(得分: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));
现在在我的表格的前端,我没有使用提交按钮,你可以使用提交按钮,但你需要抓住提交并阻止表格实际提交直到上传完成。
当我们点击“保存”时,它会生成一个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文件。
答案 3 :(得分:2)
解决您的问题,我也使用但没有laravel。
<强> 1。要将任何文件直接上传到特定文件夹中的Amazon AWS S3 Bucket,您可以这样做。
<强> HTML 强>
<form action="upload.php" enctype="multipart/form-data">
<input type="file" name="file" id="file" />
<button type="submit">Upload file</button>
</form>
PHP - upload.php
包括aws php sdk
require "vendor/autoload.php";
初始化S3客户端
$credentials = new Aws\Credentials\Credentials(
'<AWS ACCESS KEY>',
'<AWS ACCESS SECRET>'
);
$s3Client = Aws\S3\S3Client::factory(
[
'credentials' => credentials
'region' => 'us-east-1',
'version' => 'latest'
]
);
创建文件上传实体
$uploadEntity = array(
'Bucket' => <S3 Bucket Name>,
'Key' => '<Upload_Folder_If_Any>/<FileName>',
'Body' => fopen($_FILES['file']['tmp_name'], 'r+'),
//'ContentDisposition' => 'attachment; filename="<FileName>"' <-- If need to allow downloading
);
上传到s3 Bucket
try {
// $result will be Aws\Result object
$result = $s3Client->putObject($uploadEntity);
} catch (Aws\S3\Exception\S3Exception $exception) {
// S3 Exception
}
<强> 2。现在仅将上传的文件提供给经过身份验证的用户
首先,您需要为s3 Bucket创建私有存储桶策略。
广告投放管理政策 - 要生成存储分区策略,您可以使用Policy Generator。使用此方法,您可以生成这样的策略。复制自Improve.dk website
{
"Id": "Policy1319566876317",
"Statement": [
{
"Sid": "Stmt1319566860498",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::<BucketName>/*",
"Principal": {
"CanonicalUser": [
"<CannoicalUserId_of_OAI>"
]
}
}
]
}
其次,您需要在s3 Bucket中设置cloudfront的私有Web分发。只有这样,您才能通过 aws签名网址或签名Cookie
将您的内容提供给经过身份验证的用户第三,要生成已签名的网址,您需要 pem 文件,您只能从aws控制台获取该文件。
生成签名网址
$cdnName = '<AWS CLOUDFRONT WEB DISTRIBUTION CDN>';
$assetName = '<UPLOAD_FOLDER_IF_ANY>/<FILENAME>';
$expiry = time() + 300; // 5 mins expiry time, ie. the signed url will be valid only for 5 mins
$cloudfront = CloudFrontClient::factory(array(
'credentials' => $credentials,
'region' => 'us-east-1',
'version' => 'latest'
));
// Use this for creating signed url
$signedUrl = $cloudFront->getSignedUrl([
'url' => $cdnName . '/' . $assetName,
'expires' => $expiry,
'private_key' => '/path/to/your/cloudfront-private-key.pem',
'key_pair_id' => '<cloudfront key pair id>'
]);
// Use this for signed cookie
$signedCookie = $cloudFront->getSignedCookie([
'url' => $cdnName . '/' . $assetName,
'expires' => $expiry,
'private_key' => '/path/to/your/cloudfront-private-key.pem',
'key_pair_id' => '<cloudfront key pair id>'
]);