@gypark - 개인 자료라고 믿기 어려울 정도의 방대한 Perl 자료를 제공하고 있는 gypark.pe.kr의 주인장, Raymundo라는 닉을 사용하기도 한다.
예전에 리눅스 서버에서 만든 CGI를 윈도우에서 써 보고 싶은데, 짧은 CGI 스크립트를 하나 쓰자고 Apache 웹 서버를 설치하는 건 과하다 싶었습니다. 그렇다고 요즘 많이 쓴다는 Dancer나 Mojolicious 같은 웹 프레임워크를 따로 배워서 새로 스크립트를 작성하자니 이것도 배보다 배꼽이 더 큰 느낌이었죠. 그런데 Plack을 사용하여 기존 CGI 스크립트를 그대로 실행할 수 있었습니다. 이 글에서는 간단한 예를 통해 그 과정을 설명합니다.
사용하는 모듈은 아래와 같습니다.
사실 저는 여전히 잘 모르겠습니다. :-) 다만 문서에서 읽은 설명에 의하면 아래와 같습니다.
윈도우7에 Strawberry Perl 5.14를 쓰고 있는데, Plack 모듈의 경우 설치할 때 테스트에서 무수히 많은 에러가 나서 설치가 안 되었습니다. 정확한 이유는 모르겠고, 일단은 notest force install Plack
명령을 써서 강제로 설치해 주었는데, 큰 문제는 없었습니다.
간단한 CGI 스크립트 예제입니다. 이 코드 자체가 중요한 건 아니지만, 읽는 분들이 곧바로 실험해 볼 수 있게 코드 전체를 적었습니다. 이 CGI 스크립트는 간단한 텍스트 파일 관리자입니다. 다음과 같은 일을 합니다.
*.txt
파일의 내용을 보여줍니다.원래는 실험 결과 이미지를 포함한 HTML 파일 여러 개를 한 눈에 보면서 불 필요한 걸 지우고 중요한 건 다른 폴더로 옮기는 용도로 만들었던 스크립트였습니다.
#!/usr/bin/env perl # index.pl # 현재 폴더 안의 모든 텍스트 파일의 내용을 보여주거나 # 검색한 단어가 들어 있는 파일만 보여주거나 # 선택한 파일들을 삭제하는 스크립트 use strict; use warnings; # no warnings 'redefine'; use CGI; my $HEADING_STYLE = 'background-color: #aaaacc; margin-top: 10pt; padding: 2pt'; my $q = new CGI; main: { print $q->header(-type => "text/html; charset=UTF-8"); # html 헤더 print <<EOF; <head> <title>Manage text files</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <p> EOF # 검색 form print $q->start_form(-action=>"./index.pl"). "\n" . "Text Search : " . $q->textfield('content' , '', 20, 20) . "\n" . "<br /><br />\n" . $q->submit('search', '검 색') . "\n" ; # 선택한 파일 삭제 if ( $q->param('delete') ) { print "<hr />\n"; print "<ul>\n"; foreach my $file ( $q->param('delete_files') ) { unlink $file; print "<li>delete $file</li>\n"; } print "</ul>\n"; } # 모든 파일 또는 검색 텍스트를 포함한 파일들 출력 my @matches = sort glob("*.txt"); my $content = $q->param('content') || ""; if ( $q->param('search') and $content ) { # 파일내용 검색 @matches = grep { text_match($_, $content) } @matches; } print "<hr />\n"; foreach my $file ( @matches ) { print $q->h1({-style=>$HEADING_STYLE}, $file); print $q->checkbox(-name => 'delete_files', label => 'Delete?', -value => $file),"<p>\n"; print "<pre>\n", file_content($file), "\n</pre>\n"; } print "<p>"; print $q->submit('delete', '선택한 파일 삭제'); print $q->end_form(); # html 나머지 부분 출력 print <<EOF; </body> </html> EOF } # $file 을 읽어서 $search 가 매치되는지 여부 반환 sub text_match { my ( $file, $search ) = @_; open my $in, "<", $file; my $text; { local $/ = undef; $text = <$in>; } close $in; if ( $text =~ /$search/i ) { return 1; } return 0; } # $file 파일의 내용 반환 sub file_content { my $file = shift; open my $in, "<", $file; my $text; { local $/ = undef; $text = <$in>; } close $in; return $text; }
다음 스크린샷은 각각의 기능을 테스트하는 모습을 보여줍니다.
그림 1. 테스트하는 모습 (원본)
이 스크립트를 윈도우에서 실행해 보겠습니다. 먼저, CGI 환경을 에뮬레이트해주는 CGI::Emulate::PSGI 모듈을 사용하여 기존 스크립트를 구동하는 PSGI 스크립트를 만듭니다.
#!/usr/bin/env perl # app.psgi use strict; use warnings; use CGI::Emulate::PSGI; use Plack::Builder; my $index = CGI::Emulate::PSGI->handler( sub { do "index.pl"; CGI::initialize_globals() if defined &CGI::initialize_globals; } );
이 스크립트를 plackup
프로그램을 써서 구동시킵니다.
D:\psgi_example> plackup app.psgi HTTP::Server::PSGI: Accepting connections at http://0:5000/
디폴트로 5000번 포트를 사용합니다. 웹브라우저에서 http://127.0.0.1:5000 주소에 접속하면 짜잔~ 똑같은 화면이 나옵니다. 검색이나 파일 삭제 기능도 그대로 동작합니다.
위의 예제에서는 주소에 접속했을 때 무조건 index.pl
스크립트를 띄우게 됩니다.
두 개 이상의 스크립트를 사용할 경우는 Plack::Builder 모듈을 사용하여,
각 스크립트에 대응하는 URL을 장착(mount)해 줍니다.
#!/usr/bin/env perl # multi.psgi use strict; use warnings; use CGI::Emulate::PSGI; use Plack::Builder; my $cgi1 = CGI::Emulate::PSGI->handler( sub { do "cgi1.pl"; CGI::initialize_globals() if defined &CGI::initialize_globals; } ); my $cgi2 = CGI::Emulate::PSGI->handler( sub { do "cgi2.pl"; CGI::initialize_globals() if defined &CGI::initialize_globals; } ); builder { mount "/cgi1.pl" => $cgi1; # URL => 핸들러 mount "/cgi2.pl" => $cgi2; }
또는, 아예 다수 스크립트가 들어있는 디렉토리를 통채로 지정하여 사용할 수도 있습니다. Plack::App::CGIBin 모듈을 사용합니다.
#!perl # bin.psgi use strict; use warnings; use Plack::App::CGIBin; use Plack::Builder; my $app = Plack::App::CGIBin->new(root => "./")->to_app; # "./"은 실제 스크립트가 있는 디렉토리 builder { mount "/" => $app; # 여기에 "/"는 URL에 해당하는 경로 };
http://127.0.0.1:5000/cgi1.pl와 같이 접속할 수 있습니다. 이렇게 해서, 과거에 만들어 사용하던 CGI 스크립트를, 무거운 웹 서버 설치없이 손쉽게 재사용할 수 있었습니다.
1.
plackup
으로 웹 서버를 띄운 상태에서도 CGI 스크립트를 수정하면 변경 사항이 곧바로 반영이 됩니다.
그러나 PSGI 스크립트 쪽을 수정할 경우는 plackup
을 재시작해야 합니다. 이것이 불편하면 --reload | -r
옵션을 쓸 수 있습니다.
plackup -r app.psgi
2.
CGI 스크립트에 서브루틴이 정의되어 있으면 웹 브라우저로 접속할 때마다 서브루틴이 재정의되었다는 경고문이 콘솔 창에
뜹니다. 이것은 CGI 스크립트 쪽에 no warnings 'redefine'
프라그마를 넣어서 없앨 수 있습니다.
3.
제가 실제로 사용했던 스크립트의 경우, 내부에 system()
함수를 써서 외부 프로그램을 실행하는 루틴이 있었는데,
system()
의 인자로 썼던 "path/to/binary"
경로명의 슬래시가 윈도우에서는 문제가 되어서, 백슬래시를 써서
"path\\to\\binary"
형태로 고쳐주어야 했습니다.
Articles by
Seoul Perl Mongers,
Artwork by
Yura Lee
Designed by
Yura Lee
& Hojung Youn,
Edited by
Hojung Youn,
JellyPooo
& Keedi Kim.