PHP용 AWS S3 Client 사용하기

개발을 파헤치다/PHP|2018. 1. 12. 15:30

AWS에서는 Simple Storage Service(이하 S3)라는 유용한 도구를 제공합니다.

S3에는 이미지, 파일 뿐만 아니라 데이터베이스 백업, 소스코드 백업 데이터도 저장할 수 있습니다.
대용량 데이터를 저장하는데 유용한 서비스라고 할 수 있습니다.

AWS Console로도 관리가 가능하지만 AWS에서는 다양한 언어로 S3의 파일(객체)들을 다룰 수 있는 도구를 제공합니다.

이번에는 AWS S3의 저장소 개념인 Bucket에 객체를 업로드, 가져오기, 삭제하는 기능과 Bucket의 객체 목록을 받아오는 Class를 직접 구현해 봅니다.

또한, S3에서 이미지 객체를 가져오는 경우 어떻게 브라우저 상에서 보여줄 수 있는지 그리고 어떤 점을 주의해야 하는 지도 함께 살펴봅니다.


Composer 설치

CodeIgniter가 이미 설치되어 있다고 가정합니다.

$ vi composer.json

Composer.json에 다음과 같이 내용을 추가합니다.

{
"description": "The CodeIgniter framework",
"name": "codeigniter/framework",
"type": "project",
"homepage": "https://codeigniter.com",
"license": "MIT",
"support": {
"forum": "http://forum.codeigniter.com/",
"wiki": "https://github.com/bcit-ci/CodeIgniter/wiki",
"slack": "https://codeigniterchat.slack.com",
"source": "https://github.com/bcit-ci/CodeIgniter"
},
"require": {
"php": ">=5.3.7",
"aws/aws-sdk-php" : "^3.34"
},
"suggest": {
"paragonie/random_compat": "Provides better randomness in PHP 5.x"
},
"require-dev": {
"mikey179/vfsStream": "1.1.*",
"phpunit/phpunit": "4.* || 5.*"
}
}
$ composer update

AWS SDK의 설치가 완료되었습니다.

이제 autoload.php 파일을 통해 AWS SDK를 사용할 수 있습니다.

그전에 다시 한번 autoload관련 부분을 업데이트합니다.

$ composer dump-autoload -o


PHP용 AWS SDK 라이브러리 만들기

CodeIgniter에서는 직접 개발한 클래스를 라이브러리 형태로 사용할 수 있습니다.

먼저, S3 객체를 업로드, 가져오기, 삭제하는 기능과 S3 Bucket의 객체 목록을 가져오는 기능을 수행하는 클래스를 구현합니다.

<?php
class S3Image_Manager
{
    protected $connect_param; // 접속 정보
    protected $S3; // S3를 관리하는 객체
    protected $S3_bucket;

    // 생성자
    function __construct() {
        $this->connect_param = Array('region'=>'ap-northeast-2', 'version'=>'2006-03-01',
        'credentials' => array(
            'key' => 'your key',
            'secret' => 'your secret value'));

        $this->S3 = new Aws\S3\S3Client($this->connect_param); // S3에 접속한다.

        $this->S3_bucket = 'your bucket';

    }

    // $fileName_local : 업로드할 파일 경로(이름)
    // $filePath_S3 : S3에 저장할 파일 경로(이름)
    public function uploadImage($filePath_local, $filePath_S3) {
        try
        {
            $result = $this->S3->putObject(Array(
                'ACL'=>'public-read',
                'SourceFile'=>$filePath_local,
                'Bucket'=>$this->S3_bucket, // 파일을 업로드할 버킷 이름
                'Key'=>$filePath_S3
            ));
            return $result;
        } catch (Exception $e){
            $result = array("Errors" => "Upload Image Exception", "minor_code" => "Code_00");
            return $result;
        }
    }

    //$images : 삭제할 파일 이름이 저장되어있는 배열
    public function deleteImages($images)
    {
        $img_list = array();
        for($i = 0; $i < sizeof($images); $i++)
        {
            array_push($img_list, array('Key' => $images[$i]));    //지울 파일 이름이 Key값이다.
        }

        $objects = array('Objects'=>$img_list);
        try
        {
            $result = $this->S3->deleteObjects(Array(
                'Bucket' => $this->S3_bucket,
                'Delete' => $objects
            ));
            return $result;
        }catch(Exception $e){
            $result = array("Errors" => "Delete Image Exception", "minor_code" => "Code_01");
            return $result;
        }
    }

    /*
     * Bucket의 객체 목록을 가져오는 메서드
     * */
    public function getBucketList($bucket)
    {
        try{
            $result = $this->S3->listObjects(array(
                'Bucket' => $bucket
            ));
            return $result;
        }catch(Exception $e){
            $result = array("Errors" => "Get Bucket List Exception", "minor_code" => "Code_02");
            return $result;
        }

    }

    /*
     * Bucket의 객체를 가져오는 메서드
     * */
    public function getObject($bucket, $key)
    {
        try{
            $result = $this->S3->getObject([
                'Bucket' => $bucket,
                'Key' => $key,
                'SaveAs' => $path . $key    //getObject를 통해 받아온 S3 객체를 지정된 경로에 파일로 저장한다.
            ]);
            return $result;
        }catch(Exception $e)
        {
            $result = array("Errors" => "Get Object Exception", "minor_code" => "Code_03", "description" => $e->getMessage());
            return $result;
        }

    }
}
?>


Controller나 Model에서 사용할 때에는 다음과 같이 사용합니다.

class MembersModel extends CI_Model
{


    function __construct()
    {
        $this -> load -> library('S3Image_Manager');
    }

 
    public function get_certificate_image($key)
    {
        $s3 = new S3Image_Manager();
        $image_key = $this -> CERTIFICATE_HEADER . $key;
        $result = $s3 -> getObject('your bucket', $image_key);
        return $result;

    }

}


S3에서 이미지를 가져와 브라우저로 보여주기

<?php
//AWS SDK는 Composer를 사용하여 설치하는 것이 좋습니다
require 'vendor/autoload.php';

use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;

$bucket = '*** Your Bucket Name ***';
$keyname = '*** Your Object Key ***';

// S3 클라이언트를 초기화합니다
$s3 = S3Client::factory();

try {
    //S3 객체를 가져옵니다
    $result = $s3->getObject(array(
        'Bucket' => $bucket,
        'Key'    => $keyname
    ));

    //가져온 객체를 브라우저 상에 보여줍니다
    header("Content-Type: {$result['ContentType']}");
    echo $result['Body'];
} catch (S3Exception $e) {
    echo $e->getMessage() . "\n";
}

위와 같이 getObject를 통해 S3에서 이미지 객체를 가져옵니다.
그리고 PHP의 header() 메서드를 사용하여 Content Type을 이미지로 설정하면 브라우저 상에 S3 이미지를 보여줄 수 있습니다.
이때 주의할 점이 한가지 있습니다.

echo를 통해 이미지 byte 정보를 내보내게 되면 PHP에서는 내부적으로 Output Buffer에 이미지 byte 정보를 모은 뒤 HTTP 통신으로 연결 된 소켓에 Buffer의 내용을 전달하게 됩니다.
위의 코드에서는 헤더를 Image/jpeg로 설정하고 이미지 정보를 내보내기 때문에 브라우저에서는 건네 받은 이미지를 보여주게 됩니다.

PHP에서 위처럼 이미지를 보여줄 때 주의할 점이 있습니다.
바로 Output Buffer를 통해 이미지 정보를 내보낼 때 공백이나 줄바꿈이 포함되어서는 안된다는 것입니다.
이러한 것들이 포함되면 이미지가 손상되었다고 인식됩니다. 그러면 브라우저 상에도 표시되지 않고 다운로드 받아도 이미지 파일을 열 수 없습니다. 그렇기 때문에 이미지 byte 정보를 내보내기 전에 Output Buffer를 비워줘야 합니다.
아래의 ob_clean() 메서드를 통해서 이를 수행할 수 있습니다.

try {
    //S3 객체를 가져옵니다
    $result = $s3->getObject(array(
        'Bucket' => $bucket,
        'Key'    => $keyname
    ));

    ob_clean();     //Output Buffer를 비워줍니다
    //가져온 객체를 브라우저 상에 보여줍니다
    header("Content-Type: {$result['ContentType']}");
    echo $result['Body'];
} catch (S3Exception $e) {
    echo $e->getMessage() . "\n";
}


댓글()