아마존 웹서비스

SQS SDK - PHP

수업개요

이번 수업은 PHP를 이용해서 SQS를 이용하는 방법에 대한 내용이다. 하지만 PHP의 복잡한 기능을 사용하지 않을 것이기 때문에 PHP를 모른다고해도 실제 에플리케이션에서 어떻게 SQS를 활용 할 수 있는지에 대한 아이디어를 얻을 수 있을 것이다. 

선행지식

구성

환경

 EC2 인스턴스는 아래와 같은 환경에서 동작할 것이다. 

  • 운영체제 : Ubuntu (필자는 12.04)
  • 웹서버 : Apache
  • 에플리케이션 : PHP
  • SDK : AWS PHP SDK 2

위의 환경을 구축한 후에 AMI를 만들고 각각의 환경에 따라서 PHP 에플리케이션을 작성할 것이다. 

설치

PHP sdk 2 설치 방법에서 설명하고 있는 EC2 인스턴스 생성, Apache, PHP 설치, SDK 설치를 참고한다.

PHP SDK 2 설치 방법 바로가기

큐생성

 

encoding, email 큐를 생성한다. 이에 대한 방법은 SQS 수업을 참고한다.

SQS의 큐는 한달동안 사용하지 않으면 AWS에 의해서 삭제될 수 있다. 따라서 에플리케이션 레벨에서 SQS의 큐가 자동 삭제되었을 때 이를 생성하는 로직을 구현해야 안전하다. 본 수업에서는 이 방법에 대해서 다루지는 않는다. 

파일 수신자

 

test.php 파일을 생성하고 테스트를 해본다. 아래 내용은 1.avi라는 메시지를 encoding 큐에 추가한다. 자세한 설명은 동영상을 참고한다.

아래는 파일을 전송하는 html 페이지다. 

sender.html

<html>
    <body>
        <form enctype="multipart/form-data" action="./receiver.php" method="POST">
            <input type="file" name="userfile" />
            <input type="submit" />
        </form>
    </body>
</html>

receiver.php

send.html이 아래는 전송한 파일을 수신 받는 php 에플리케이션이다. 

<?php
require 'aws-sdk-php-master/vendor/autoload.php';
use Aws\Sqs\SqsClient;
use Aws\S3\S3Client;
$key = 'AKIAJKWXNJYIQPXOP14SQ';
$secret = 'K39qUQYjMW8jBUQlxki1MY/OlC2QejcDsHKZXRf4/';
$bucket = 'codingeverybodysqs';
if(move_uploaded_file($_FILES['userfile']['tmp_name'], '/var/www/original/'.$_FILES['userfile']['name'])){
        $s3_client = S3Client::factory(array(
            'key'    => $key,
            'secret' => $secret
        ));

        $result = $s3_client->putObject(array(
            'Bucket'     => $bucket,
            'Key'        => $_FILES['userfile']['name'],
            'SourceFile' => '/var/www/original/'.$_FILES['userfile']['name']
        ));

        unlink('/var/www/original/'.$_FILES['userfile']['name']);

        $sqs_client = SqsClient::factory(array(
            'key'    => $key,
            'secret' => $secret,
            'region' => 'ap-northeast-1'

        ));


        $sqs_client->sendMessage(array(
            'QueueUrl'    => 'https://sqs.ap-northeast-1.amazonaws.com/666877925577/encoding',
            'MessageBody' => $_FILES['userfile']['name'],
        ));
}
?>

인코더 서버

 

인코더 서버는 encoding 큐에 반복적으로 접속해서 새로운 큐가 생성된 것이 있는지를 확인한다. 새로운 큐가 있다면 이를 받아온다. 

인코더 서버는 GD 라이브러리를 사용한다. 따라서 GD 라이브러리를 설치해야 한다. 아래와 같은 방법으로 설치 할 수 있다.

sudo apt-get install php5-gd;
sudo service apache2 reload;

resizeImage.php

<?php
/**
 * Resize image class will allow you to resize an image
 *
 * Can resize to exact size
 * Max width size while keep aspect ratio
 * Max height size while keep aspect ratio
 * Automatic while keep aspect ratio
 */
class ResizeImage
{
    private $ext;
	private $image;
	private $newImage;
	private $origWidth;
	private $origHeight;
	private $resizeWidth;
	private $resizeHeight;
	/**
	 * Class constructor requires to send through the image filename
	 *
	 * @param string $filename - Filename of the image you want to resize
	 */
	public function __construct( $filename )
	{
		if(file_exists($filename))
		{
			$this->setImage( $filename );
		} else {
			throw new Exception('Image ' . $filename . ' can not be found, try another image.');
		}
	}
	/**
	 * Set the image variable by using image create
	 *
	 * @param string $filename - The image filename
	 */
	private function setImage( $filename )
	{
		$size = getimagesize($filename);
		$this->ext = $size['mime'];
		switch($this->ext)
	    {
	    	// Image is a JPG
	        case 'image/jpg':
	        case 'image/jpeg':
	        	// create a jpeg extension
	            $this->image = imagecreatefromjpeg($filename);
	            break;
	        // Image is a GIF
	        case 'image/gif':
	            $this->image = @imagecreatefromgif($filename);
	            break;
	        // Image is a PNG
	        case 'image/png':
	            $this->image = @imagecreatefrompng($filename);
	            break;
	        // Mime type not found
	        default:
	            throw new Exception("File is not an image, please use another file type.", 1);
	    }
	    $this->origWidth = imagesx($this->image);
	    $this->origHeight = imagesy($this->image);
	}
	/**
	 * Save the image as the image type the original image was
	 *
	 * @param  String[type] $savePath     - The path to store the new image
	 * @param  string $imageQuality 	  - The qulaity level of image to create
	 *
	 * @return Saves the image
	 */
	public function saveImage($savePath, $imageQuality="100", $download = false)
	{
	    switch($this->ext)
	    {
	        case 'image/jpg':
	        case 'image/jpeg':
	        	// Check PHP supports this file type
	            if (imagetypes() & IMG_JPG) {
	                imagejpeg($this->newImage, $savePath, $imageQuality);
	            }
	            break;
	        case 'image/gif':
	        	// Check PHP supports this file type
	            if (imagetypes() & IMG_GIF) {
	                imagegif($this->newImage, $savePath);
	            }
	            break;
	        case 'image/png':
	            $invertScaleQuality = 9 - round(($imageQuality/100) * 9);
	            // Check PHP supports this file type
	            if (imagetypes() & IMG_PNG) {
	                imagepng($this->newImage, $savePath, $invertScaleQuality);
	            }
	            break;
	    }
	    if($download)
	    {
	    	header('Content-Description: File Transfer');
			header("Content-type: application/octet-stream");
			header("Content-disposition: attachment; filename= ".$savePath."");
			readfile($savePath);
	    }
	    imagedestroy($this->newImage);
	}
	/**
	 * Resize the image to these set dimensions
	 *
	 * @param  int $width        	- Max width of the image
	 * @param  int $height       	- Max height of the image
	 * @param  string $resizeOption - Scale option for the image
	 *
	 * @return Save new image
	 */
	public function resizeTo( $width, $height, $resizeOption = 'default' )
	{
		switch(strtolower($resizeOption))
		{
			case 'exact':
				$this->resizeWidth = $width;
				$this->resizeHeight = $height;
			break;
			case 'maxwidth':
				$this->resizeWidth  = $width;
				$this->resizeHeight = $this->resizeHeightByWidth($width);
			break;
			case 'maxheight':
				$this->resizeWidth  = $this->resizeWidthByHeight($height);
				$this->resizeHeight = $height;
			break;
			default:
				if($this->origWidth > $width || $this->origHeight > $height)
				{
					if ( $this->origWidth > $this->origHeight ) {
				    	 $this->resizeHeight = $this->resizeHeightByWidth($width);
			  			 $this->resizeWidth  = $width;
					} else if( $this->origWidth < $this->origHeight ) {
						$this->resizeWidth  = $this->resizeWidthByHeight($height);
						$this->resizeHeight = $height;
					}
				} else {
		            $this->resizeWidth = $width;
		            $this->resizeHeight = $height;
		        }
			break;
		}
		$this->newImage = imagecreatetruecolor($this->resizeWidth, $this->resizeHeight);
    	imagecopyresampled($this->newImage, $this->image, 0, 0, 0, 0, $this->resizeWidth, $this->resizeHeight, $this->origWidth, $this->origHeight);
	}
	/**
	 * Get the resized height from the width keeping the aspect ratio
	 *
	 * @param  int $width - Max image width
	 *
	 * @return Height keeping aspect ratio
	 */
	private function resizeHeightByWidth($width)
	{
		return floor(($this->origHeight/$this->origWidth)*$width);
	}
	/**
	 * Get the resized width from the height keeping the aspect ratio
	 *
	 * @param  int $height - Max image height
	 *
	 * @return Width keeping aspect ratio
	 */
	private function resizeWidthByHeight($height)
	{
		return floor(($this->origWidth/$this->origHeight)*$height);
	}
}
?>

encoder.php 

 

<?php
require 'aws-sdk-php-master/vendor/autoload.php';
require 'resizeImage.php';
use Aws\Sqs\SqsClient;
use Aws\S3\S3Client;
$key = 'AKIAJKWXNJYIQPXaOP4SQ';
$secret = 'K39qUQYjMW8jBUaQlxkiMY/OlC2QejcDsHKZXRf4/';
$bucket = 'codingeverybodysqs';
$encoding_queue = 'https://sqs.ap-northeast-1.amazonaws.com/666877925577/encoding';
$email_queue = 'https://sqs.ap-northeast-1.amazonaws.com/666877925577/email';
$sqs_client = SqsClient::factory(array(
    'key'    => $key,
    'secret' => $secret,
    'region' => 'ap-northeast-1'

));
$s3_client = S3Client::factory(array(
    'key'    => $key,
    'secret' => $secret
));

while(true){
        sleep(1);
        $result = $sqs_client->receiveMessage(array(
            'QueueUrl' => $encoding_queue,
        ));
        $msgs = $result->getPath('Messages');
        if(count($msgs)===0){
                echo ".";
                continue;
        }
        foreach ($msgs as $msg) {
                $messageBody = $msg['Body'];
                $receiptHandle = $msg['ReceiptHandle'];
                echo "\n".$messageBody.".... start encoding process\n";
                $result = $s3_client->getObject(array(
                    'Bucket' => $bucket,
                    'Key'    => $messageBody,
                    'SaveAs' => '/var/www/temp/'.$messageBody
                ));
                echo $messageBody.".....downloaded\n";
                $resize = new ResizeImage('/var/www/temp/'.$messageBody);
                $resize->resizeTo(100, 100, 'exact');
                $resize->saveImage('/var/www/encoded/'.$messageBody);
                echo $messageBody.".....resized \n";

                $result = $s3_client->putObject(array(
                    'Bucket'     => $bucket,
                    'Key'        => 'thumb.'.$messageBody,
                    'SourceFile' => '/var/www/encoded/'.$messageBody
                ));
                echo $messageBody.".....upload s3\n";

                $sqs_client->sendMessage(array(
                    'QueueUrl'    => $email_queue,
                    'MessageBody' => json_encode(array('file'=>'thumb.'.$messageBody, 'email'=>'egoing@gmail.com')),
                ));
                echo $messageBody.".....send message to the email queue\n";

                $sqs_client->deleteMessage(array(
                    'QueueUrl'  => $encoding_queue,
                    'ReceiptHandle' =>$receiptHandle
                ));
                echo $messageBody.".....remove message from the encoding queue\n";
        }
}
?>                

이메일 발송 서버

이메일 발송 서버는 email 큐에 반복적으로 접속해서 처리해야 할 메시지가 없는지 확인한다. 메시지를 발견하면 해당 메시지를 이용해서 이메일을 발송한다. 

이메일을 발송하기 위해서는 sendmail이 설치 되어 있어야 한다. 아래와 같은 방법으로 설치하면 된다.

sudo apt-get install sendmail;
sudo service apache2 reload;

emailer.php

<?php
require 'aws-sdk-php-master/vendor/autoload.php';
use Aws\Sqs\SqsClient;
use Aws\S3\S3Client;
$key = 'AKIAJALGGRUXMMQERZKQ';
$secret = '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';
$bucket = 'codingeverybodysqs';
$encoding_queue = 'https://sqs.ap-northeast-1.amazonaws.com/666877925577/encoding';
$email_queue = 'https://sqs.ap-northeast-1.amazonaws.com/666877925577/email';
$sqs_client = SqsClient::factory(array(
    'key'    => $key,
    'secret' => $secret,
    'region' => 'ap-northeast-1'

));

while(true){
        sleep(1);
        $result = $sqs_client->receiveMessage(array(
            'QueueUrl' => $email_queue,
        ));
        $msgs = $result->getPath('Messages');
        if(count($msgs)===0){
                echo ".";
                continue;
        }
        foreach ($msgs as $msg) {
                $body = json_decode($msg['Body']);
                $file = $body->file;
                $mailto = $body->email;
                $receiptHandle = $msg['ReceiptHandle'];

                echo "\n".$file.".... start email process\n";
                mail($mailto, $file.'의 인코딩이 끝났습니다.', $file);

                echo $file.".....sended email to {$mailto}\n";

                $sqs_client->deleteMessage(array(
                    'QueueUrl'  => $email_queue,
                    'ReceiptHandle' =>$receiptHandle
                ));
                echo $file.".....remove message from the email queue\n";
        }
}
?>

댓글

댓글 본문
버전 관리
egoing@gmail.com
현재 버전
선택 버전
graphittie 자세히 보기