[AWS] S3 SDK

당당·2023년 6월 24일
0

AWS

목록 보기
19/24
post-custom-banner

📔설명

https://velog.io/@dangdang/AWS-AWS-SDK

위의 수업이 선행되어야 한다.

php 또는 Nodejs를 이용해서 S3를 제어하는 방법을 살펴보도록 하자.


🍙PHP를 위한 S3 SDK

🍕파일 전송

S3를 제어하는 방법은 여러가지가 있으나, 가장 중요한 것은 데이터를 넣고 (파일 업로드), 업로드한 파일을 다운로드 받고, 파일 목록을 보여주는 것이다.

위의 실습을 하기 위해 먼저 ec2ubuntu 인스턴스를 생성해서 접속하고 시작하자.

그리고 위에 이전에 했던 php를 설치하고 composer.json 를 만들고, credentials 파일까지 만드는 걸 진행하자.

그 후 /var/www/htmls3.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가 생성된 것을 확인할 수 있다.

🌭웹애플리케이션에서 S3 활용

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을 받아서 화면에 출력해준다.


🥨Nodejs를 위한 S3 SDK

🧇업로드

우선, 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파일이 저장되었다.

🥡nodejs 웹애플리케이션에서 s3 SDK 활용

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 메소드를 쓰자.

https://github.com/node-formidable/formidable

업로드 된 파일을 사용하기 위해서는 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 메소드를 위처럼 변경해주자.

에러가 없다면 이미지를 화면에 출력해주는 코드이다.

위의 코드로 수정해주면, 이미지가 화면에 바로 보이게 된다.

profile
MySQL DBA 신입
post-custom-banner

0개의 댓글