저장프로시저
- 저장 프로시저는 하나 이상으로 구성된 Transact-SQL 문을 데이터베이스에 저장한 개체입니다.

저장프로시저 특징
  • 모듈 프로그래밍
    자주 반복해서 사용하는 T-SQL문을 DB에 저장해 필요한 시점에만 사용함.
    매번 같은 구문을 다시 작성할 필요가 없음
  • 유연한 보완관리
    데이터 조회하는 저장프로시저. 접근권한이 없어도 저장프로시저를 실행할 권한이 있다면 조회가능
  • 네트워크 트래픽 감소
    쿼리전체를 서버로 전송해서 작업하는 것이 아닌 저장 프로시저와 매개변수값만을 전달함으로 데이터량이 작음
  • 빠른실행
    저장프로시저는 실행후 쿼리 실행계획을 메모리에 저장 > 저장된 실행계획 사용 > 구문분석이나 최적화 과정 거치지 않아서 더 빠른 실행을 할수 있고 캐시에 없더라도 구문분석, 표준화등의 작업을 하지 않기에 성능이 빠름

저장프로저의 구성요소
저장 프로시저명, 매개변수들, SQL문, 결과값 반환의 반환값

저장프로시저의 종류
  • 확장프로시저 : C와 같은 언어를 이용해서 구현한 프로시저, master DB에만 추가가능
  • 사용자 정의 저장 프로시저 : T-SQL문을 이용해 저장 프로시저로 구현
  • 시스템 저장 프로시저 : SQL서버관리를 위해 시스템에서 제공해주는 저장 프로시저
    sys의 스키마로 나타남, 데이터베이스 명 필요없이 시스템 저장 프로시저명을 통해서 실행가능

    Sp_who, sp_who2 : 사용자 정보
    Sp_lock : lock 정보
    Sp_help : 지정한 개체 정보
    Sp_helpdb : 지정한 DB정보
    Sp_configure : SQL 서버 설정변경
  • 임시 저장프로시저
    T-SQL 문 또는 일괄처리의 실행계획을 재 사용하지 않던 이전 버전의 방식
    사용자 정의 프로시저와 동일하게 작성하지만, 저장프로시저 명을 #으로 하면 임시저장프로시저가 됨
    SQL Server 2005에서는 T-SQL문과 일괄처리의 실행계획을 재 사용할수 있음으로 임시저장프로시저 사용이 거의없음
  • CLR 저장 프로시저
    T-SQL에서 부족한 프로그래밍 부분을 CLR 저장 프로시저를 통해 T-SQL 저장 프로시저보다는 더 강력한 구조적 프로그래밍이 가능

저장 프로시저의 생성

CREATE PROCEDURE usp_withANumber <- 소문자 : 스키마. 저장 프로시저명
@ EmployeeID INT <- 매개변수, 데이터 형식
AS
SELECT ANumber, AContent, ManagerID
FROM HumanResource.analysisDate
WHERE ManagerID = @ EmployeeID
GO

EXECUTE usp_withANumber

GO
* 임시 저장프로시저의 생성은
CREATE PROCEDURE #usp_withANumber <- 소문자 : 스키마. 저장 프로시저명앞에 샾
* 저장프로시저 생성시, SP_ 접두사는 시스템저장프로시저와 혼란을 줄수 있음으로 사용금지
* 그룹화면 저장프로시저 삭제시 개별적으로 하나씩 삭제할수 없음으로 가급적 사용하지말것
- 그룹화하기 : 같은 저장 프로시저명에 ; 하고 숫자를 매김

CREATE PROCEDURE usp_withANumber;1
AS
[ T-SQL구문 ]
GO

CREATE PROCEDURE usp_withANumber;2
AS
[ T-SQL구문 ]
GO

* 다른 사용자의 접근막기위해서는 CREATE아래쪽에 WITH ENCRYPTION을 사용함
시스템뷰에서 저장프로시저의 텍스트가 나타나지 않음. 암호화된 저장프로시저의 내용은 다시 확인할수 있는 방법이 없음으로 암호화되기전의 저장프로시저를 잘 보관해야함



저장 프로시저의 수정

ALTER PROCEDURE 스키마. 저장프로시저명.
@ 매개변수 데이터 형식
AS
[ 변경된 SQL문 ]



저장 프로시저의 삭제

DROP PROCEDURE 스키마.저장프로시저명;



기본값을 지니는 매개변수의 사용과 output사용

CREATE PROCEDURE usp_withANumber
@EmployeeID INT = 10 <- EmployeeID에 기본값을 지정한 것
@outvalue int output <- outvalue에 output 변수를 쓰겠다는것
@currency_cursor CURSOR VARYING OUTPUT <- output 매개변수로 커서를 사용할때
AS
SELECT @outvalue = ManagerID <- 관리자 ID를 output 매개변수에 설정
FROM HumanResource.analysisDate
WHERE ManagerID = @ EmployeeID
GO

DECLARE @ManagerID INT; <- 저장프로시저 output 매개변수에 반환하는 값저장을 위한 지역변수선언

EXECUTE usp_withANumber 20, @ManagerID output <-반환되는값 조회

GO
2010/02/17 17:50 2010/02/17 17:50
MYSQL 테이블을 가변적으로 사용할때 쓰면 편리하다

SET
@table = 'mysql.user';
SET @host = '''%localhost%''';
SET @s = CONCAT('SELECT * FROM ', @table, ' WHERE host LIKE ', @host);
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

음..
2010/01/05 11:53 2010/01/05 11:53
원문 : http://www.oracle.com/technology/tech/linux/install/xe-on-kubuntu.html

1. 먼저 apt-get 저장소를 연다.
$ sudo gedit /etc/apt/sources.list
2. sources.list에 다음을 추가한다.
deb http://oss.oracle.com/debian unstable main non-free
3. 인증키를 얻고 오라클 XE를 설치한다.
$ wget http://oss.oracle.com/el4/RPM-GPG-KEY-oracle  -O- | sudo apt-key add -
$ sudo apt-get update
$ sudo apt-get install oracle-xe
 여기까진 쉽다. 만약에 설치 중에 스왑 파티션이 부족하다고 할 수 있다. 오라클 XE는 최소 1G이상의 스왑 파티션을 요구한다. 나는 이것 때문에 포맷을 두 번이나 하고 우분투를 설치했다. -_-;;
 
 근 데 원문 6번 글을 보면 스왑 파티션을 설정하는 방법이 나온다. 직접 해보지는 않았지만 원문 작성자도 별로 추천하지 않는단다. ㅡ.,ㅡ 그냥 포맷하고 반드시 수동으로 해서 스왑 파티션을 잡아준다. 1G라고 해서 1024이런 식으로 했다가는 또 다시 포맷해야하는 불상사가 생길 수 있다. 적당히 1200정도로 잡아줘야 이상 없다. 이것 때문에 두 번이나 다시 깔았다. ㅠ.ㅠ

4. 아무튼 스왑 파티션에 이상이 없으면 터미널에서 다음과 같이 실행하여 root 로 로그인 한다.
$ su -
 아마 패스워드를 입력하라고 할 것이다. 우분투를 처음 설치한 상황에서는 root의 비밀번호가 설정이 되어 있지 않다. 설정하는 방법은 간단하다.
$ sudo bash
# passwd
    또는
$ sudo passwd
 이 명령으로 root 계정 비밀번호를 설정하고 root로 로그인한다. root 비밀번호를 설정하지 않고 그냥 하려면 아래와 같이 입력하고 그 상태에서 작업한다.
$ sudo bash
    또는
$ sudo -i
5. 이제 root 권한 상태에서 다음 명령을 실행한다.
# /etc/init.d/oracle-xe configure
 그럼 아래와 같은 설정 화면이 나올 것이다.
Oracle Database 10g Express Edition Configuration
-------------------------------------------------
Specify the HTTP port that will be used for Oracle Application Express [8080]: Enter
Specify a port that will be used for the database listener [1521]: Enter

Specify a password to be used for database accounts. Note that the same
password will be used for SYS and SYSTEM. Oracle recommends the use of
different passwords for each database account. This can be done after
initial configuration: Enter

Confirm the password: 비밀번호 입력

Do you want Oracle Database 10g Express Edition to be started on boot (y/n) [y]: y

Starting Oracle Net Listener...Done
Configuring Database...Done
Starting Oracle Database 10g Express Edition Instance...Done    Installation Completed Successfully.
To access the Database Home Page go to "http://127.0.0.1:8080/apex"
6. 이제 설정이 끝났다. http://127.0.0.1:8080/apex 로 이동해서 Username은 "system", Password는 위에서 입력한 비밀번호로 로그인한다.



---- 여기서 부턴 웅자 --- config



난 server 기 때문에 로컬에서 접속이 불가능하다 -_-;; 장난하나 ;;;;
브라우져를 어케 까나;;;
결론은 외부로 접속을 시켜야되는데.
어쩔수 없이 sqlplus 를 쓰자고 생각했다.

** root 로 생각한다 **

*. 루트 쉘 환경변수 추가
# cd ~
# vi .bashrc
source /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh

*. 환경변수 설정
# cd /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin
# ./oracle_env.sh

*. 114: [[: not fount 에러시 쉘 변경
# vi nls_lang.sh
- 첫줄의 #!/bin/sh -> #!/bin/bash 로 변경

그리고 또 위와 같이 했는데
LC TYPE... 어쩌구 저쩌구 나오면

$ apt-get install language-pack-ko
$ locale-gen ko_KR.EUC-KR (root로)
$ dpkg-reconfigure locales
해서 재설정해주고. 해봐라 .. 난 됐다 ...
아참 root 에 .profile 에 LANG=C 이딴게 있는데 이거 다 주석 체크 해버려라.


1. oracle 계정에 .bash_profile , 그리고 /usr/sbin/apachectl 이부분에 .

아래와 같은 허접을 껴둔다.
# oracle path
source /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh
# oracle path end...

아차 맨위에는 무조건 #/bin/bash 를 선언해줘야 된다 . !

후에...

chmod -R 755 $ORACLE_HOME/sqlplus

chmod 755 $ORACLE_HOME/nls

chmod 755 $ORACLE_HOME/nls/data
chmod 744 $ORACLE_HOME/nls/data/*
chmod 755 $ORACLE_HOME/nls/data/lx1boot.nlb
chmod 755 $ORACLE_HOME/oracore
chmod 755 $ORACLE_HOME/oracore/zoneinfo
chmod 755 $ORACLE_HOME/oracore/zoneinfo/timezlrg.dat

이렇게 해주고!!!!

그리고 su - oracle 로 접속을 한뒤

sqlplus 오나클/비밀번호@XE or sqlplus system 후 비밀번호 치던지...
이렇게만 하면 잘 접속 된다.

==================================================================
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production
SQL> EXEC DBMS_XDB.SETLISTENERLOCALACCESS(FALSE); <= 이거 명령어다.

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL>
===================================================================

우왕ㅋ굳ㅋ 이제 외부에서 접속 가능 !
보안이 후달리니. 설정할때만 잠깐 올리고 다시 닫자 .
SQL> EXEC DBMS_XDB.SETLISTENERLOCALACCESS(TRUE);

자 ~ 외부에서 접속이 될꺼다 ~ ㅋㅋㅋ 아이피:8080/apex 우왕ㅋ굳ㅋ

그럼 ~~ 이번건은 php 에 연동해보자.


1. apt-get install 로 php-pear패키지와 php5-dev패키지를 설치한다.
2. pecl install oci8 한다. (난 /usr/lib/php5/20060613+lfs/oci8.so 여기에 생겨뜸...)
3. /etc/php5/apache2/php.iniextention=oci8.so 혹은 vi /etc/php5/conf.d/oracle.ini 하고 옆에 extention=oci8.so 추가해줘라...그리고 phpinfo(); 로 oci8관련된 항목이 있는지 확인한다.
4.난 이렇게 그냥 검사해봤당.

<?

   //echo PHPINFO();
    $db = "//127.0.0.1/xe";
    $c1 = ocilogon("system","비밀번호",$db);

    echo $c1;

    exit;
?>

잘나오던데 ;;; 난 연동 끝이었다.
2008/10/09 12:36 2008/10/09 12:36
오라클을 통해 작업할 시
insert시점에서 정상적으로 인덱싱이 되지 않는 경우가 발생한다.
특히 결합인덱스를 많이 사용하고 있는 경우 발생될 확률이 높다.
 
이런경우 오라클의 Analyzed를 통해서 해결이 가능하고
어느정도의 실행속도를 향상 시킬 수있다.
(실제 오라클사에서도 3개월에 한번씩은 Analyze를 실행하라 권고하고 있다.)
 
[Analyzed 확인 방법]
         select table_name, num_rows, to_char(last_analyzed, 'yyyymmdd') from user_tables
         select index_name, num_rows, to_char(last_analyzed, 'yyyymmdd') from user_indexes
 
ex) select table_name, num_rows, to_char(last_analyzed, 'yyyymmdd') from user_tables;
TABLE_NAME                       NUM_ROWS TO_CHAR(
------------------------------ ---------- --------
ABS_TYPE                               38 20040101
ANNIVERS                              183 20040101
APPRFLDRHISTORY                       570 20040101
APPRFOLDER                          16885 20040101
APPRFOLDER_ERR                       3670 20040101
APPRFORM                              359 20040101
.
.
.
USR_INFO_ADMIN                          0 20040101
VAR_DEPT_INFO                           0 20040101
VIEW_TYPE                               0 20040101
WASTEBOX                                0 20040101
ZIP_CODE                            44195 20040101
252 rows selected.
 
※ 참고 : desc user_tables 에서 보통 num_rows 로도 확인 가능
             
 
[특정 Table만 Analyze 하는 방법]
 
analyze table document compute statistics
ex) DOCUMENT Table 만 Analyze
 
analyze index xpkdocbox compute statistics
ex) XPKDOCBOX Index 만 Analyze
 
[전체 Table Analyze 하는 간단한 방법]
 
1. vi analyze_all.sql
    select 'analyze table || table_name || estimate statistics;' from user_tables
 
2. @analyze_all.sql
 
3. set heading off
     set echo off
     set feedback off
     set pagesize 300  (line 이 300 미만일 경우)
     spool analyze_table.sql
     /
     spool off
 
4. vi analyze_table.sql
    필요없는 Line 제거 및 정리
 
5. @analyze_table.sql
 
[전체 Index Analyze 하는 간단한 방법]
 
1. vi analyze_all.sql
    select 'analyze index || index_name || estimate statistics;' from user_indexes
 
2. @analyze_all.sql
 
3. set heading off
     set echo off
     set feedback off
     set pagesize 300  (line 이 300 미만일 경우)
     spool analyze_index.sql
     /
     spool off
 
4. vi analyze_index.sql
    필요없는 Line 제거 및 정리
 
5. @analyze_index.sql
2008/09/03 20:22 2008/09/03 20:22
안녕하세요.

원래 수줍어서 이런거 못올립니다만 .

다른분들이 해결방법을 찾으셧으면 해서 올립니다 .



전 img 및 script rpc 를 이용하여 값을 넘길때.

해당 페이지 or 받는 페이지가 utf-8 이면

받는페이지에서


------------------------------------------------------------------------------------

// 값이 아래와 같다면
$a = "http://comefeel.com/tt/comefeel/entry/윈도우XP-속도-200-빠르게-하기?info=nom&elch=18";

$b = parse_url($a);
echo "<pre>";
print_r($b);

------------------------------------------------------------------------------------

위와같이 한다면 한글 부분이 깨져서 나옵니다.
정확한 인코딩도 다 해봤으나 유효 불가해서 아래와 같이
그냥 -_- 무식하게 (parse_url 처럼 혹은 비슷 ) 나눠 봤습니다.

좀더 좋은 팁이 있거나 좋은거 알고계신분은 정보 공유 합시다.


======================================

// 값이 아래와 같다면
$a = "http://comefeel.com/tt/comefeel/entry/윈도우XP-속도-200-빠르게-하기?info=nom&elch=18";

preg_match('@(^.*):\/\/(.*?)/([^?]*)\??(.*)@', $a, $matches);

 echo "<pre>";
 var_dump( ($matches) );

=======================================
2008/07/11 19:27 2008/07/11 19:27

1. 테이블 생성
CREATE TABLE `TranTest` (
`num` int(11) NOT NULL auto_increment,
`col01` varchar(32) default NULL,
PRIMARY KEY (`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `TranTest2` (
`num` int(11) NOT NULL auto_increment,
`col01` varchar(32) default NULL,
PRIMARY KEY (`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 입력 용 프로시저 생성
CREATE PROCEDURE `Prc_TranTest_Input`
(
in in_col01 varchar(32)
)
BEGIN
INSERT INTO TranTest SET col01 = in_col01;
END;

3. SELECT 용 프로시저 생성
CREATE PROCEDURE `Prc_TranTest_Select`
(
in in_col01 varchar(32)
)
BEGIN
SELECT num, col01 FROM TranTest WHERE col01 like concat(in_col01, ‘%’) ;
END;

4. Transaction 용 프로시저 생성
CREATE PROCEDURE `Prc_TranTest_InError`
(
)
NOT DETERMINISTIC
SQL SECURITY DEFINER
COMMENT ”
BEGIN
DECLARE dbErr int default 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET dbErr = -1;
START TRANSACTION;
INSERT INTO TranTest SET col01 = ‘1234′;
INSERT INTO TranTest2 SET col012 = ‘1234′; //일부러 에러값을 내기위해 칼럼명을 다르게 적습니다.
IF dbErr < 0 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END;

5. PHP 를 이용하여 SELECT 및 입력하기
$mysqli = new mysqli(”localhost”, “USERID”, “USERPW”, “USERDB”);
if (mysqli_connect_error()) {
printf(”Connect Failed : %s\n”, mysqli_connect_error());
exit;
}
$mysqli->query(”set names utf8″);

//SELECT
if($qry = $mysqli->query(”Call Prc_TranTest_Select(’123′)”)) {
$rs = $qry->fetch_object();
echo $rs->col01;
}

//INSERT TranTest;
$mysqli->query(”Call Prc_TranTest_InError()”);

2008/02/18 16:17 2008/02/18 16:17
저 렴한 광랜의 등장과 대용량 하드디스크 가격의 하락, 그리고 Adobe 사의 플래시 플레이어(Flash Player), 플래시 비디오(Flash Video)의 등장으로 인터넷을 통한 비디오 공유가 정말 많이 보편화 되었습니다. 구글 비디오(http://video.google.com)와 YouTube(http://www.youtube.com)가 이미 이런 비디오 사업을 시작한지 오래됐지만, 여전히 공략할 수 있는 틈새 시장이 굉장히 많이 있다고 할 수 있는데, 그럼 우리도 한 번 틈새 시장을 공략해 보면 어떨까? PHP, 플래시, Adobe의 Flex를 이용해서 어떻게 하면 비디오 공유 사이트를 만들 수 있을까? 사실 알고보면 정말 쉽게 만들 수 있습니다.

여기서는 PHP를 이용해서 웹 사이트를 만드는 방법 그리고 Flex를 이용해서 Flash로 된 비디오 뷰어를 만드는 방법에 대해서 설명을 하겠습니다. 그럼 먼저 더 진행하기 전에 준비해야 하는 소프트웨어 몇 가지를 살펴보도록 하죠.

우선 서버쪽에서는 PHP와 MySQL이 필요합니다. MySQL은 비디오에 대한 정보(예를 들면, 비디오의 파일 이름, 미리보기 파일, 미리보기 파일의 너비와 높이, 제목, 그리고 기타 정보 등)를 저장하는데 사용되겠습니다. PHP는 전체적인 페이지를 구성하는데 사용되게 됩니다.

그리고 ffmpeg(http://ffmpeg.mplayerhq.hu/) 이라고 하는 유틸리티 프로그램도 필요한데요, 이 프로그램은 유저가 올리는 비디오 파일을 플래시 비디오 파일(FLV)로 변환하는 역할을 수행하게 됩니다. ffmpeg은 비디오의 변환외에도 비디오의 스냅샷을 찍어서 미리보기 파일을 만들어 낼 수도 있습니다. 이 ffmpeg을 이용하게 되면 사실상 어려운 작업을 손쉽게 처리할 수가 있어서 우리가 MyTube를 구현하는데 상당히 유용하게 활용이 됩니다.

클라이언트쪽에서는 두 가지 방법이 있는데요. 하나는 YouTube에서와 같이 HTML과 Flash를 같이 이용해서 인터페이스를 구성하는 방법이 있고, 두 번째로 플래시만으로 인터페이스를 구성하는 방법이 있습니다. 이 글에서는 Flex 프레임워크를 이용해서 비디오를 보고 등록된 비디오를 탐색하고 찾기 위해서 리스트를 생성하도록 할 예정입니다.

PHP로 서버쪽 코드 구성하기

서버쪽 코드 작성을 하기에 앞서, MySQL에 데이터 스키마를 생성해야 합니다. 우선 사용할 데이터베이스를 생성하기 위해서, 다음과 같이 mysqladmin 명령어를 사용합니다.
mysqladmin create movies 
스키마가 생성되었으면 데이터베이스를 로드합니다. 스키마 파일은 아래 [리스트 1]과 같습니다.

[리스트 1] movies.sql
DROP TABLE IF EXISTS movies; 
CREATE TABLE movies (
movieId INTEGER NOT NULL AUTO_INCREMENT,
title VARCHAR( 255 ),
source VARCHAR( 255 ),
thumb VARCHAR( 255 ),
width INTEGER,
height INTEGER,
PRIMARY KEY( movieId )
);
이제 위의 movies.sql 스키마 파일을 다음과 같은 명령어를 이용해서 데이터베이스에 테이블을 생성할 수 있습니다.
mysql movies < movies.sql 
데이터베이스에 무비 데이터를 넣기 위해서는 HTML을 이용해서 업로드 기능을 만들어야 합니다. 즉 비디오 파일을 받아서 플래시 비디오 파일로 변환하고 미리보기 파일을 만든후에 데이터베이스에 넣으면 되겠습니다.

업로드 페이지의 제작

비디오 파일을 업로드 하기 위한 HTML 파일은 다음 [리스트 2]에서 보는 것과 같이 아주 간단합니다.

[리스트 2] addmovie.html
<html>
<body>
<form enctype="multipart/form-data" method="post" action="upload.php">
<input type="hidden" name="MAX_FILE_SIZE" value="300000" />
<table>
<tr><td>Title</td><td><input type="text" name="title"></td></tr>
<tr><td>Movie</td><td><input type="file" name="movie"></td></tr>
</table>
<input type="submit" value="Upload" />
</form>
</body>
</html>
위 HTML은 입력받은 정보를 upload.php 페이지로 전송하게 되는데, 이 페이지에서 비디오를 변환하고 미리보기를 만들어 내고 데이터베이스에 저장하게 되는 것입니다. 다음의 upload.php 코드를 보도록 하겠습니다.

[리스트 3] upload.php
<html><body>
<?php
require "DB.php";

function converttoflv( $in, $out )
{
unlink( $out );
$cmd = "ffmpeg -v 0 -i $in -ar 11025 $out 2>&1";
$fh = popen( $cmd, "r" );
while( fgets( $fh ) ) { }
pclose( $fh );
}

function getthumbnail( $in, $out )
{
unlink( $out );
$cmd = "ffmpeg -i $in -pix_fmt rgb24 -vframes 1 -s 300x200 $out 2>&1";
$fh = popen( $cmd, "r" );
while( fgets( $fh ) ) { }
pclose( $fh );
}

function flv_import( $upfile, $fname, $title )
{
$fname = preg_replace( '/..*$/', '', basename( $fname ) );
$flvpath = "$fname.flv";
$thumbpath = "$fname.gif";

converttoflv( $upfile, "movies\$flvpath" );
getthumbnail( $upfile, "movies\$thumbpath" );

$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }

$sth = $db->prepare( 'INSERT INTO movies VALUES ( 0, ?, ?, ?, ?, ? )' );
$db->execute( $sth, array( $title, $flvpath, $thumbpath, 300, 200 ) );
}

flv_import( $_FILES['movie']['tmp_name'], $_FILES['movie']['name'], $_POST['title'] );
?>
File sucessfully uploaded
</body></html>
위 코드에서 flv_import 함수를 중점적으로 봐야 합니다. flv_import 함수내에서 converttoflv 함수로 비디오 파일을 플래시 비디오 파일로 변경하고 있고, getthumbnail 함수로 미리보기 파일을 생성하고 있습니다. 그리고 다음으로 업로드가 완료된 무비에 대한 정보를 데이터베이스에 저장합니다. 위 리스트 3에 있는 FLV 플래시 비디오 파일과 미리보기 파일을 생성하는 함수는 ffmpeg 라는 명령어와 여러가지 명령어를 이용해서 변환을 수행하게 됩니다.

그럼 다음 [그림 1]처럼 addmovie.html 페이지를 브라우저로 한 번 보도록 하겠습니다.


[그림 1] 비디오를 업로드하는 페이지

여기서 비디오 파일을 지정하고 Upload 버튼을 눌러서 비디오 파일을 처리하기 위해 서버에 보낼 수가 있습니다.

사 실 upload.php 파일은 아주 기본적인 부분만 작성이 되어 있기때문에, 실제 서비스 용도로 사용하기 위해서는 에러 체크 루틴을 추가 적으로 작성해야 합니다. 그리고 그것보다도 더 큰 문제는 크기가 큰 비디오 파일을 업로드 하려고 할 때인데, 이런 경우에는 파일의 크기가 크기 때문에 비디오 변환 과정이 오래 걸리게 되고 유저의 대기시간이 상당히 길어지면서 더 큰 문제가 됩니다.

그럼 이런 문제를 해결하기 위한 방법은 뭐가 있을까요? 한 가지 방법으로 큰 크기의 비디오 파일이 업로드가 되면(10초 이상의 비디오 파일) 유저에게는 잠시 후에 비디오가 게시될 것이라고 말을 해 놓고 서버내의 다른 폴더에 비디오 파일을 저장한 후에 또 다른 스크립트를 이용해서 비디오를 변환하는 것입니다.

더 진행하기 전에 왜 꼭 플래시 비디오 파일로 변환을 해야 하는지에 대해서 생각을 해보도록 합시다. 그냥 원본 그대로 저장해도 되는데 왜 플래시 비디오로 변환을 하려고 하는 걸까요? 그건 원본 상태로 저장을 해 놓게 되면 각 비디오 파일의 타입 별로 비디오 플레이어를 찾아서 수행할 수 있는 코드를 작성을 해야만 하기 때문에, 굉장히 힘든 일이 될 것이라고 생각합니다.

이 과정을 플래시 파일로 변환하여 해결하게 되면 코드도 간단해지고 많은 OS에서 실행될 수 있도록 할 수도 있습니다.

그럼 이제 HTML과 플래시를 이용해서 유투브와 같은 입력양식을 간단하게 만들어 보겠습니다.

HTML과 플래시를 이용한 인터페이스 구성

입 력받은 URL을 가지고 플래시 비디오 파일을 재생하는 프로그램을 만들기 위해서는 Adobe Flex Builder 2를 이용해서 새로운 프로젝트를 만들어야 합니다. 새로운 프로젝트를 생성했다면 simplemovie.mxml 이라는 Flex 애플리케이션을 만들어야 합니다. 이 애플리케이션 파일의 내용은 다음 [리스트 4]와 같습니다.

[리스트 4] simplemovie.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:VBox backgroundColor="white" width="400" height="335">
<mx:VideoDisplay width="400" height="300" id="videoPlayer"
source="{Application.application.parameters.movie}" />
<mx:HBox width="100%" horizontalAlign="center">
<mx:Button label="Play" click="videoPlayer.play()" />
</mx:HBox>
</mx:VBox>
</mx:Application>
위 [리스트 4]에서 두가지 중요한 요소를 볼 수 있습니다 : VideoDisplay 요소는 비디오를 재생하는 역할을 하고 "Play"라는 이름을 가진 버튼은 비디오의 재생이 끝난 후에 유저가 클릭할 경우 비디오를 다시 재생하는 역할을 하게 됩니다.

VideoDisplay 요소는 "source"라는 속성을 가지게 되는데요, source 속성으로 재생해야 하는 플래시 비디오 파일의 URL을 지정하게 됩니다. 위 리스트에서 source 속성이 가지고 있는 값은 HTML 파일에 있는 <object>나 <embed> 태그에 있는 FlashVars 속성의 값이 되게 됩니다.

Flex Builder를 이용하게 되면 위 [리스트 4]의 simplemovie.mxml 프로그램을 simplemovie.swf 파일로 변환할 수가 있고, 변환된 swf 파일을 bin 디렉토리에서 PHP가 있는 곳의 디렉토리로 이동시켜야 합니다. 그리고 PHP 페이지를 하나 만들어서 비디오를 재생시킬 수가 있습니다. 다음 [리스트 5]를 보도록 하죠.

[리스트 5] simpletest.php
<?php
require "DB.php";

$moviebase = 'http://localhost:8080/movies/';

$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }

$source = null;
$movieId = 1;
if ( array_key_exists( 'movie', $_GET ) )
$movieId = $_GET['movie'];

$movies = array();
$res = $db->query( 'SELECT movieId, source, title FROM movies' );
while( $row = $res->fetchrow( ) ) {
$movies []= $row;
if ( $row[0] == $movieId )
$source = $row[1];
}

if ( $source == null )
$source = $movies[0][1];
?>
<html>
<body>
<table>
<tr><td valign="top">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="400"
height="335"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="simplemovie.swf" />
<param name="quality" value="high" />
<param name="flashVars" value="movie=<?php echo( $moviebase.$source ) ?>">
<embed src="simplemovie.swf" quality="high"
width="400" height="335" play="true"
loop="false"
quality="high"
flashVars="movie=<?php echo( $moviebase.$source ) ?>"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>
</td><td valign="top">
<?php
foreach( $movies as $movie ) {
?>
<a href="simptest.php?movie=<?php echo( $movie[0] )?>"><?php echo( $movie[2] )?></a><br/>
<?php
}
?>
</td></tr></table>
</body>
</html>
위 PHP 스크립트는 우선 데이터베이스에 접속한 후에 비디오 리스트를 받아오고 있습니다. 그리고 나서 URL을 통해서 넘어온 ID와 읽어온 비디오 리스트를 비교해서 동일한 ID를 가진 비디오가 있는지를 확인하게 됩니다. 동일한 ID를 찾을 경우 이 ID 값을 simplemovie.swf 파일로 넘기기 위해서 flashVars 속성에 지정하고 있습니다.

PHP 스크립트 다음 부분에서는 HTML 태그가 시작되고 simplemovie.swf 파일을 페이지에 표시하기 위한 태그인 <object>, <embed> 태그를 사용하고 있습니다. 물론 여기에 재생해야 하는 비디오에 대한 URL도 지정해 주고 있는 걸 볼 수 있습니다. 그리고 바로 아래에 현재 비디오외에 볼 수 있는 비디오에 대한 링크를 만들어 주고 있는 걸 볼 수 있습니다.

이제 웹 브라우저에서 [리스트 5]에 있는 페이지를 한 번 보도록 하겠습니다. 다음 [그림 2]와 같이 나오네요.


[그림 2] 간단한 비디오 플레이어와 함께 볼 수 있는 비디오에 대한 리스트가 출력되었다.

웹 브라우저를 열자마자 첫번째 비디오가 재생이 되게 되고, 오른쪽에 있는 비디오 리스트중에서 하나를 선택하면 페이지가 다시 로딩되면서 선택된 비디오가 재생되게 됩니다.

정말 간단하죠? Flex 파일 하나와 PHP 파일 하나, 그리고 데이터베이스만 가지고 위와 같이 비디오 공유 사이트를 만들었습니다.




Flex를 이용한 인터페이스 구성 파트 1


Flex 를 이용해서 원하는 비디오를 재생시키기 위해서는 Flex에게 재생시킬 수 있는 비디오의 리스트를 알려줘야만 합니다. 어떻게 해야하냐면 XML파일을 이용해서 Flex에게 비디오 리스트 정보를 넘겨줄 수가 있는데요, 여기서는 PHP로 다시 돌아가서 데이터베이스에서 비디오 리스트를 읽어들인 후에 XML로 출력하는 스크립트를 만들어 보도록 하겠습니다. 다음 [리스트 6]의 movies.php 파일을 보도록 하죠.

[리스트 6] movies.php
<?php
require "DB.php";

$moviebase = 'http://localhost:8080/movies/';

header( 'content-type: text/xml' );

$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }
?>
<movies>
<?php
$res = $db->query( 'SELECT title, source, thumb, width, height FROM movies' );
while( $row = $res->fetchrow( ) ) {
?>
<movie title="<?php echo( $row[0] ) ?>" source="<?php echo( $moviebase.$row[1] ) ?>"
thumb="<?php echo( $moviebase.$row[2] ) ?>" width="<?php echo( $row[3] ) ?>"
height="<?php echo( $row[4] ) ?>" />
<?php
}
?>
</movies>
위 PHP 스크립트를 만든 후에 커맨드 라인에서 실행시키거나 브라우저에서 실행시키게 되면 다음 [그림 3]과 같은 XML 리스트를 볼 수가 있습니다.


[그림 3] XML로 표현된 비디오 리스트

이제 XML로 비디오 리스트 정보를 넘겨줄 수 있으니 전에 만들었던 simplemovie.mxml 파일을 좀 더 개선해 보도록 하겠습니다. 다음 [리스트 7]은 simplemovie.mxml의 업그레이드 된 버전입니다.

[리스트 7] mytube1.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="movieXmlData.send()">

<mx:HTTPService method="get" url="http://localhost:8080/movies.php"
id="movieXmlData" result="onGetMovies( event )" />

<mx:Script>
import mx.rpc.events.ResultEvent;
import mx.controls.VideoDisplay;
import mx.controls.List;
import mx.rpc.http.HTTPService;
import mx.collections.ArrayCollection;

[Bindable]
private var movies : ArrayCollection = new ArrayCollection();

public function onGetMovies( event : ResultEvent ) : void
{
var firstMovie : String = event.result.movies.movie[0].source.toString();
videoPlayer.source = firstMovie;

movies = event.result.movies.movie;
movieList.selectedIndex = 0;
}

public function onPrevious() : void
{
if ( movieList.selectedIndex == 0 )
movieList.selectedIndex = movies.length - 1;
else
movieList.selectedIndex -= 1;
videoPlayer.source = this.movieList.selectedItem.source.toString();
}

public function onPlay() : void
{
videoPlayer.source = this.movieList.selectedItem.source.toString();
videoPlayer.play();
}

public function onNext() : void
{
if ( movieList.selectedIndex >= ( movies.length - 1 ) )
movieList.selectedIndex = 0;
else
movieList.selectedIndex += 1;
videoPlayer.source = this.movieList.selectedItem.source.toString();
}

public function onChange() : void
{
videoPlayer.source = this.movieList.selectedItem.source.toString();
}
</mx:Script>

<mx:HBox width="100%" paddingLeft="10" paddingTop="10" paddingRight="10">
<mx:VBox>
<mx:VideoDisplay width="400" height="300" id="videoPlayer" complete="onNext()" />
<mx:HBox width="100%" horizontalAlign="center">
<mx:Button label="<<" click="onPrevious()" />
<mx:Button label="Play" click="onPlay()" />
<mx:Button label=">>" click="onNext()" />
</mx:HBox>
</mx:VBox>
<mx:List width="100%" height="340" id="movieList"
dataProvider="{movies}"
change="onChange()"
labelField="title"></mx:List>
</mx:HBox>

</mx:Application>
전과 비교해서 크게 바뀐 부분이 있다면 파일의 상단에 있는 액션 스크립트(ActionScript)인데요, 이 코드로 전체적인 인터페이스를 관리하게 됩니다. 이 액션 스크립트가 하는 일은 먼저 onGetMovies 함수에 있는 HTTPService를 이용해서 movies.php 파일로부터 XML 정보를 읽어들이는 것입니다. HTTPService 클래스는 XML 리스트를 찾게 되면 XML 문서 객체모델(Document Object Model)로 변경하게 되고, 우린 이 문서 객체 모델을 이용해서 첫번째 비디오에 대한 정보를 얻어서 재생할 수가 있습니다. 또 onGetMovies 함수는 movies 라는 변수를 이용해서 페이지에 있는 리스트 박스에 비디오의 이름을 출력하게 됩니다. 나머지 액션 스크립트는 유저가 리스트 박스에 있는 비디오를 선택하거나 "이전", "다음" 버튼을 선택했을 경우를 처리하기 위한 코드입니다.

위 리스트의 제일 아래를 보면 전체 유저 인터페이스를 구성하는 Flex 오브젝트를 볼 수 있습니다. 여기에 이전 비디오와 다음 비디오를 선택할 수 있는 버튼을 배치하고, 오른쪽에는 현재 비디오 리스트를 출력하는 리스트 박스가 배치되어 있습니다.

이제 Flex Builder를 이용해서 위 프로그램을 컴파일하고 실행시키게 되면 [그림 4]와 같은 화면을 볼 수 있습니다.


[그림 4] Flex를 이용해서 구성한 첫 번째 인터페이스

리스트 박스에서 비디오를 선택할 수도 있고, 이전, 다음 버튼을 이용해서 비디오를 선택할 수도 있습니다. 멋있죠? 이제 미리보기 이미지를 제공해 주면 더 멋있어질 것 같네요.

Flex를 이용한 인터페이스 구성 파트 2 – 미리보기 이미지

미 리보기 이미지를 비디오 리스트에 출력하려면 리스트 박스를 비디오의 제목과 미리보기 이미지를 같이 출력할 수 있도록 수정해야 합니다. 다행히도 Flex의 기능을 이용하면 아주 쉽게 수정이 가능합니다. 우선 <List> 태그에 itemRenderer를 추가하도록 하고, 다음 [리스트 8]을 보겠습니다.

[리스트 8] mytube2.mxml
...
<mx:List width="100%" height="340" id="movieList"
dataProvider="{movies}"
change="onChange()"
itemRenderer="MovieItem"></mx:List>
...
여기서 MovieItem이라는 item renderer MXML 컴포넌트를 만들었습니다. 이 컴포넌트를 만들려면 메뉴에서 "New > MXML Component"를 선택하고 [리스트 9]와 같이 컴포넌트를 코드에 넣으면 됩니다.

[리스트 9] MovieItem.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" height="80">
<mx:Image source="{data.thumb}" width="{data.width/3}"
height="{data.height/3}" rotation="5" left="10" top="0" />
<mx:Label text="{data.title}" fontWeight="bold" top="10" left="100" fontSize="18" />
</mx:Canvas>
여기서는 Canvas 라는 컨테이너를 이용했지만, 원한다면 마음에 드는 컨테이너를 선택해서 설정하셔도 괜찮습니다. 그리고 나서 미리보기 이미지 추가를 위해서 <mx:Image> 태그를 사용하고 비디오 제목을 출력하기 위해서 <mx:Label>을 이용하면 됩니다. 좀 더 재밌게 해보기 위해서 미리보기 이미지를 약간 회전시켜 봤습니다. [그림 5]를 보도록 하죠.


[그림 5] 미리보기 이미지를 추가한 리스트 박스

꽤 괜찮은 비디오 플레이어가 됐네요. 여기에 추가적으로 비디오 설명, 재생 시간, 링크, 추천 버튼과 같은 기능을 추가하면 더 좋을 것 같습니다.

저장소와 대역폭

데 이터베이스를 구성하고 비디오 공유 사이트 페이지를 만들어 내는것 자체는 지금까지 잘 해결했는데, 사실 이것말고 한가지 더 고려해야 할 것이 있습니다. 바로 대역폭을 고려해야 합니다. 플래시 비디오 파일 자체가 인코딩이 잘 된다고 해도 역시 비디오 파일이기 때문에 크기가 큰 편에 속하게 됩니다. 그렇기 때문에 중간에 끊김없이 비디오 재생을 얼마나 할 수 있는지 파악하는 것이 무엇보다 중요하게 됩니다.

확실한 방법중 하나는 인터넷 데이터 센타에서 서비스를 하는 것입니다. 다른 방법으로는 비디오 공유 사이트에서는 비디오 자체에 대한 데이터를 가지지 않고 링크만 저장하고 실제 비디오 데이터는 다른 곳에 저장하는 방법입니다. 아마존의 S3 서비스 같은 경우가 좋은예인데요, 저렴한 가격으로 좋은 저장소로 활용할 수가 있고, 어느정도 사이트가 커질때까지는 안정적으로 활용할 수 있습니다.

결론

플래시를 이용한 비디오의 등장과 광대역폭의 보편화로 인해서 이제 적은 예산으로 비디오 공유 사이트를 운영한다는 것이 현실로 다가왔습니다. 바라기는 이 글을 통해서 여러분이 좀 더 멋있는 비디오 공유사이트를 만들어냈으면 하는 것입니다.
2007/12/26 16:16 2007/12/26 16:16

1. 사용자 인증의 단일 창구 SSO

 가. SSO(Single Sigh On)의 개념

  - 사용자가 한 개의 ID, PASSWORD로 여러 응용시스템을 접근할 수 있는 기술

 나. SSO가 필요한 이유

  - 기업내 다양한 응용시스템 도입 및 운영에 따른 ID, PASSWORD 관리 복잡

  - 중앙집중적인 ID관리 및 시스템 권한관리를 통한 업무의 순화 및 표준화 실현


2. SSO의 요소기술과 EAM의 비교

 가. SSO의 특징

   1) 특징 : 단일의 ID, PASSWORD를 통한 다양한 시스템 접근 제공

   2) 구성요소 : 클라이언트/서버 Agent, SSO 인증서버, LDAP

   3) 주요기능 : 단일 로그인, 표준화된 인증 접근방법, 중앙집중식 접근관리 가능

   4) 구현방식 : 쿠키방식, 웹방식, PKI인증서 이용방식


 나. EAM(Enterprise Access Management)와 SSO의 비교

비교항목 EAM SSO
목적 ID관리와 권한, 자원정책의 결합 중앙집중식 ID 관리
장점 자원접근시 권한까지 제어
개별응용레벨의 권한제어
단일 ID 로 사용의 편리성
인증정책과 권한설정이 용이
단점 사용자/자원별 권한관리 어려움
고가 및 구현의 복잡성
ID, PASSWORD노출시 전체시스템 위험
자원별 권한관리 미비


3. SSO 적용시 고려사항 및 활용

 가. 단일 ID, PASSWORD 사용으로 노출시 기업전체의 보안위협이 되므로 개인의 철저한 ID,

       PASSWORD관리와 병행하여 ONE-TIME PASSWORD 정책이 필요함

 나. PKI 기반의 SSO 단순성 탈피위해 PMI(Previlege Management Infrastructure) 의 AC(Attribute

       Certificate) 인증서 사용하고 , 향후 EAM 도입이 필요함.

EAM 시스템과 요구 사항

연·재·목·차

제1회 EAM 시스템과 요구 사항
제2회 SSO 모델과 보안 기술
제3회 SSO·RBAC 표준화 동향


기업의 IT 인프라와 자산에 대한 통합화 및 관리 그리고 통제에 대한 관심이 증대되고 있다. 단순한 사내망에 불과하던 기업 IT 인프라가 직원, 고객, 파트너 등으로 사용자가 확대되면서 다양한 서비스를 요구받기 때문이다. 모든 기업들은 회사의 자원을 보호하고 자원에 대한 접근 권한을 관리함으로써 이러한 복잡한 문제들을 해결하길 바라고 있다. 이러한 기업의 요구에 부합하는 기술적 트렌드를 3회에 걸쳐 연재한다.

강신범 | 소프트포럼 기반기술개발실장


EAM(Extranet Access Management) 시스템은 인트라넷·익스트라넷 서비스를 동시에 수행하는 현재의 기업 IT 인프라 시스템을 안전하게 구성하고 효율적인 관리를 수행할 수 있는 환경 제공을 목적으로 한다.

EAM 시스템에 대한 이해를 돕기 위해 먼저 기업 내 IT 인프라를 EAM 시스템으로 통합하는 시나리오를 간단히 기술하고, 이 시나리오에 근거해서 EAM 시스템의 요구사항을 보안 a기술 측면에서 살펴본다.


EAM 시스템

현재 그룹웨어, 인사관리(HR) 시스템 그리고 전사적자원관리(ERP) 시스템을 운영하고 있는 회사의 경우 각 애플리케이션 별로 각각의 사용자 계정과 권한 관리를 위한 자원이 투입돼 운영된다. 이는 부가적인 관리를 필요로 함은 물론이고 획일적이고 통합되지 않은 상태의 시스템 운영으로 인한 다양한 부작용 및 보안적 결함을 드러내게 된다. 이와 같은 고민에 빠진 회사는 규모의 증대와 IT 인프라 확산에 비례해 보안적 결함이 점차 증가하게 된다. 또한 일정 시일 이후에는 EAM 시스템 도입 비용을 상회하는 기존 시스템의 운영비용으로 인한 손실분을 안게 되는 최악의 상황에까지 몰리게 된다.

이같은 회사가 EAM 시스템을 도입하게 되었을 경우에 회사 내부에서 사용되는 그룹웨어, HR, ERP를 EAM 시스템으로 통합하고 각 애플리케이션별로 개별적으로 관리되던 사용자 계정, 권한관리시스템까지도 단일화된 EAM 시스템에서 통합 관리하게 된다. 이 작업으로 인한 회사의 IT 인프라는 다음과 같이 변경된다.

우선 사내 직원은 사용자 인증을 최초로 한번 받고, 각 애플리케이션을 SSO(Single Sign-On) 기술에 의해 추가 인증없이 사용할 수 있다. 또한 각 애플리케이션은 개인화 서비스를 통해 인증된 사용자의 정보를 얻어 동작에 적용한다.

개별 애플리케이션은 통합된 인가·접근제어 정책에 따라 사용자의 접근을 제어한다. 사내 IT 인프라 관리자는 EAM 관리시스템을 통해 각 애플리케이션별로 접근권한을 사용자에게 제어할 수 있다. 사용자가 통합 인증을 받고 각 애플리케이션에 접근하는 모든 감사정보를 EAM 시스템이 관리해 개별적으로 관리되던 감사정보를 통합해 관리할 수 있게 된다.


EAM 시스템의 요구사항

EAM 시스템은 적어도 다음과 같은 6가지 요구사항 항목을 가진다.

△인증(Authentication):

시스템에 접근하는 사용자를 확인한다. 일반적으로 ID/PWD 방식이 가장 널리 사용되며 보안성을 강화하기 위해 암호, PKI 기술들이 이용된다.

△SSO:

통합 인증된 사용자가 개별 애플리케이션에 추가적인 인증 요구 없이 사용할 수 있어야 한다.

△인가·접근제어(Authorization):

개별 애플리케이션의 각 자원 및 서비스에 대한 인가·접근제어 권한을 관리 툴로 설정하고, 설정된 인가·접근제어 권한이 개별 애플리케이션 동작에 적용이 돼야 한다.

△개인화(Personalization):

통합 인증된 사용자가 개별 애플리케이션에 접근할 때, 접근하는 사용자의 아이덴티티(Identity)와 사용자의 정보를 확인할 수 있는 기술이 제공돼야 한다.

△관리(Administration):

통합 인증을 위한 사용자 계정, 개별 애플리케이션의 인가·접근제어, 개인화를 위한 정보제공의 범위, 감사기능 등을 편리하게 관리할 수 있는 기능이 제공돼야 한다.

△감사(Auditing):

전체 시스템에 접근해 통합 인증을 받고 SSO으로 개별 애플리케이션에 접근, 인가·접근제어가 수행되는 모든 과정이 감사 기록으로 남아야 한다.

<그림> Extranet Computing 환경


인증(Authentication)

EAM 시스템의 요구사항에서 사용자 인증에 관련된 보안 기술은 전체 시스템의 보안성에 매우 중요한 부분을 차지한다. 이와 관련해 EAM 시스템에서 사용될 수 있는 다양한 인증방법 기술에 대해서 소개한다.

인증방법은 기본적인 ID/PWD 방식과 보안성이 상대적으로 높은 X.509 인증서, OTP(One Time Password), 생체인식으로 나뉘어 진다. 아래에서 설명하고 있는 인증 방법들은 일반적인 EAM 시스템에서 웹 환경에 적용하기 적합한 기술들이다.

△Basic ID/PWD:

HTTP/HTTPS 프로토콜의 BASIC Authentication 방법을 이용해 ID와 패스워드로 사용자를 인증한다. 이 인증 방법은 HTTP 프로토콜을 사용하는 경우 사용자가 입력한 ID와 패스워드가 네트워크를 통해 암호화되지 않고 전송된다. HTTPS 프로토콜을 이용하는 경우에는 암호화돼 전달된다.

△Digest Authentication:

HTTP/HTTPS 프로토콜의 Digest Authentica-tion 방법을 이용해 ID와 패스워드로 사용자를 인증한다. 이 인증방법은 패스워드가 평문으로 전달되지 않아 Basic ID/PWD 인증보다 향상된 보안 서비스를 제공하지만, 패스워드가 저장될 때 반드시 패스워드 원본 혹은 복호화될 수 있는 정보로 저장돼야 하기 때문에 서버에서의 패스워드 관리에 각별한 주의가 요구된다.

△Form Based Authentication:

Customized Form(HTML/JSP/ASP etc.)을 이용해 사용자를 확인한다. 폼에 입력되는 인증 정보는 사용자 ID/PWD 만으로 구성될 수도 있고 사용자 ID/PWD 이외의 다른 정보, 예를 들어 사용자 주민등록번호 등을 추가적으로 포함해 사용할 수 있다. 전달되는 정보의 암호화를 위해서는 HTTPS 프로토콜이나 기타 암호 제품을 사용할 수 있다.

△X.509 Client Certificate over SSL:

HTTPS 프로토콜의 사용자 인증서 인증 프로토콜을 이용해 인증한다. 인증서의 폐기 여부 확인을 위해 CRL 검증과 OCSP 검증 방법을 사용할 수 있다.

△One Time Password 인증:

한 번만 사용될 수 있는 패스워드를 이용해 사용자를 인증한다. 사용자에게 미리 전달된 OTP Token을 이용하여 사용자를 인증한다.

△생체 인식:

사용자의 지문이나 홍채 등을 이용해 사용자를 인증한다. 아직은 널리 사용되고 있지 않으나 지문 인식의 경우 그 영역이 확대되고 있는 추세이다.

지금까지 기업의 IT 인프라 관리를 위해 효율성과 보안성을 모두 만족시킬 수 있는 EAM 시스템에 대한 개념과 요구사항을 살펴봤다. 기업의 다양한 IT 시스템 운영에 있어서 보다 안전하고 저비용의 운영 방식을 원한다면 각 애플리케이션 별로 분산돼 있는 인증과 권한 관리 부분을 통합시켜 전사적인 관리가 가능한 EAM 시스템 도입을 고려해 봐야 한다.



연재/EAM·SSO 기술과 표준화 동향 ②

SSO 모델과 보안 기술

강신범
소프트포럼 기반기술개발실장

연·재·목·차

제1회 EAM 시스템과 요구 사항
제2회 SSO 모델과 보안 기술
제3회 SSO·RBAC 표준화 동향

SSO 모델

일반적으로 사용되는 SSO 시스템은 두 가지 모델로 구분된다. SSO 대상 애플리케이션에서 사용되는 사용자 인증 방법을 별도의 SSO 에이전트가 대행해주는 Delegation(인증 대행) 방식과 SSO 시스템과 신뢰관계를 토대로 사용자를 인증한 사실을 전달받아 SSO를 구현하는 Propagation(인증정보 전달) 방식으로 구분된다.

<그림 1> SSO Delegation Model

△Delegation 방식: 대상 애플리케이션의 인증 방식을 변경하기 어려울 때 많이 사용된다. 대상 애플리케이션의 인증 방식을 전혀 변경하지 않고, 사용자의 대상 애플리케이션 인증 정보를 에이전트가 관리해 사용자 대신 로그온 해주는 방식이다. 즉 Target Server 1을 로그온 할 때 User1이 alice/alice라는 ID/ PWD가 필요하다면, 에이전트가 이 정보를 가지고 있고, User1이 Target Service 1에 접근할 때 에이전트가 대신 alice/alice ID/PWD 정보를 전달해서 로그온 시켜준다. △Propagation 방식: 통합 인증을 수행하는 곳에서 인증을 받아 대상 애플리케이션으로 전달할 토큰(Token)을 발급 받는다. 대상 애플리케이션에 사용자가 접근할 때 토큰을 자동으로 전달해 대상 애플리케이션이 사용자를 확인할 수 있도록 하는 방식이다. 웹 환경에서는 쿠키(Cookie)라는 기술을 이용해 토큰을 자동으로 대상 애플리케이션에 전달할 수 있다. 이러한 웹 환경의 이점으로 웹 환경에서의 SSO는 대부분 이 모델을 채택하고 있다.

<그림 2> SSO Propagation Model

△Delegation & Propagation 방식: 웹 환경이라고 하더라도 Propagation 방식이 모두 적용될 수는 없다. 특히 웹 애플리케이션의 변경이 전혀 불가능하고 사용자 통합이 어려운 경우 Delegation 방식을 사용하게 된다. 또한 대상 애플리케이션들이 많이 있고 애플리케이션의 특성들이 다양한 경우 각 애플리케이션에 Delegation 방식과 Propagation 방식을 혼용해서 전체 시스템의 SSO을 구성한다.

△Web 기반 One Cookie Domain SSO: SSO 대상 서비스와 응용 애플리케이션들이 하나의 Cookie Domain안에 존재할 때 사용된다. 일반적인 기업 내부의 컴퓨팅 환경이다. 통합인증을 받은 사용자는 토큰을 발급받게 되고, 이 토큰은 Cookie Domain에 Cookie로 설정되어 Cookie Domain 내의 다른 서비스로 접근할 때 자동으로 토큰을 서비스에 제공하게 된다. 서비스에서 동작되는 SSO 에이전트는 토큰으로부터 사용자 신원을 확인하고 요청된 자원에 대한 접근을 허가 해준다.

Web 기반 Multi Cookie Domain SSO

SSO 대상 서비스와 응용 애플리케이션들이 여러 도메인으로 분산돼 있을 경우다. Multi Domain 환경인 경우에는 사용자 인증 및 토큰의 발행을 위한 마스터 에이전트가 존재한다.
마스터 에이전트는 각 서비스 에이전트의 사용자 인증을 위임받아 수행한다. 인증된 사용자에게는 토큰을 발급하고 각 서비스 에이전트에게 안전하게 전달한다. 또한 에이전트가 해당 토큰을 자신의 Domain에서 Cookie로 저장해 사용할 수 있도록 한다. 각 서비스 에이전트의 신뢰도 및 SSO 시스템의 보안 레벨에 따라 다음과 같이 두 가지 방식으로 서비스될 수 있다.

<그림 3> One Token for All Multi Cookie Domain

△One Token for All Multi Cookie Domain: 모든 도메인이 하나의 토큰을 공유한다. 모든 시스템은 서로 신뢰관계를 가져야 한다. 토큰이 하나만 사용되므로, 마스터 에이전트는 사용자 인증 및 각 도메인에 대한 토큰 제공에 대해서만 수행하게 돼 에이전트들의 관리 및 구성이 매우 간단하다. 하지만 모든 도메인들이 서로 신뢰관계를 가져야 한다는 제약사항으로 인해 적용대상이 제한적이다. 일반적으로 하나의 기업에서 운영하는 다중 도메인 서비스들을 SSO로 구성할 때 많이 사용된다.

<그림 4> One Token form each cookie domain & One Token for Master Agent

△One Token for each cookie domain & One Token for Master Agent: 마스터 에이전트와 각 도메인들이 각각 토큰을 가진다. 마스터 에이전트는 각 도메인의 에이전트들과 신뢰관계를 가지며, 각 도메인의 에이전트들 사이는 신뢰관계를 가지지 않는다. 마스터 에이전트는 각 도메인의 에이전트에게 전달할 사용자 토큰을 발행하므로, 에이전트들의 레벨이나 속성에 따라 토큰에 저장되는 사용자 정보의 양을 조절할 수 있다. 토큰이 각 도메인 별로 발행되므로, 도메인별 Replay Attack 등에 대한 취약성이 전체 시스템에 영향을 주지 않는다.

SSO 보안 기술

토큰은 쿠키를 통해 전달되므로 외부에 노출되는 정보이다. 완벽한 보안을 위해서는 토큰이 네트워크에서 노출되어서는 안되지만, 비용 및 관리상의 이유로 허용되고 있다. 하지만 토큰을 통해 토큰이 포함하고 있는 정보까지 외부에 노출하는 것은 심각한 결함을 제공한다. 토큰의 네트워크 구간에서의 정보 노출 및 위·변조를 방지하기 위해 다음과 같은 보안기술이 사용된다.

△Data Confidentiality: 토큰은 주요 암호 알고리즘(AES, SEED)과 128bit 이상의 키로 암호화돼 보호되어야 한다. △Data Integrity: 토큰은 MAC

(Message Authentication Code) 등을 포함해 데이터의 무결성을 보장해야 한다. △Replay Attack Protection: 토큰은 사용자와 대상 애플리케이션 사이에 전달되는 인증 정보이다. 일반적으로 토큰은 네트워크에 노출되며, 노출된 토큰을 사용해 다른 사용자가 인증을 받고 들어올 수 있다(Replay Attack). 특히 웹 환경에서 이러한 문제점이 중요한 이슈로 등장하고 있다. 이러한 문제점을 근본적으로 해결하기 위해서는 토큰을 네트워크에 노출시키지 않아야 한다.
토큰을 네트워크에 노출시키지 않기 위해서는 항상 사용자와 대상 애플리케이션 사이에 암호 채널을 형성해야 하며, 이 채널을 통해 토큰을 전달해야 한다. 그러나 SSL과 같은 채널 암호를 사용하는 데에는 매우 많은 비용이 요구되어 실제로 많이 사용되고 있지는 않다.
SSL과 같은 암호채널을 사용하지 않으면서 Replay Attack이 발생할 수 있는 상황을 줄일 수 있도록 다음과 같은 보안 기술들이 사용된다.

△사용자 주소 제한: 토큰이 발행될 때 접속한 사용자 주소 정보를 토큰 내부나 토큰을 발행한 서버에서 기억함으르써 Token이 제출된 사용자 주소와 최초 발행시 기억된 주소를 비교하여 접속한 곳 이외에서의 접속을 제한할 수 있다. 사용자 주소가 업무진행 중에 자주 변경되지 않는 시스템일 경우 유효하다. 예를 들어 회사내의 인터넷 환경일 경우 사용될 수 있다. 인터넷 환경의 경우에는 사용자 주소가 특정 범위에서 자주 바뀔 수 있는 환경도 있기 때문에 불특정 다수를 위한 일반적인 인터넷 서비스에 사용하기에는 부적합하다.

△유효시간 제한: 토큰의 유효시간을 매우 짧게 줌으로써 Replay Attack에 사용될 수 있는 시간을 제한한다. 유효시간내에 임계시간(예: 유효시간의 1/2)을 넘으면 자동으로 토큰을 재 발행하여 사용자는 의식하지 못하고 서비스를 계속 사용하게 한다. 지금까지 사용자가 각 애플리케이션별로 별도의 인증을 받지 않고, 한번의 통합 인증만으로 각 애플리케이션들을 사용할 수 있도록 하는 SSO 기술에 대해 살펴보았다. 대상 애플리케이션의 수정을 최소화할 수 있는 Delegation 모델과 토큰을 생성해 통합 인증 서비스를 제공하는 Propagation 모델 그리고 양자의 장점을 조합한 Delegation & Propagation 방식을 이해한다면 현재 도입 대상 기업의 IT 인프라와 진행중인 서비스 및 애플리케이션의 특성에 적합한 EAM 시스템 도입을 결정하는데 도움이 될 것이다.

EAM·SSO 기술과 표준화 동향

제3회 SSO·RBAC 표준화 동향

2007/10/11 16:27 2007/10/11 16:27

출처 :

http://comeng.andong.ac.kr/%7Echi23/bbs/view.php?id=downdoli_db&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=hit&desc=desc&no=2

 

보통 my-sql에서는 PK로 잡고 auto-increment를 많이 사용하는데
이를 오라클 DB로 마이그레이션 하면서 다음과 같이 한다.....

원본 my-sql 쿼리:
select no, gno, ono, nested, id, name, title, registerDate, readno ]
from tableName
order by gno desc, ono asc limit 0, 15

오라클로 변환된 쿼리
select *
from (select a.*,rownum rnum from
(select * from table_notice order by gno desc, ono asc) a)
where rnum >  페이지당 리스트 수* ( 원하는페이지 번호 - 1) and rownum <= 페이지당 리스트 수

rownum으로 번호를 매기는 것이 order by보다 우선 순위가 높단다.
그리고 위의 방식 말고도 인덱스를 이용한 방법도 있는데..

뭐 이것도 쓸만하지만 더 쓸만한건 ;;;; 내가 품고 이찌롱 ^_^

2007/09/27 17:41 2007/09/27 17:41
Tags:
출처 블로그 > The Secret To Success Is To Never Give Up
원본 http://blog.naver.com/nkmin80/140032103146

※ 인덱스란?

  인덱스는 테이블이나 클러스트에서 쓰여지는 선택적인 객체로서,
오라클 데이터베이스 테이블내의
원하는 레코드를 빠르게 찾아갈 수 있도록 만들어진 데이터 구조
입니다.  

자동 인덱스 : 프라이머리 키 또는 uinque 제한 규칙에 의해 자동적으로 생성되는 인덱스 입니다.

수동 인덱스 : CREATE INDEX 명령을 실행해서 만드는 인덱스들 입니다.  

※  Index를 생성하는 것이 좋은 Column

WHERE절이나 join조건 안에서 자주 사용되는 컬럼
null 값이 많이 포함되어 있는 컬럼
WHERE절이나 join조건에서 자주 사용되는 두 개이상의 컬럼들


※  다음과 같은 경우에는 index 생성이 불필요 합니다.
table이 작을 때
테이블이 자주 갱신될 때

※  오라클 인덱스는 B-tree(binary search tree)에 대한 원리를 기반으로 하고 있습니다.

  B-tree인덱스는 컬럼안에 독특한 데이터가 많을 때 가장 좋은 효과를 냅니다.

이 알고리즘 원리는

 ① 주어진 값을 리스트의 중간점에 있는 값과 비교합니다.    
     만약 그 값이 더 크면 리스트의 아래쪽 반을 버립니다.
     만약 그 값이 더 작다면 위쪽 반을 버립니다.

 ② 하나의 값이 발견될 때 까지 또는 리스트가 끝날 때까지 그와 같은 작업을 다른 반쪽에도
     반복합니다.



 ※  인덱스는 B-tree 구조를 가지며 크게 다음 네 가지로 분류될수 있습니다.


Bitmap 인덱스

  비트맵 인덱스는 각 컬럼에 대해 적은 개수의 독특한 값이 있을 경우에 가장 잘 작동합니다.
  그러므로 비트맵 인덱스는 B-tree 인덱스가 사용되지 않을 경우에서 성능을 향상 시킵니다.
  테이블이 매우 크거나 수정/변경이 잘 일어나지 않는 경우에 사용할수 있습니다.

SQL>CREATE BITMAP INDEX emp_deptno_indx
        ON emp(deptno);


Unique 인덱스

  Unique 인덱스는 인덱스를 사용한 컬럼의 중복값들을 포함하지 않고 사용할 수 있는 장점이 있습니다.
  프라이머리키 와 Unique 제약 조건시 생성되는 인덱스는 Unique 인덱스입니다.

SQL>CREATE UNIQUE INDEX emp_ename_indx
        ON  emp(ename);


Non-Unique 인덱스

   Non-Unique 인덱스는 인덱스를 사용한 컬럼에 중복 데이터 값을 가질수 있습니다.

SQL>CREATE INDEX  dept_dname_indx
        ON  dept(dname);


결합 (Concatenated(=Composite)) 인덱스

   복수개의 컬럼에 생성할 수 있으며 복수키 인덱스가 가질수 있는 최대 컬럼값은 16개입니다

SQL>CREATE UNIQUE INDEX emp_empno_ename_indx
        ON  emp(empno, ename);


※  인덱스의 삭제

 
 - 인덱스의 구조는 테이블과 독립적이므로 인덱스의 삭제는 테이블의 데이터에는 아무런 영향도 미치지
않습니다.

 - 인덱스를 삭제하려면 INDEX의 소유자이거나 DROP ANY INDEX권한
을 가지고 있어야 합니다.


 - INDEX는 ALTER를 할 수 없습니다.


SQL>DROP INDEX emp_empno_ename_indx ;


※  인덱스에 대한 정보는 USER_INDEXES 뷰 또는 USER_IND_COLUMNS뷰를 통해 검색할 수
      있습니다.

※ 인덱스 생성

 

Oralce 9i에서 인덱스는 Primary Key와 Unique Key와는 별도로 CREATE TABLE의 USING INDEX CREATE INDEX 문법을 이용해서 정의하는 것이 가능해 졌습니다.


아마도 대부분의 사용자들은 다음과 같은 방식을 알고 계실텐데…

예제를 보시면서 어떤 것이 바뀌었는지 확인토록 해보세요~~

SQL> create table test (
 c1 varchar2(4) not null,
 c2 number(10)  not null,
 constrint pk_test primary key(c1) using index );


테이블이 생성되었습니다.


위의 create table문은 pk_test라는 이름을 가지는 primary key 제약 조건을 만들며 아울러 pk_test라는 이름을 가진 인덱스를 만듭니다. 이 두가지는 user_ind_colums 뷰와 user_constraints 뷰에서 table_name = ‘TEST’라는 조건을 주시면 확인이 가능합니다.

그러나 9i이후에서는 인덱스에 대해 명시적으로 이름을 주는 것이 가능해 졌는데…

우선 아래의 예제를 참고 하도록 하죠…


SQL> create table test (

 c1 varchar2(4) not null,
 c2 number(7),
 constraint pk_test primary key(c1)
 using index
 (create index idx_test_c1 on test(c1))
 );


테이블이 생성되었습니다.

이 경우는 테이블을 만들면서 primary key를 만드는데 (원래는 default로 pk를 만들게 되면 그 컬럼으로 인덱스를 만듭니다.) 인덱스의 이름은 primary key 이름과 다르게 주기 위해 using index 구안에 create index문을 이용해서 인덱스를 생성했습니다.


--------------------------------------------------------------------
아래의 SQL문중 하나를 이용해 인덱스는 놔두고 PK만 삭제할 수 있습니다.
--------------------------------------------------------------------

SQL> alter table test drop primary key keep index;


테이블이 변경되었습니다.


또는


SQL> alter table test drop constraint pk_test;


테이블이 변경되었습니다.

2007/09/25 13:59 2007/09/25 13:59
Tags: