UNIX 계열에서 사용되는 웹프로그램 언어로는
C, Perl, PHP 등이 있는데 장단점을 개인적 견해로 비교해보면 다음과
같다.
C는 코딩속도와 라이브러리 등에서 열세를 보이는
반면 실행속도가 빠르다는 장점이 있다.
Perl의 경우 거의 대부분의 UNIX 시스템에 기본적으로 설치되어
있어 시스템간 호환성이 뛰어나고 코딩 속도도 빠르지만 인터프리터
언어 특성상 실행속도가 약간 느리고 다수 프로그램이 동시에 실행될
경우 서버에 부담이 될 수 있다. PHP는 코딩 속도와 실행속도
면에서 우위를 보이지만 웹서버와 조화를 이뤄야 하므로 범용 프로그램으로
배포하기엔 부적절한 데다 비대한 웹서버가 동작하게 되어 서버에
부담이 될 수 있다.
필자가 다른 언어보다 Perl을 주로 사용하는
이유는 코딩속도와 시스템 도구나 문자열 조작도구로 사용할 수
있기 때문이다.
Ⅱ. CGI Using Perl
생소할지 모르지만 다음의 소스는 본쉘(bash)
스크립트를 이용한 간단한 CGI이다.
#!/bin/bash echo Content-type: text/html
echo echo “bash를 이용한 CGI입니다.<BR>”
echo “접속주소 : $REMOTE_ADDR”
다음은 C를 이용한 CGI이다. 소스를 way.c라는
파일에 저장한 후 컴파일($ gcc -oway.cgi way.c)해서 웹상에서
실행해보면 간단한 결과가 출력된다.
main() { printf (“Content-type:
text/html\n\n”); printf (“C를 이용한 CGI입니다.<BR>”);
printf (“접속주소 : %s”, getenv(“REMOTE_ADDR”));
}
이렇듯 많은 언어나 쉘스크립트를 이용해 CGI를
만들어낼 수 있다.
1. Perl CGI 맛보기
Perl로 웹상에서 특정 문자를 출력하기 위해서는
내용을 출력하기 전에 다음과 같은 헤더를 출력하여 형식을 선언해줘야
한다.
간혹 뉴스그룹(han.comp.lang.perl)에 올라오는
질문 중 적지 않는 질문이 이런 사소한 문제가 원인인 경우가 많다.
특히 “Internal Server Error(500)”는 대부분 웹서버 Error log나
구문점검 옵션($ perl -c 파일명)을 통해 원인을 파악할 수 있다.
다음 소스를 way.cgi 라는 파일로 저장한 후 실행권한을 부여(chmod
+x)하면 웹브라우져로 “Hello, Way!”라는 내용을 접할 수 있다.
#!/usr/bin/perl print “Content-type:
text/html\n\n”; print “<H1>Hello, Way!</H1>\n”;
특정 URL로 접속을 전환(Redirect)하기 위해서는
다음과 같이 사용한다. 보통 http:// 등의 프로토콜 지정 없이 상대
URL로 사용할 수도 있지만 원칙적으로 프로토콜까지 포함해서 적어줘야
한다. 생략할 경우 오라클 웹서버, PWS 구버전 등의 일부 웹서버에서는
에러가 발생하기도 한다. 다음 소스가 브라우져로 실행되면 지정된
URL로 접속이 전환된다.
2. 아파치 웹서버 설정
만약 사용하는 웹서버에서 CGI 실행을 허용하지
않거나 CGI 파일에 실행권한이 부여되지 않았을 경우 “Forbidden(403)”이나
“Method Not Allowed(405)” 에러가 발생할 것이다. 경우에 따라
Perl 소스가 브라우져에 그대로 출력되기도 한다.
※ 아파치 웹서버 CGI 실행오류 해결방법
가. AddHandler cgi-script .cgi 부분의 주석
제거 나. <Diretory> 설정 중 Options 에 ExecCGI 추가
<Directory “/usr/local/apache/htdocs”>
Options Indexes Includes ExecCGI AllowOverride
FileInfo AuthConfig </Directory>
다음은 계정사용자의 웹문서 경로에 CGI실행을
허용하는 설정이다. <Directory /home/*/public_html>
Options Indexes Includes ExecCGI AllowOverride
FileInfo AuthConfig </Directory>
|
다. ScriptAlias 설정
ScriptAlias /cgi-bin/ “/usr/local/apache/cgi-bin/”
(VirtualHost의 경우도 적용이 가능하다.)
·ScriptAlias란? 1. 실제
디렉토리를 가상 디렉토리로 인식하도록 한다.(Alias,
별칭 기능) 2. 디렉토리 내의 파일을 브라우저로
접근하면 무조건
실행 프로그램(CGI)으로 취급하여 실행한다.
3. 보안상 HTML 문서 등은 퍼미션 에러나 서버에러가
발생하고 이미지는 나타나지
않는다.
|
3. FORM 태그
HTML 문서를 이용해 CGI에 정보를 전달하기 위해
FORM 태그가 사용된다. FORM 태그는 여느 HTML 태그와 마찬가지로
<FORM>으로 시작하여 </FORM>으로 끝이 난다.
<FORM ACTION=”연결할 CGI URL” METHOD=GET>
TARGET을 지정하거나 NAME을 지정할 수 있으며,
다음과 같이 파일 업로드를 위한 선언도 가능하다.
<FORM ACTION=”연결할 CGI URL” METHOD=POST
ENCTYPE=”multipart/form-data”>
다음과 같이 FORM 태그 내부에 <INPUT>,
<SELECT>, <TEXTAREA> 등의 태그를 사용하여 실질적인
정보를 전달하도록 한다.
<FORM ACTION=”way.cgi” METHOD=GET>
성명 <INPUT TYPE=TEXT NAME=user><BR>
주소 <INPUT TYPE=TEXT NAME=address><BR>
성별 <SELECT NAME=sex> <OPTION>남
<OPTION>여
</SELECT><BR>
<INPUT TYPE=SUBMIT
VALUE=”전송”><BR> </FORM>
성명에 way를 입력하고 주소에 Kwangju를, 성별은
‘남’을 선택하면 브라우져 주소입력줄에 다음과 같이 나타나며
지정된 CGI에 정보를 전달하게 된다.(GET 방식의 예이다.)
way.cgi?user=way&address=Kwangju&sex=%B3%B2
----- ----- -------- ------- ------------- CGI
성명 주소
성별
? 기호를 구분자로 하여 실행될 CGI(좌측)와
인자(우측)로 구성되며 각 인자들은 & 기호로 연결된다. 각
인자들은 = 기호로 키(항목명)와 값으로 구성된다.
4. 인자의 전달과 처리
FORM 태그나 GET방식의 직접연결을 통해 전달된
정보는 약간의 절차를 거쳐야 Perl에서 활용할 수 있다. 특정
기호로 나뉜 인자들을 추출해 내야하고 성별과 같이 16진수 형태로
전달된 한글이나 특수문자를 정상적인 자료로 변환해야 한다. 이를
위해 많은 이들이 cgi-lib.pl 라이브러리나 CGI.pm 모듈을 사용하는
것이 보통이다. 하지만 필요한 범위 이상의 비대한 소스를
사용하고 싶지 않기에 필자는 한번도 사용해본 적이 없다. 적어도
다음의 소스 정도면 넘겨받은 인자를 Perl에서 정상적인 자료로
활용할 수 있기 때문이다.
sub input_form { # 사용할
변수를 지역변수로 선언 local ($form, $tmp,
$key, $value); # GET, POST 방식을 판별하여
인자 습득 if($ENV{‘REQUEST_METHOD’} eq
“GET”) { $form = $ENV{‘QUERY_STRING’};
} if($ENV{‘REQUEST_METHOD’} eq “POST”)
{ read(STDIN, $form, $ENV{‘CONTENT_LENGTH’});
} # 키와 값으로 구분하고 16진수를 일반문자로
변환 foreach $tmp (split(/&/, $form))
{ ($key, $value) = split(/=/,
$tmp); $key =~ tr/+/
/; $value =~ tr/+/ /; $key
=~ s/%(..)/pack(“C”, hex($1))/ge;
$value =~ s/%(..)/pack(“C”, hex($1))/ge;
$input{$key} = $value; } }
|
소스를 간략히 설명하면 다음과 같다. 1.
인자 전달방식(GET 또는 POST) 판별 2. 전체 인자 습득
3. 전체인자에서 & 기호를 기준으로 각 인자 추출 4. 각
인자에서 = 기호를 기준으로 키와 값으로 구분 5. + 기호로
넘어온 공백문자를 정상적인 공백으로 변환 6. 한글이나 특수문자인
16진수 자료를 일반문자로 변환 7. %input 조합배열에 키와
값 저장
이제 &input_form; 을 먼저 호출하고 $input{‘항목명’}
과 같이 자료를 추출하여 활용할 수 있다.
앞서 설명한 FORM 태그가 포함된 HTML 문서에서
CGI를 호출하면 전달된 정보를 출력하는 CGI를 만들어 보자.
다음은 HTML문서(FORM 태그 사용)에 웹브라우져로
정보를 입력하는 화면(lynx)이다.
다음은 way.cgi 파일이다. 반드시 Perl경로를
확인하고 실행권한을 부여해야 정상적인 결과를 얻을 수 있을 것이다.
#!/usr/bin/perl
&input_form; &print_html;
sub input_form { ... } #
앞서 설명한 소스 sub print_html { print
“Content-type: text/html\n\n”; print
“<HR>\n”; print “<H2>원래
전달되었던 인자</H2>\n”; print “$ENV{‘QUERY_STRING’}<BR>\n”;
print “<HR>\n”; print “<H2>변환하여
활용이 가능해진 자료</H2>\n”; print
“성명 : $input{‘user’}<BR>\n”;
print “주소 : $input{‘address’}<BR>\n”;
print “성별 : $input{‘sex’}<BR>\n”;
print “<HR>\n”; exit; }
|
정상적인 경우 결과는 다음과 같다.
___________________________________________
원래 전달되었던 인자 user=way&address=Kwangju&sex=%B3%B2
___________________________________________
변환하여 활용이 가능해진 자료 성명 : way
주소 : Kwangju 성별 : 남 ___________________________________________
|
5. 모듈과 라이브러리 Socket, DBI, DBD
등의 Perl 모듈은 Perl의 활용범위를 확장시켜주는 매우 유용한
도구이다. Perl 모듈을 사용하기 위해서는 다음과 같이 선언해주어야
한다.
use 모듈명;
Socket 모듈의 경우 원격통신을 가능하게 해주는
도구로서, sendmail 이 지원되지 않는 UNIX계열 서버나 WindowsNT/98/95
운영체제의 서버에서 SMTP 서버에 접속하여 메일을 전송하는 경우가
좋은 예이다. 관심 있는 독자는 Way-BOARD(Ver1.2)를 다운로드
하여 압축을 해제한 후 lib/mail.cgi 파일 하단의 Socket Mail 부분을
참고하기 바란다. 많은 모듈은 Perl이 설치되면서 함께 설치되지만
그 밖의 모듈은 http://www.perl.com/CPAN/에서
구할 수 있다.
자주 사용되는 함수를 특정 파일에 넣어두고
필요에 따라 꺼내 쓸 수 있다.
require(“라이브러리 파일명”);
C나 PHP의 include문과 거의 동일한 기능을 한다.
앞의 인자변환 소스도 라이브러리 파일에 넣어두고 각종의
CGI에서 함께 공유할 경우 작업효율은 극대화 된다. 라이브러리
파일에 넣어둘 경우 실행권한을 부여하거나 Perl 위치를 적어줄
필요가 없지만 유의할 점은 파일의 제일 하단에 다음과 같이 return
1; 이라는 줄을 추가해줘야 에러가 발생하지 않는다는 것이다.
# Perl Library File
sub input_form { ... }
sub html_header { ... }
return 1;
|
6. 환경변수 앞서 설명한 인자처리 소스와
bash, C를 이용한 CGI에서 각각 환경변수를 읽어들여 활용하는 법을
볼 수 있었다. Perl에서는 환경변수가 조합배열인 %ENV에
저장되어있다. 다음은 Perl, PHP, C, bash에서 접속자의 IP정보를
얻어내는 방법이다.
구 분 |
환경변수 습득방법 |
perl |
$ENV{‘REMOTE_ADDR’} |
PHP,
C |
getenv(“REMOTE_ADDR”) |
bash |
$REMOTE_ADDR |
다음의 소스를 실행해보면 Perl에서 사용되는
각종의 환경변수명과 값을 구할 수 있다.
#!/usr/bin/perl print “Content-type:
text/html\n\n”; foreach $env_val (keys %ENV) {
print “* $env_val : $ENV{$env_val}<BR>\n”;
}
다음은 필자의 서버에서 소스를 실행한 결과다.
대충 훑어보면 어떤 기능을 하는 것들인지 알 수 있을 것이다.
경우에 따라 환경변수 종류가 늘어나거나 줄어들 수 있다.
* SERVER_SOFTWARE : Apache/1.3.9
(Unix) * GATEWAY_INTERFACE : CGI/1.1
* DOCUMENT_ROOT : /home/way/public_html
* REMOTE_ADDR : 210.123.123.123 * SERVER_PROTOCOL
: HTTP/1.1 * SERVER_SIGNATURE : Apache/1.3.9
Server at way.co.kr Port
80 * REQUEST_METHOD : GET * QUERY_STRING
: * HTTP_USER_AGENT : Mozilla/4.0 (compatible;
MSIE 5.0); Windows 98
* PATH : /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
* HTTP_ACCEPT : */* * HTTP_CONNECTION :
Keep-Alive * REMOTE_PORT : 1129 * SERVER_ADDR
: 210.123.254.100 * HTTP_ACCEPT_LANGUAGE
: ko * SCRIPT_NAME : /test/env.cgi *
HTTP_ACCEPT_ENCODING : gzip, deflate * SCRIPT_FILENAME
: /home/way/ public_html/test/env.cgi
* SERVER_NAME : way.co.kr * REQUEST_URI
: /test/env.cgi * SERVER_PORT : 80 *
HTTP_HOST : way.co.kr * SERVER_ADMIN : webmaster@way.co.kr
|
만약 브라우져에 입력된(특히 VirtualHost에서)
도메인을 얻기 위해서는 $ENV{‘HTTP_HOST’}라는 변수를 읽어들이면
된다.
예시에 나와있지 않지만 HTTP_COOKIE(쿠키정보),
HTTP_REFERER(CGI 실행 URL), REMOTE_USER (인증 사용자
ID) 등의 환경변수도 매우 유용하다.
다음 소스는 환경변수를 이용해 스스로의 URL을
표시하는 간단한 소스이다.
#!/usr/bin/perl print “Content-type:
text/html\n\n”; print “http://$ENV{‘HTTP_HOST’}$ENV{‘SCRIPT_NAME’}\n”;
7. 시간정보
시간정보를 얻기 위해서는 time() 함수를 이용한다.
얻을 수 있는 값은 1970년 1월 1일을 기준으로 한 초 단위 값이다.
보통의 경우 localtime() 함수를 사용하여 단위별 값들을 리스트로
추출해낸다. 다음은 시간정보를 보기 좋게 추출해내는 소스이다.
주의할 점은 요일($weekday)이나 월($month)은 0부터 시작된다는
것이다. 또한 항간에 시끄러운 Y2K문제와 관련해 고려할 부분은
$year가 실제 연도에서 1900을 뺀 수치로 구성된다는 것이다. 그러니까
$year 값에 1999년은 99, 2000년은 100이 저장된다. 외국서버를
사용하는 경우와 같이 필요에 따라 지역시간대에 따른 조정이 필요하면
time()에 초단위로 조정을 가할 수 있다. localtime(time()+(12*60*60))와
같이 사용할 경우 서버시간에서 12시간 빠른 시간정보가 추출된다.
#!/usr/bin/perl print
“Content-type: text/html\n\n”; ($second,
$minute, $hour, $date, $month, $year, $weekday,
$yearday, $Isdst) = localtime(time());
$month ++; $year += 1900;
@dayname = (“일”,”월”,”화”,”수”,”목”,”금”,”토”);
$weekday = $dayname[$weekday];
print “일자 : $year년 $month월
$date일 $weekday요일<BR>\n”; print
“시간 : $hour시 $minute분 $second초<BR>\n”;
|
PHP에서 사용하는 date 함수처럼 표시형식의
자유로운 지정이 가능한 Perl 함수를 만들어보는 것도 좋은 공부가
될 것이다.
8. 연속출력
정보를 연달아 출력하기 위해서는 수많은 print문을
사용하기도 하고 print문 하나로 다수의 라인을 출력하기도 하지만
“ 기호 등을 표시할 때 \”와 같이 표시해 줘야하므로 매우 불편하다.
하지만 다음과 같이 print문을 print <<”구분문자”;와 같이
사용하게 되면 “구분문자”가 나타날 때까지 계속 출력할 수 있다.
해당범위 내에서는 HTML 문서처럼 코딩해도 크게 문제가 없으며
Perl에서 사용중인 변수를 직접 사용할 수도 있고 “ 등의 큰따옴표를
가공 없이 사용할 수도 있다. 유의할 점은 끝을 알리는
“구분문자”는 첫 번째 자릿수부터 입력되어야 한다는 것과 메일주소에
쓰이는 @기호는 \@와 같이 사용해야 한다는 것이다. 만약 print
<<’EOF’;와 같이 작은따옴표를 이용해 구분문자를 감싸주면
@ 기호를 그대로 사용할 수 있지만 변수참조가 불가능하다.
#!/usr/bin/perl $user
= “way”; $address = “Kwangju”; print
“Content-type: text/html\n\n”; print
<<EOF; <HTML> <HEAD>
<TITLE>연속출력 시험</TITLE>
</HEAD> <BODY> 성명 : “$user”<BR>
주소 : “$address”<BR> </BODY>
</HTML> EOF print “출력완료”;
|
9. 메일전송
게시판에 새로운 글이 등록되거나 방문자가 방명록에
글을 남길 경우, 특정양식의 신청서를 입력받는 경우 메일로 정보가
전달되도록 메일을 전송하는 방법을 알아보자. 앞서 설명했듯이
파일을 조작하기 위해 다음과 같이 사용했었다.
open(파일핸들, “[조작방법] 파일명”);
여기에 조작방법을 “|” 기호로 하고 파일명
대신 명령어(sendmail)나 장치(프린터 등)를 적어주면 Perl에서
정보를 전달할 수 있다.
다음은 메일을 전송하는 소스이다. @기호는
\@와 같이 표시하거나 큰따옴표 대신 작은따옴표로 감싸주면 에러가
발생하지 않는다.
#!/usr/bin/perl open(MAIL,”|/usr/sbin/sendmail
-t”); print MAIL “To: way\@abc.co.kr\n”;
print MAIL “Subject: 제목입니다.\n\n”;;
print MAIL “메세지 본문입니다.”;
close (MAIL);
print “Content-type: text/html\n\n”;
print “전송완료”;
|
발송자(From)를 지정하려면 To 아랫줄에 다음과
같이 삽입한다.
print MAIL “From: 임대호 <lawwal\@way.co.kr>\n”;
HTML형식으로 메일을 보내려면 Subject 부분을
다음과 같이 바꿔주면 된다.
print MAIL “Subject: 제목입니다.\n”;
print MAIL “Content-type: text/html\n\n”;
10. 쿠키
게시판에 글을 쓰면 다음에 글을 쓸 때 자동으로
이름과 메일주소를 적어주거나 접속자 인증에 주로 쿠키가 사용된다.
Perl에서도 쿠키를 직접 핸들링할 수 있다. 다음 소스는
Perl에서 사용자의 브라우져에 쿠키값을 저장하는 함수이다.
sub cookie_set { local($name,
$value, $exp) = @_; $exp
= scalar localtime(time()+(24*60*60)*$exp);
print “Content-type: text/html\n”;
print “Set-Cookie: $name=;\n”;
print “Set-Cookie: $name=$value;expires=$exp;\n”;
}
|
사용자의 브라우져에 저장된 쿠키값은 환경변수인
$ENV{‘HTTP_COOKIE’}에 저장된다. 다음 소스는 쿠키를 읽어들여
%cookie라는 조합배열에 넣어 활용이 가능토록 하는 함수이다. 자세히
보면 앞서 설명한 input_form() 함수와 유사하다는 것을 알 수 있을
것이다.
sub cookie_read { @strings
= split(/; /,$ENV{‘HTTP_COOKIE’}); foreach
$strs (@strings) { local
($name, $value) = split(/=/,$strs); $value
=~ tr/+/ /; $value
=~ s/%(..)/pack(“C”, hex($1))/ge; $cookie{$name}
= $value; } }
|
두 개의 함수를 이용해서 쿠키를 저장하고 읽어보도록
하겠다.
#!/usr/bin/perl &cookie_set(“name”,
“way”, 7); # 키, 값, 만료기일 print
“Content-type: text/html\n\n”; print
“쿠키를 저장하였습니다.”;
#!/usr/bin/perl &cookie_read;
print “Content-type: text/html\n\n”; print
“읽어온 name의 값은 $cookie{‘name’}입니다.”;
11. 실행권한과 보안
Perl뿐만 아니라 모든 CGI가 파일을 조작할 경우
웹서버가 nobody 등으로 실행되므로 nobody 등의 소유로 파일이
생성되고 조작되어진다. 이는 실제 파일소유자가 접근하기도
곤란할뿐더러 동일한 서버를 사용하는 구성원은 공통의 권한을 가지는
형국이 되므로 보안문제가 야기될 수 있다.(역효과를 우려해 소스를
소개하지는 않겠다.) 해결방법으로는 다음 세 가지 정도로
요약할 수 있다. 세 가지 방법 모두 실제 사용자의 권한으로 실행되므로
중요한 정보를 지닌 자료파일이나 디렉토리는 chmod go-rwx 와 같이
해두어도 무방하다.
가. 아파치 suexec 적용
아파치 설치시 다음과 같이 suexec를 적용하고
컴파일한다. 가상 도메인의 경우 아파치 설정시 <VirtualHost>
부분에 User와 Group을 실제 계정 사용자로 지정해주면 된다.
# ./configure --prefix=/usr/local/apache
--enable-suexec --suexec-caller=nobody
--suexec-docroot=/home --suexec-logfile=/usr/local/apache/logs/suexec_log
--suexec-userdir=public_html --suexec-uidmin=500
--suexec-gidmin=500 --suexec-safepath=/usr/local/bin:/usr/bin:/bin
# make # make install
* 아파치 VirtualHost 설정 <VirtualHost
210.123.254.100> User way
Group user
ServerAdmin webmaster@way.co.kr
DocumentRoot /home/way/public_html
ScriptAlias /cgi-bin/ /home/way/public_html/cgi-bin/
ServerName www.way.co.kr
ServerAlias way.co.kr www.way.co.kr
TransferLog /home/way/www_log/today.log
ErrorLog /home/way/www_log/error.log
</VirtualHost>
나. cgiwrap 적용
ftp://ftp.umr.edu/pub/cgi/cgiwrap/cgiwrap-Version.tar.gz
# tar xvfz cgiwrap-Version.tar.gz # ./configure --help(옵션
확인) # ./configure --with-httpd-user=nobody # make
# make install # cp cgiwrap /usr/local/apache/cgi-bin
# cd /usr/local/apache/cgi-bin # chown root cgiwrap
# chmod 4755 cgiwrap # ln -s cgiwrap cgiwrapd # ln -s
cgiwrap nph-cgiwrap # ln -s cgiwrap nph-cgiwrapd
필자의 경우 위와 같이 설치한 후 cgi-bin은
이미 /home/way/public_html/cgi-bin 으로 ScriptAlias 되어있으므로
/usr/local/apache/cgi-bin 디렉토리를 cgi-sys로 ScriptAlias해서
다음과 같이 실행하였다.
* 시스템 경로 : /home/way/public_html/cgi-bin/file.cgi
* 실행URL : http://way.co.kr/cgi-sys/cgiwrap/way/file.cgi
(우측의 way는 사용자 ID를 뜻한다.)
다. Set User ID
12. 방명록 만들기
이제 CGI 예제로 간단한 방명록을 한번 만들어
보자. 지면관계상 메일이나 쿠키, 페이지 나눔 등은 배제하도록
하겠다. 참고로 방명록파일(guestbook.dat)은 nobody 등의
웹사용자가 쓸 수 있는 권한이 부여되어야 한다.
#!/usr/bin/perl # 먼저 인자정보를 습득한다.
&input_form;
# 전달된 값중 ‘작업’ 항목의 값이 없을 경우
# 이미 등록된 글을 출력(방명록 보기)하고 종료한다. if(!$input{‘작업’})
{ &print_guestbook; exit; }
# 전달된 값중 ‘작업’ 항목의 값이 ‘쓰기’일
경우 # 쓰기화면을 출력한다. elsif($input{‘작업’} eq
“쓰기”) { &guestbook_write;
exit; }
# 전달된 값중 ‘작업’ 항목의 값이 ‘처리’일
경우 # 글을 등록하고 등록된 글을 출력한다. elsif($input{‘작업’}
eq “처리”) { &guestbook_add;
&print_guestbook; exit; }
# 어느것도 아닐 경우 그냥 종료한다. else
{ exit; }
sub input_form {
# 앞서 설명했던 인자처리함수이다. local
($form, $tmp, $key, $value); if($ENV{‘REQUEST_METHOD’}
eq “GET”) { $form = $ENV{‘QUERY_STRING’};
} if($ENV{‘REQUEST_METHOD’} eq “POST”) { read(STDIN,
$form, $ENV{‘CONTENT_LENGTH’}); } foreach $tmp (split(/&/,
$form)) { ($key, $value) = split(/=/, $tmp);
$key =~ tr/+/ /; $value
=~ tr/+/ /; $key =~ s/%(..)/pack(“C”,
hex($1))/ge; $value =~ s/%(..)/pack(“C”, hex($1))/ge;
$input{$key} = $value; } }
sub print_guestbook {
# HTML 머릿말 출력 &html_start(“방명록
보기”);
print “<TABLE BORDER=1 WIDTH=500>\n”;
# 방명록 파일로 사용할 파일명을 지정한다.
local $file = “guestbook.dat”;
# 파일이 존재하지 않거나 크기가 0byte면 작성된
# 자료가 없다고 출력하고 종료한다. if(!-e $file || -s $file
eq 0) { print “<TR><TD>작성된 글이
없습니다.</TD></TR>\n”; &guestbook_write_link;
print “</TABLE>\n”; &html_end;
exit; }
local $print_msg;
# 방명록 파일을 열어 출력한다. # 파일을
열 수 없을 경우 종료한다. open(FILE, “$file”) || die “파일을
열 수 없습니다.($file)”; while(<FILE>)
{ # 한줄을 읽어와서 끝에있는 개행문자(\n)를
제거한다. chomp $_; #
읽어온 줄의 자료를 | 기호를 기준으로 추출하여 #
@guest 라는 배열에 집어 넣는다. local
@guest = split(/\|/, $_); # 항목별로
추출한다. local $name = $guest[0];
local $mail = $guest[1]; local
$home = $guest[2]; local $date =
$guest[3]; local $usip = $guest[4];
local $mesg = $guest[5]; #
자료를 가공(링크 삽입 및 시간 출력)한다. if($mail)
{ $mail = “<A HREF=mailto:$mail>$mail</A>”;
} if($home) { $home = “<A
HREF=$home>$home</A>”; } $date
= &time_conv($date); # HTML
형식으로 자료를 변수에 저장한다. $print_msg
.= “<TR>\n”;
$print_msg .= “<TD><FONT
SIZE=2>\n”; $print_msg .= “◈
성명 : $name($mail)<BR>\n”; $print_msg
.= “◈ 홈페이지 : $home<BR>\n”; $print_msg
.= “◈ 일자 : $date (IP:$usip)<BR>\n”; $print_msg
.= “◈ $mesg”; $print_msg .= “</FONT></TD>\n”;
$print_msg .= “</TR>\n”;
} # -- while 루프 종단점 close(FILE);
# 모든 글을 출력한다. print $print_msg;
# 글쓰기 부분의 링크를 출력한다. &guestbook_write_link;
print “</TABLE>\n”; # HTML을
마무리한다. &html_end; }
sub guestbook_write {
&html_start(“방명록 쓰기”);
# 등록양식을 출력한다. # 주의할 사항은
FORM ACTION 부분과 # 하단의 ‘작업’ 부분이다. print
<<”EOF”; <FORM ACTION=$ENV{‘SCRIPT_NAME’}
METHOD=POST>
<TABLE BORDER=1 WIDTH=500> <TR> <TD>성명</TD>
<TD><INPUT TYPE=TEXT NAME=name SIZE=20></TD>
</TR> <TR> <TD>E-mail</TD>
<TD><INPUT TYPE=TEXT NAME=mail SIZE=35></TD>
</TR> <TR> <TD>홈페이지</TD>
<TD><INPUT TYPE=TEXT NAME=home SIZE=35 VALUE=”http://”></TD>
</TR> <TR> <TD>남기실 내용</TD>
<TD><TEXTAREA NAME=mesg ROWS=5
COLS=35></TEXTAREA> </TR> <TR>
<TD COLSPAN=2> <INPUT TYPE=SUBMIT VALUE=”글을
등록합니다.”> </TD> <INPUT TYPE=HIDDEN
NAME=”작업” VALUE=”처리”> </FORM> </TR>
</TABLE> EOF &html_end;
}
sub guestbook_add {
# 전달받은 각 항목별 정보를 저장하기 위해
준비한다. # 등록된 시간과 글쓴이의 IP주소도 습득한다.
local $name = $input{‘name’}; local $mail = $input{‘mail’};
local $home = $input{‘home’}; local $date = time();
local $usip = $ENV{‘REMOTE_ADDR’}; local $mesg = $input{‘mesg’};
# $mesg 값에서 개행문자를 공백문자로 변환한다.
$mesg =~ s/\cM//g; $mesg =~ s/\r\n/\n/g; $mesg =~
s/\n/ /g;
# 가급적 자료 구분자로 사용할 | 기호가 입력된
# 자료를 다른 기호로 변환한다. $mesg =~ s/|/\:/g; local
$file = “guestbook.dat”; local $original;
# 최근에 등록된 글을 먼저 출력하기위해
# 종전에 등록된 글이 있을 경우 읽어온다. if(-e $file) {
open(FILE, “$file”) || die “파일을 열수 없습니다.($file)”;
while(<FILE>) { $original .= $_; } close(FILE);
}
# 새로운 글을 저장하고 종전의 글도 뒤이어
저장한다. open(NEW, “>$file”) || die “파일을
열수 없습니다.($file)”; print NEW “$name|$mail|$home|$date|$usip|$mesg|\n”;
print NEW $original; close(NEW); }
sub html_start {
# TITLE로 인쇄할 정보를 넘겨받는다. local($title)
= @_;
# HTML 문서형식으로 출력하겠다고 선언한다.
print “Content-type: text/html\n\n”;
# HTML 태그 연속 출력(TITLE 포함) print
<<”EOF”; <HTML> <HEAD> <TITLE>$title</TITLE>
</HEAD> <BODY> <HR SIZE=1> <H2>$title</H2>
<HR SIZE=1> EOF }
sub html_end {
# HTML 출력을 마무리한다. print <<”EOF”;
<HR SIZE=1> </BODY> </HTML> EOF
}
sub guestbook_write_link {
# ‘쓰기’ 링크를 출력한다. print <<”EOF”;
<TR> <TD>[ <A HREF=”$ENV{‘SCRIPT_NAME’}?작업=쓰기”>글쓰기</A>
]</TD> </TR> EOF }
sub time_conv {
# 시간변환 함수이다. # time() 값으로 저장된
자료를 출력형식에 맞게 # 변환한다. local ($data) = @_;
local ($second, $minute, $hour, $date, $month, $year, $weekday,
$yearday, $Isdst) = localtime($data); $month ++; $year
+= 1900; $month < 10 && ($month = “0$month”);
$date < 10 && ($date = “0$date”); $hour <
10 && ($hour = “0$hour”); $minute < 10 &&
($minute = “0$minute”); $second < 10 && ($second
= “0$second”); return “$year/$month/$date $hour:$minute:$second”;
}
필자는 한번 컴퓨터에 입력한
자료를 또다시 입력하기를 매우 싫어한다. 본 강좌는
http://way.co.kr 에도 동시에 올려진다. 지면에 소개된 소스를
키보드로 입력하지 말고 필자의 홈페이지를 찾아 복사해서 사용하기
바란다.
▲ top
|