위의 수업이 선행되어야 한다.
php
또는 Nodejs
를 이용해서 S3를 제어하는 방법을 살펴보도록 하자.
S3
를 제어하는 방법은 여러가지가 있으나, 가장 중요한 것은 데이터를 넣고 (파일 업로드), 업로드한 파일을 다운로드 받고, 파일 목록을 보여주는 것이다.
위의 실습을 하기 위해 먼저 ec2
로 ubuntu
인스턴스를 생성해서 접속하고 시작하자.
그리고 위에 이전에 했던 php를 설치하고 composer.json
를 만들고, credentials 파일까지 만드는 걸 진행하자.
그 후 /var/www/html
에 s3.php
라는 파일을 만들 것 이다.
$nano s3.php
s3.php
파일을 만들어주고, 그곳에 아래 코드를 붙여넣기 할 것이다.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01','profile'=>'default');
그 다음 우리가 s3
를 사용하기 위해선 s3 클라이언트
라는 클래스를 객체화 시킬 필요가 있다.
$s3=new Aws\S3\S3Client($param);
그러면, s3변수로 s3의 인프라를 제어할 수 있게 되는 것이다.
https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.S3.html
위에 php aws sdk
를 사용할 수 있는 레퍼런스가 있다.
S3Client
로 들어가면 PutObject
라는 것이 있는데 이것이 파일을 업로드 하는 것이다.
위와 같은 형식으로 사용하면 된다고 적혀있다.
$result = $client->putObject([
'ACL' => 'private|public-read|public-read-write|authenticated-read|aws-exec-read|bucket-owner-read|bucket-owner-full-control',
'AddContentMD5' => true || false,
'Body' => <string || resource || Psr\Http\Message\StreamInterface>,
'Bucket' => '<string>', // REQUIRED
'BucketKeyEnabled' => true || false,
'CacheControl' => '<string>',
'ChecksumAlgorithm' => 'CRC32|CRC32C|SHA1|SHA256',
'ChecksumCRC32' => '<string>',
'ChecksumCRC32C' => '<string>',
'ChecksumSHA1' => '<string>',
'ChecksumSHA256' => '<string>',
'ContentDisposition' => '<string>',
'ContentEncoding' => '<string>',
'ContentLanguage' => '<string>',
'ContentLength' => <integer>,
'ContentMD5' => '<string>',
'ContentSHA256' => '<string>',
'ContentType' => '<string>',
'ExpectedBucketOwner' => '<string>',
'Expires' => <integer || string || DateTime>,
'GrantFullControl' => '<string>',
'GrantRead' => '<string>',
'GrantReadACP' => '<string>',
'GrantWriteACP' => '<string>',
'Key' => '<string>', // REQUIRED
'Metadata' => ['<string>', ...],
'ObjectLockLegalHoldStatus' => 'ON|OFF',
'ObjectLockMode' => 'GOVERNANCE|COMPLIANCE',
'ObjectLockRetainUntilDate' => <integer || string || DateTime>,
'RequestPayer' => 'requester',
'SSECustomerAlgorithm' => '<string>',
'SSECustomerKey' => '<string>',
'SSECustomerKeyMD5' => '<string>',
'SSEKMSEncryptionContext' => '<string>',
'SSEKMSKeyId' => '<string>',
'ServerSideEncryption' => 'AES256|aws:kms|aws:kms:dsse',
'SourceFile' => '<string>',
'StorageClass' => 'STANDARD|REDUCED_REDUNDANCY|STANDARD_IA|ONEZONE_IA|INTELLIGENT_TIERING|GLACIER|DEEP_ARCHIVE|OUTPOSTS|GLACIER_IR|SNOW',
'Tagging' => '<string>',
'WebsiteRedirectLocation' => '<string>',
]);
밑으로 내려보면 코드의 옵션
이 있다.
ACL
: 권한 지정. 파일 업로드 시 파일을 비공개로 할 것인지 등을 표시Body
: 포함시키고 싶은 내용SourceFile
: 현재 컴퓨터에서 직접 파일을 올리고 싶을 때 사용Bucket
: S3 버킷Key
: 파일 이름먼저, sample.txt
라는 파일을 만들고 hello s3
라는 내용으로 두자.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01','profile'=>'default');
$s3=new Aws\S3\S3Client($param);
$s3->putObject([
'ACL'=>'public-read',
'SourceFile'=>'sample.txt',
'Bucket' =>'버킷명',
'Key'=>'sample.txt'
]);
?>
그 다음 s3.php
의 내용을 위 코드처럼 변경하자.
그리고
$sudo apt-get install php-xml
을 실행해주자.
이제 이 깔끔한 버킷에 php를 실행시켜서 sample.txt를 업로드해보자.
그 전에 버킷의 객체 소유권을 수정해주고,
모든 퍼블릭 액세스 차단을 비활성화해주자.
그러면 성공적으로 된다!
방금 만든 s3.php
파일을 기능별로 쪼개도록 하자.
mv s3.php s3_put.php
이번에는 업로드 된 파일의 목록을 확인하는 코드를 작성해보자.
$ cp s3_put.php s3_list.php
s3_list.php
를 수정해보자.
우리는 ListObjects
라는 명령어를 이용해보자.
위에꺼로 사용을 하자.
옵션은 위와 같다.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01','profile'=>'default');
$s3=new Aws\S3\S3Client($param);
$list=$s3->listObjects(Array('Bucket'=>'내 버킷명'));
var_dump($list);
?>
list변수에다가 파일 목록들을 배열로 저장하고, 그것을 출력해보자.
그러면 Aws\Result
에 담기는 것을 알 수 있다.
이것을 어떻게 사용하면 좋을지 한번 알아보자.
결과 객체를 toArray()
로 호출하면 배열을 만들어준다고 적혀있다.
var_dump($list->toArray());
위 처럼 수정해보자!
그럼 아까와는 다르게 배열에 저장되어있는 것을 확인할 수 있다.
이 배열은 Contents
라는 키 값으로 저장되어있다.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01','profile'=>'default');
$s3=new Aws\S3\S3Client($param);
$list=$s3->listObjects(Array('Bucket'=>'awsstudys3bucket'));
$listArray=$list->toArray();
foreach($listArray['Contents'] as $item){
print($item['Key']."\n");
}
?>
그러면 listArray
변수를 주고 그것의 'Contents'
의 Key
에만 접근을 해보자.
S3에 업로드 된 파일을 다운로드 받는 방법을 살펴보자.
기존에 만들었던 파일 중 s3_put.php
를 복사하자.
$ cp s3_put.php s3_get.php
putObject
라고 되어있는 부분을 getObject
로 해주면 된다.
그리고 ACL이랑 SourceFile을 지워주면 된다.
어디에 저장
할 것인지를 정해주는 SaveAs
를 추가하면 된다.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01','profile'=>'default');
$s3=new Aws\S3\S3Client($param);
$s3->getObject([
'Bucket' =>'awsstudys3bucket',
'Key'=>'sample.txt',
'SaveAs'=>fopen('sample_saved.txt','w')
]);
?>
즉, 이렇게 해주면 된다.
sample_saved.txt
가 생성된 것을 확인할 수 있다.
php 어플리케이션에서 파일을 업로드해서 S3로 데이터를 전송하는 방법에 대해 알아보자.
먼저, 파일을 전송하는 폼
을 만들고, 그것을 이용해서 파일을 전송하면 php가 그것을 받고, 다시 php가 s3로 전송해줄 것이다.
우선 폼을 만들어보자.
$nano upload.html
upload.html
을 만들어주자.
<html>
<body>
<form enctype="multipart/form-data" action="./s3_upload.php" method="POST">
<input type="file" name="userfile">
<input type="submit">
</form>
</body>
</html>
먼저, enctype
을 꼭 작성해주어야 한다.
그리고 action
부분은 사용자가 파일을 전송한다고 했을 때,
전송한 파일을 받는 쪽이 action
이 들어와야 한다.
우리는 현재 디렉터리에 s3_upload.php
쪽으로 파일을 전송하도록 하겠다.
전송하는 파일의 타입은 파일, 이름은 유저파일로 할 것이고
사용자가 파일을 선택한 후 서버로 전송하기 위해서는 submit
버튼이 필요하다.
이렇게 저장해두자.
그다음 ec2
의 퍼블릭 dns로 한 번 접속해보자.
뒤에 /upload.html
을 붙여야 한다.
그러면 위처럼 화면이 나온다.
s3_upload.php
파일로 사용자가 선택한 파일이 전송되는 것이다.
그러므로 이제 s3_upload.php
를 만들어보자.
우리가 필요한 것은 사용자가 전송한 파일이 어떤 임시 디렉터리에 어떤 이름으로 저장되어있는 지를 알려주는 $_FILES['userfile']['tmp_name']
가 필요하다.
<?php
var_dump($_FILES);
?>
먼저 위의 내용만 저장해서 출력해보자.
다시 제출하면 위와 같은 형식으로 표시된다.
이제는 s3를 활용해보자. 위에서 만든 s3_put.php
를 복사하자.
임시 디렉터리의 파일을 알아내서 그것을 sourfile로 지정하고
업로드 될 파일의 이름은 Key
뒤에다가 FILES를 이용해서 name으로 지정해준다.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01','profile'=>'default');
$s3=new Aws\S3\S3Client($param);
$s3->putObject(Array(
'ACL'=>'public-read',
'SourceFile'=>$_FILES['userfile']['tmp_name'],
'Bucket' =>'버킷이름',
'Key'=>$_FILES['userfile']['name']
));
unlink($_FILES['userfile']['tmp_name']);
?>
그다음 unlink로 사용자가 업로드한 파일을 지워준다.
한 번 테스트 해보자!
제출하면, 파일이 버킷에 저장되어야 한다.
(아무리 아무리 2시간이나 해봤는데도 도저히 500 error때문에 해결되지 않는다..)
사용자가 업로드한 파일을 붙여넣기 하려면 파일의 이름을 알아야한다.
즉, S3
상의 이름을 알아야 한다.
ObjectURL
이라는 것을 통해 파일을 다운받을 수 있을 것 같다.
ContentType
을 지정해보자.
'ContentType'=>$_FILES['userfile']['type']
이렇게 하면, S3로 전송할 때 사용자가 전송한 타입 정보까지 전송할 수 있게 된다.
S3에서는 putObject 메소드의 실행결과로 $result
객체를 리턴하는 것을 알 수 있다.
$resultArray = $result->toArray();
var_dump($resultArray['ObjectURL']);
ObjectURL만을 출력해보자.
실행시키면 잘 찍힌다.
<html>
<body>
<img src="<?php print($resultArray['ObjectURL']);?>" style="width:100%">
</body>
</html>
밑에 html 소스코드도 추가로 넣어주자.
<?php
require 'vendor/autoload.php';
$param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01');
$s3 = new Aws\S3\S3Client($param);
$result = $s3->putObject(Array(
'ACL'=>'public-read',
'SourceFile'=>$_FILES['userfile']['tmp_name'],
'Bucket'=>'codingeverybody2',
'Key'=>$_FILES['userfile']['name'],
'ContentType'=>$_FILES['userfile']['type']
));
unlink($_FILES['userfile']['tmp_name']);
$resultArray = $result->toArray();
var_dump($resultArray['ObjectURL']);
?>
<html>
<body>
<img src="<?php print($resultArray['ObjectURL']);?>" style="width:100%">
</body>
</html>
전체 소스코드는 위와 같이 된다.
파일이 서버로 전송 되고, s3가 알려주는 url을 받아서 화면에 출력해준다.
우선, s3_put.js
라는 파일을 하나 만들자.
var AWS = require("aws-sdk");
AWS.config.region='ap-northeast-2';
이전 시간에 배웠던 기본적인 코드를 붙여넣자.
s3라는 클래스가 있는데,
클래스를 사용하기 위한 기본 코드는
var s3=new AWS.S3();
위와 같다.
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
이미지를 올리는 것은 putObejct
를 사용한다.
var AWS = require("aws-sdk");
AWS.config.region='ap-northeast-2';
var s3=new AWS.S3();
var param={
'Bucket':'awsstudys3bucket',
'Key':'logo.png',
'ACL':'public-read',
'Body':
}
s3.putObject({}, function(err, data){
console.log(err);
console.log(data);
})
여기서 Body
에는 다양한 값이 들어올 수 있다.
fs
란 nodejs에서 파일을 헨들링 할 때 사용하는 모듈이다.
큰 파일을 조각해서 읽어서 처리할 수 있는 체계를 만들 수 있다.
그 전에,
$wget https://s3.ap-northeast-2.amazonaws.com/opentutorials-user-file/course/94.png
위의 명령을 통해 94.png라는 파일을 다운받아 두자.
var AWS = require("aws-sdk");
var fs=require('fs');
AWS.config.region='ap-northeast-2';
var s3=new AWS.S3();
var param={
'Bucket':'awsstudys3bucket',
'Key':'logo.png',
'ACL':'public-read',
'Body':fs.createReadStream('94.png'),
'ContentType':'image/png'
}
s3.putObject(param, function(err, data){
console.log(err);
console.log(data);
})
Body
는 무슨 뜻이냐면, 94.png라는 파일을 Body의 프로퍼티 값으로 주겠다는 뜻이고, 내부적으로 94.png를 s3로 전송하게 된다.
ContentType
을 지정하지 않으면 이미지를 표시 하지 않고 다운로드 해버리는 문제가 생길 수 있으므로 추가로 param에 넣어주자.
이제 실행해보자!
$node s3_put.js
버킷에 가보면 잘 보인다!!
그치만 putObject
는 실행을 시키면 data라는 매개변수를 통해서 들어오게 되는데,
매개변수 안에는 우리가 업로드한 파일의 주소가 들어있지 않다.
그래서 주소가 필요한 경우에는 upload
메소드를 쓰는 것이 낫다.
이 로케이션을 통해서
주소를 인터넷에 입력하면, 위처럼 파일을 확인할 수 있다.
s3_list.js
라는 파일을 만들자.
var AWS = require("aws-sdk");
AWS.config.region='ap-northeast-2';
var s3=new AWS.S3();
공통으로 했던 소스코드는 계속 붙여넣자.
파일의 목록을 가져오는 방법은 listObjects
를 사용하면 된다.
위의 메소드는 첫번째 인자로 param을 받는데, bucket
의 이름을 가지고 있어야 한다.
.on('success')
이렇게 하면, 앞에 있는 결과가 성공이라면 success 뒤의 function을 실행하도록 약속이 되어있다.
var AWS = require("aws-sdk");
AWS.config.region='ap-northeast-2';
var s3=new AWS.S3();
s3.listObjects({Bucket:'awsstudys3bucket'}).on('success',function handlePage(response){
console.log(response.data.Contents);
if(response.hasNextPage()){
response.nextPage().on('success',handlePage).send();
}
}).send();
response
안에 무엇이 있는지 찍어보면 어떻게 사용할 지 알 수 있을 것이다.
그리고 그 밑에 있는것은, 만약 버킷안에 파일이 수천개 있다면 데이터를 가져오는 양을 페이징을 통해 정하게 된다. 이 때, response 안의 hasNextPage()를 이용해 조절하게 된다.
즉, if()안의 내용은 재귀함수와 비슷하게 작동한다.
실행시켜보자!
response.data.Contents
는 우리가 s3에 업로드해둔 파일들의 배열이라는 것을 알 수 있다.
var AWS = require("aws-sdk");
AWS.config.region='ap-northeast-2';
var s3=new AWS.S3();
s3.listObjects({Bucket:'awsstudys3bucket'}).on('success',function handlePage(response){
for(var name in response.data.Contents){
console.log(response.data.Contents[name].Key);
}
if(response.hasNextPage()){
response.nextPage().on('success',handlePage).send();
}
}).send();
Key
만 출력해서 파일 이름들만 출력된다.
S3에 올라간 특정한 파일을 다운받아서 저장하는 방법을 살펴보자.
s3_get.js
라는 파일을 만들자.
먼저, 공통코드 3줄을 붙여넣어주자!
Streaming Requests
Streaming 방식을 통해서 정보를 다운받을 수 있도록 한다. Streaming은 다운받을 파일의 크기 용량이 매우 클 때, 사용하는 것이다.
즉, 파일을 부분부분적으로 사용할 수 있도록 해주는 것이다.
var file = require('fs').createWriteStream('logo.png');
s3.getObject(params).createReadStream().pipe(file);
위의 코드를 이용해서 파일을 저장해보자.
createWriteStream
쓰는 쪽은 파일이기 때문에, 우리가 저장하고자 하는 파일을 입력값으로 줘야 한다.
var params = {Bucket:'awsstudys3bucket', Key:'logo.png'};
params
는 어디서 파일을 가져올 것인지를 주면 된다.
params에는 Bucket 프로퍼티와 Key 프로퍼티를 입력해야 한다.
createReadStream
을 통해서 S3에 있는 데이터를 읽어들여서 데이터를 파일에 저장하는 것이다.
저장하고, 실행시켜보자!
logo.png
파일이 저장되었다.
s3_app.js
파일을 하나 생성하자.
var express=require('express');
var app=express();
app.get('/s3',function(req,res){
res.send('Hello s3');
});
app.listen(80,function(){
console.log('Connected');
})
위의 소스코드를 일단 붙여넣자. 기본적인 코드다.
express
를 이용해서 웹 애플리케이션을 개발할 때 사용하는 코드이다.
먼저 실행시켜보자.
$sudo node s3_app.js
Connected
가 나오면 성공이다.
만약, 에러가 난다면
$sudo service apache2 stop
으로 80번 포트를 자유롭게 해주고 실행해보자!
public dns로 접속하면 잘 출력된다.
이제부터 본격적으로 코딩을 해보자.
먼저, 사용자가 upload라는 url로 접속을 하게 되면, 입력 양식을 화면에 보이게 할 것이다.
app.get('/form',function(req,res){
var output=``;
res.send(output);
});
위의 코드를 추가하자. `
와 `
사이에 있는 것은 nodejs에 최신으로 생긴 것으로.. (7년전이니 최신이 이제 아니다..) <html>
과 같은 태그를 이용하기 쉽게 만들어 진 것이다.
var express=require('express');
var AWS=require("aws-sdk");
var app=express();
app.get('/s3',function(req,res){
res.send('Hello s3');
});
app.get('/form',function(req,res){
var output=`
<html>
<body>
<form enctype="multipart/form-data" method="post" action="upload_receiver">
<input type="file" name="userfile">
<input type="submit">
</form>
</body>
</html>
`;
res.send(output);
});
app.listen(80,function(){
console.log('Connected');
})
위의 소스코드를 한 번 실행시켜보자.
$ sudo node s3_app.js
/form
으로 접속하면, 위와 같은 폼이 출력된다.
제출버튼을 누르면 /upload_receiver
로 이동하게 된다.
이번엔 /upload_receiver 부분을 만들어주자.
post
방식으로 받아야 하기 때문에 post 메소드를 쓰자.
업로드 된 파일을 사용하기 위해서는 formidable
을 사용해야 한다.
이것을 설치해보자.
$ npm install formidable@latest --save
설치를 완료해주자.
var formidable=require('formidable');
먼저 모듈을 가져와주자.
그 후, 받는 쪽에서 form 객체를 만들자.
app.post('/upload_receiver',function(req,res){
var form=new formidable.IncommingForm();
form.parse(req,function(err,fields,files){
console.log(err,fields, files);
});
});
위의 내용을 추가해서 한 번 실행시켜보자.
그 전에, formidable이 지금 require
을 안 쓰기 때문에,
수정해줘야 할 부분이 많다.
import express from 'express';
import formidable from 'formidable';
import AWS from 'aws-sdk';
먼저, s3_app.sj를 위의 내용처럼 바꿔준다.
그리고, package.json
파일을 수정해줘야 한다.
"type":"module"
이라는 내용을 추가해주면 정상적으로 실행 가능하다.
한 번 실행시켜서 접속해보자~
또 오류다~
왜 이렇게 뜨는가 고쳐보자.
var form = formidable({});
이제는 incomingFrom이라는 게 없다. 위 처럼 수정해주자.
그 다음 제출해주면 시간이 오래걸리는 데 이게 성공한것이다.
cmd 창으로 가보면 뭐가 좌라락 나와있다.
현재는 File
안이 아니라 PersistentFile
안에 우리가 업로드했던 파일들이 나오고 있다.
이제 s3로 업로드 하는 코드를 작성해보자.
import express from 'express';
import formidable from 'formidable';
import AWS from 'aws-sdk';
import fs from "fs";
var app=express();
app.get('/s3',function(req,res){
res.send('Hello s3');
});
app.get('/form',function(req,res){
var output=`
<html>
<body>
<form enctype="multipart/form-data" method="post" action="upload_receiver">
<input type="file" name="userfile">
<input type="submit">
</form>
</body>
</html>
`;
res.send(output);
});
app.post('/upload_receiver',function(req,res){
var form = formidable({});
form.parse(req,function(err,fields,files){
var s3=new AWS.S3();
const fileBuffer=fs.createReadStream(files.userfile.filepath);
var params={
Bucket:'awsstudys3bucket',
Key:files.userfile.originalFilename,
ACL:'public-read',
Body:fileBuffer
}
s3.upload(params,function(err,data){
if(err)
console.log(err);
else
console.log(data);
});
console.log(err,fields, files);
});
});
app.listen(80,function(){
console.log('Connected');
})
위의 내용으로 수정하고, 출력을 해보자.
해도 해도 자꾸 path
뭐라뭐라 하면서 에러가 뜬다..
아무튼 잘 되면,
파일이 잘 업로드 되게 된다..
s3.upload(params, function(err, data){
var result='';
if(err)
result = 'Fail';
else
result = `<img src="${data.Location}">`;
res.send(`<html><body>${result}</body></html>`);
});
upload 메소드를 위처럼 변경해주자.
에러가 없다면 이미지를 화면에 출력해주는 코드이다.
위의 코드로 수정해주면, 이미지가 화면에 바로 보이게 된다.