![]() Luis Colorado 글쓴이 소개: Luis Colorado님은 스페인에 있는 Telefonica Sistemas S.A.에서 유닉스시스템과 인터넷접근을 가능하게 해주는 관리자로 일하고 계십니다. 글쓴이는 Universidad Complutense of Madrid에서 물리학을 전공하였으며 몇몇 유닉스 유틸리티를 오픈소스의 형태로 개발해오고 계십니다. 순 서:들어가는 글 개발동기 M4 작동원리 사용자가 CGI로 정보전달하기 다운로드 |
요약:
이 글에서는 HTML페이지에서 데이터베이스에 접속할 수 있게 해주는 새로운 프로그램에 대해 이야기하고자 합니다. 이 프로그램이 설계된 목적은 데이터접근을 통제하고, 환경설정에서 유연성을 획득하며, 레이아웃 형식에 독립적으로 만들어주는 것잆니다. 이 프로그램은 최근 1년동안 Linux Journal과 LinuxFocus (www.linuxfocus.org) 에서 많이 등장하는 M4에 대한 몇몇 기사를 읽다가 떠오른 생각들을 모아서 개발한 것입니다.
이 글을 통해 나는 여러분께 웹을 통하여 데이터베이스를 이용할 수 있게하는 패키지를 개발하게 된 아이디어와 근본원리에 대해 이야기하고자 한다. 즉 PG2CGI패키지에 대한 사용설명서를 쓰기 위하여 적는 것이 아니라 간단한 소개와 소프트웨어를 사용해 보고 독자들이 평가를 해본 다음 여러분의 피드백을 보내주기를 기대하면서 이 글을 적는다. (이미 참고할만한 가이드가 프로그램의 배포판에 들어 있다. 이 배포판이 있는 URL은 이 글 뒤에 있다.)
나는 리눅스저널과 리눅스포커스에서 HTML소스를 관리하기 위하여 M4를 사용하는 것에 대한 연재기사의 결과물로 이 프로그램을 개발하였다. 연재된 글들은 웹페이지를 관리하는 독립실행형 도구로서, 동적으로 내용을 생성하는 도구로서의 M4의 잠재성과 유용성을 보여주었다.
반면 매우 다양한 웹 서버나 데이터베이스를 이용하는 것은 양쪽 환경사이를 연결해주는 유틸리티의 부족을 가져왔다.(대부분의 이런 다리 역할을 하는 응용프로그램들은 상업용이거나 다룰 수 있는 특정 형식에 따라야 하는 심각한 의존성을 가지고 있다.)
이러한 소프트웨어 패키지들은 데이터베이스와 웹 환경을 하나로 통합해준다. 그러기 위해서 다음과 같은 요구조건을 만족하여야 한다.:
필자가 알고있는 HTML과 데이터베이스를 상호작동하게 하는 유틸리티의 대부분은 HTML의 확장테그집합을 이용하여 출력결과물을 만들어 낸다; 이러한 새로운 태그들은 이후 '매크로(macro)'로 작동된다. 그러나 이러한 방법은 심각한 단점을 가지고 있다: 우리는 대부분의 시간을 원래의 HTML태그들 사이에서 각 요소들을 수정하는데 쓰게 되고 이러한 점은 중요한 제약조건이 된다. 종종 이러한 유틸리티들은 현재 존재하는 HTML태그들사이에서 특수한 효과를 내기 위하여 재사용되곤 한다. 내 프로그램에서는 필요한 매크로 대용품으로 동작하기 위하여 M4를 사용한다. 이 프로그램은 어떤 형식으로 된 문서를 생성하지 않는데, 결국 최종적으로 얻어지는 형식언어에 사용되는 것과 독립적으로 되게 된다. 프로그램은 질의(쿼리;query)의 결과로 매크로들의 집합을 만들어 낸 다음 M4가 이러한 매크로의 집합과 주어진 HTML템플릿을 이용하여 HTML문서를 만들어 내게 된다.
이 때 유틸리티는 요구조건들을 만족시키기 위하여 효율성면에서 약간의 조그마한 불이익을 감수한다.(유틸리티는 실행되는 동안 M4를 여러분 호출하게 된다.) 그러나 그 결과는 대부분의 경우 만족스럽다.(대부분의 경우를 고려해보면 HTML문서를 동적으로 생성하기 위하여 데이터베이스의 질의는 이미 여러분 수행되어 있다.)
M4는 오래전에 개발된 매크로 처리 도구이다. 우리가 만든 소프트웨어는 이 매크로처리기를 매우 유용하게 사용한다.:
M4는 원래 PostgreSQL데이터베이스와 CGI(Common Gateway Interface)를 연결하기 위하여 개발되었다. 그러나 얼마후 사람들은 이것이 CGI뿐만 아니라 다른 인터페이스에 사용하기에도 충분히 일반적이라는 사실을 알 수 있었다.(예를 들자면 LDAP서버와 인포믹스나 오라클과 같은 다른 데이터베이스의 게이트웨이(gateway)로도 사용된다.) 이후 인터페이스는 필요한 기능을 모두 통합하기 위하여 표준화되었으며 PostgreSQL의 모듈들은 이러한 새로운 인터페이스에 따라 다시 개발되었다. 현재 다른 데이터베이스 관리자를 연결해주는 프로그램을 만들기 위한 새로운 드라이버들을 만드는 것이 가능하다. |
이러한 매크로처리기의 반복사용은 GNU의 M4유틸리티로 검사하는 것을 잘 만족시켜주지만 결국 효율성면에서 손실을 가져온다.
이 유틸리티는 주어진 설정규칙이 옳은지 그른지를 확인하기 위하여 정규표현식을 엄격히 사용한다. 정규표현식은 우리에게 매우 편리한 기능을 제공하기 때문에 간단한 비교보다 더 선호되고 있다. 정규표현식은 다음과 같은 장점을 가지고 있다.:
|
하나의 정규표현식에서 복수의 하위체인들로 그룹화할 수 있기때문에 표현식의 문법과 정규표현식에서 드라이버로 전달하기 위한 데이터의 파싱은 쉽게 이루어진다.
한 예를 살펴보자: 클라이언트가 잘의문에 어떤 정보를 전달하려 한다면 그 데이터들은 다음 문법에 알맞게 바뀌어져야 한다.:
항목=값
질의문은 이 형식을 만족해야 하기 때문에 문장에 부가적 정보가 있을 수 없다.
선택규칙에서 다음 조건을 쓸 때 이 문법을 반드시 사용하는 것은 쉬운 일이다.:
QUERY_STRING: "^FIELD=[^&]*$";
윗 줄은 질의문이 적절한 문법을 만족할 경우에만 규칙들이 호출되는 것을 보장한다. 위의 예에서 항목의 값을 괄호로 묶을 경우 프로그램은 일치하는 값을 파싱할 수 있게 해준다.:
QUERY_STRING: "^FIELD=([^&]*)$";
이 과정에서 프로그램은 네비케이터에 의해 만들어지는 %xx형식으로 전달되는 값을 적절한 값으로 변환시켜준다.
이제 어떻게 작동하는지 이야기 해보자. 처음으로 실행되면 프로그램은 웹서버로부터 환경변수들의 값을 받아서 그 값들을 이용하여 스스로 적절한 환경설정을 해준다. 환경변수는 프로그램이 확인해보는 모든 것들이다.:클라이언트가 무엇인가? 어떤 요청이 이루어졌는가? 요청의 내용은 무엇인가? 클라이언트가 지원하는 정보의 형식(MIME형식)은 무엇인가?등등.... PG2CGI는 그 다음 규칙의 왼쪽에 사용되는 규칙을 선택한다. 현재는 세가지형식의 규칙이 제공된다.:
QUERY_STRING: "^FIELD=([^&]*)$";
! HTTP_ADDRESS: "^194\.142\.12\.";(이 예에서 만약 요청이 194.142.12.xxx번지에서 이러어졌다면 규칙이 무효가 된다.)
[ QUERY_STRING: "USER=([^&]*)" ];이 경우는 클라이언트가 값을 준다면 사용자(user)의 값을 전달할 수 있게해준다. 그러나 클라이언트가 값을 정하지 않는다면 규칙을 무효화하지 않는다.
이러한 방법으로 규칙을 만들수 있다. 다음에는 우리는 규칙에서 유효한 왼쪽항목을 정하기 위하여 많은 조건들을 묶는다. 조건들은 중괄호 "{}"사이에 위치한다.
규칙의 오른쪽과 왼쪽은 중괄호"{}"로 구분을 함으로써 경계를 나타낸다. 그리고 왼쪽과 오른쪽은 '->'기호를 이용하여 구분된다.
오른쪽 항목들은 동일한 구문을 가진 조건들이 들어있다.: 변수의 이름,':'문자, 문자열과 종결을 의미하는 ';'문자. 오른쪽에 있는 모든 조건은 M4에 의해 수행되어져 주어진 값을 변수에 할당하는 것이다.:
다른 변수는 템플릿파일이나 적절한 드라이버에 의해 사용되어질 수도 있다.
매우 간단하다. 각각의 규칙에서 왼쪽에 있는 정규표현식으로부터 그룹들이 만들어 지는데 이 그룹들은 각각 변수로 변환되어진다.(이 새로운 변수들의 이름은 `term_<i>_match_<j>'과 같은 형식이다. 이때 <i>는 규칙에 사용된 순서번호이다.(결국 첫 조건은 1을, 두번째 조건은 2를 가지는 형태가 된다.) 만약 클라이언트로 부터 다음과 같은 질의문이 전달되었다고 하자.:
웹싸이트에 선언된 규칙은 다음과 같다.:
QUERY_STRING: "NAME=([^&]*)"; QUERY_STRING: "FAMNAME1=([^&]*)"; QUERY_STRING: "FAMNAME2=([^&]*)";결과는 다음과 같이 될 것이다.::
term_0_match_0 <- "NAME=JOSE"; term_0_match_1 <- "JOSE"; term_1_match_0 <- "FAMNAME1=DE LA FUENTE"; (공백은 +문자로 바뀌어짐을 알 수 있다.) term_1_match_1 <- "DE LA FUENTE"; term_2_match_0 <- "FAMNAME2=LOPEZ"; term_2_match_1 <- "LOPEZ";드라이버:
이 글에서 구체적으로 드라이버에 관한 이야기는 하지 않았다. 그러나 이미 PG2CGI배포판에 들어 있는 문서자료를 통해 드라이버의 사용방법을 설명했다. 관심이 있는 독자라면 꼭 참고설명서에 포함되어 있는 글을 읽어보기 바란다.
POSTGRESQL로 운영되는 데이터베이스에 연결하는 경우에는 단 하나의 드라이버가 사용된다 그러나 이미 개발자는 LDAP형식의 데이터베이스를 위한 다른 드라이버를 개발할 계획을 가지고 있다.
보기:
전체적인 예제 소스를 살펴보자
slug.ctv.es에 있는 공지사항과 관련된 데이터베이스에서 공지사항 테이블을 만들어보자. 이는 테이블에서 각각의 레코드를 찾아보거나 전체 목록을 만들기 위하여 두개의 템플릿을 사용하는 가장 단순한 예이다.
/etc/html2sql.cfg
{ PATH_INFO: "^/avisos/?$"; # PATH_INFO변수에 의해 선택된다. [SERVER_ADMIN: ".*"]; # SERVER_ADMIN으로부터 정보를 얻는다. 선택사항 } -> { DRIVER: "POSTGRESQL"; PGTTY: "/dev/console"; # 콘솔로 로그하도록 한다. PGDATABASE: "postgres"; # 우리는 항상 질의를 한다.(늘 내부적으로 템플릿파일에서 개별적인 레코드들을 # 연결하기 위하여 질의문을 사용한다.) PGQUERY: "select oid,ct,titulo,texto,mt" " from avisos" " where (dt is NULL or dt > 'now')" " order by mt desc"; # 파일은 템플릿을 가지고 있다. M4FILE: "/usr/local/etc/httpd/plantillas_m4/avisos.m4"; WEBMASTER: "term_1_match_0"; #TESTMODE: "TRUE"; } # 다음 선택규칙은 알려진 우선키값인 OID를 가지는 공지사항(aviso)를 선택할 수 # 있도록 해준다. 이 정보는CGI의 PATH_INFO변수에 포함되어 있다. { PATH_INFO: "^/avisos/([0-9]+)/?$"; SERVER_ADMIN: ".*"; } -> { DRIVER: "POSTGRESQL"; PGTTY: "/dev/console"; # 앞에서 처럼 콘솔로 로그한다. PGDATABASE: "postgres"; OID: "term_0_match_1"; # OID를 부여한다. # 한번더 선택이 중요하다. 우리는 필드의 시작부분에 OID를 포함시키며 # 이경우 우리는 이 레코드를 지우기 위한 하이퍼링크를 적게 하고 싶다. PGQUERY: "select oid,ct,titulo,texto,mt,dt,autor" " from avisos" " where (dt is NULL or dt > 'now') and oid=OID"; # 이제 템플릿이 서로 다르다. M4FILE: "/usr/local/etc/httpd/plantillas_m4/avisos_oid.m4"; WEBMASTER: "term_1_match_0"; #TESTMODE: "TRUE"; } |
define(<<<for>>>, <<<dnl
ifelse(eval((<<<$2>>>) <= (<<<$3>>>)), 1, <<<define(<<<$1>>>,<<<$2>>>)$4<<<>>>dnl for(<<<$1>>>,eval(<<<$2>>>+1),<<<$3>>>, <<<$4>>>)dnl >>>)dnl >>>)dnl divert(0)dnl Mime-Version: 1.0 Content-type: text/html <HTML>
<!-- la tabla est\xe1 vac\xeda -->
>>>,<<<dnl /* PGRES_NTUPLES != 0 )( */
for(<<<i>>>,0,eval(PGRES_NTUPLES-1),<<<dnl
</table>
>>>)dnl /* PGRES_NTUPLES */ >>>,<<<dnl /* ifelse PGRES_RESULTSTATUS )(*/ Error en el resultado: <B>PGRES_RESULTSTATUS</b><BR>
>>>)dnl <CENTER><HR WIDTH=100></center>
|
divert(-1)
$Id: generic_list.m4,v 1.1 1998/07/06 17:13:33 luis Exp $ define(<<<cell>>>, <<<PGRES_CELL_$1_$2>>>) define(<<<field>>>, <<<PGRES_FNAME_$1>>>) define(<<<for>>>, <<<dnl ifelse(eval((<<<$2>>>) <= (<<<$3>>>)), 1, <<<define(<<<$1>>>,<<<$2>>>)$4<<<>>>dnl for(<<<$1>>>,eval(<<<$2>>>+1),<<<$3>>>, <<<$4>>>)dnl >>>)dnl >>>)dnl divert(0)dnl Mime-Version: 1.0 Content-type: text/html <HTML>
ifelse(PGRES_RESULTSTATUS, <<<PGRES_TUPLES_OK>>>,<<<dnl
<!-- la tabla est\xe1 vac\xeda -->
>>>,<<<dnl /* PGRES_NTUPLES != 0 )( */
>>>)dnl /* PGRES_NTUPLES */ >>>,<<<dnl /* ifelse PGRES_RESULTSTATUS )(*/ Error en el resultado: <B>PGRES_RESULTSTATUS</b><BR>
>>>)dnl <CENTER><HR WIDTH=100></center>
|
결과는 이 URL에서 볼 수 있다.:
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/20384
PG2CGI프로그램은 다음 URL들에서 다운로드 받을 수 있다.:
http://slug.ctv.es/~luis/utils/pg2cgi.tar.gz번역 : 이주호
본 웹싸이트는 Miguel 햚gel Sep?veda님에 의해 관리되고 있습니다. © Luis Colorado 1998 LinuxFocus 1999 |