사용자의 입력은 요청한 방법이 GET이냐 POST이냐에 따라 달라진다. 따라서 사용자의 입력을 읽기위해서는 먼저 REQUEST_METHOD를 이용해서 요청 방법을 판정해야 한다.
GET
사용자의 요청 방법이 GET인 경우 사용자의 입력은 QUERY_STRING이라는 환경 변수에 저장 되므로 %ENV를 이용해서 사용자의 입력을 읽으면 된다.
@query = <STDIN>; # STDIN으로 전달되는 모든 값을 읽음
# <INPUT> 태그의 Type을 FILE로 하고
# <FORM> 태그의 ENCTYPE을 multipart/form-data로
# 한경우에 사용된다.
$query = <STDIN>; # STDIN으로 전달되는 값중 한줄만 읽는다.
# Method가 POST인 경우에 사용.
$ret = read(STDIN, $inputstring, $length);
# Method가 POST인 경우, 전부 사용할 수 있다.
# 읽을 바이트의 수는 CONTENT_LENGTH로 판정한다.
POST
사용자의 요청방법이 POST라면 사용자의 입력 STDIN을 통해 전달된다. 따라서 사용자의 입력은 다음과 같은 방법으로 읽을 수 있다.
read FILEHANDLE,SCALAR,LENGTH
read FILEHANDLE,SCALAR,LENGTH,OFFSET
FILEHANDLE : 읽고자하는 파일핸들.
SCALAT : 읽은 내용을 저장할 스칼라변수
LENGTH : 읽을 바이트의 수
OFFSET : 건너뛸 바이트의 수
@query = <STDIN>;
Method가 POST인 경우 사용자의 입력은 STDIN으로 전달된다. 펄에서는 파일핸들을 처리하는 상당히 다양한 방법을 제공하는데, 그중 하나가 <> 연산자 이다. <> 연산자는 앞어 언급했든 파일을 읽을 때 줄단위(개행문자까지)로 읽는다.
<STDIN>을 @query와 같이 배열(배열환경)로 받으면 한줄이아니라 STDIN으로 전달된 모든 데이터를 읽을 수 있다.
이 방법은 주로 <INPUT> 태그의 Type을 FILE로 하고 <FORM> 태그의 ENCTYPE을 multipart/form-data로 한경우에 사용된다.
$query = <STDIN>;
위의 문장과 동일한 문장이다. 다만 <STDIN>을 $query(스칼라 환경)로 받으면 STDIN으로 전달된 데이터의 전부가 아니라 오로지 한줄만 읽게된다.
이 방법은 주로 <FORM> 태그의 Method가 POST이고, ENCTYPE이 application/x-www-form-urlencoded인 경우에 사용된다.
$ret = read(STDIN, $inputstring, $length);
STDIN을 <> 연산자를 사용해서 읽는 경우 전송된 데이터를 잘못읽을 수 있으며, 오류가 발생한 경우에도 오류가 발생한 사실을 알 수 없다. 따라서 사용자의 입력을 처리하는 일반적인 방법은 read 함수이다.
사용형식
if($ret != $length) {
&cgi_die("오류", "STDIN을 읽는 중에 알 수 없는 오류가 발생했습니다");
}
설명
read 함수는 FILEHANDLE로부터 데이터를 LENGTH 바이트만큼 읽어 SCALAR 변수에 저장하며 읽을 바이트 수를 리턴한다.
따라서 read 함수를 이용해서 파일핸들을 읽는 경우 리턴 값과 LENGTH를 조사해서 데이터가 정상적으로 읽혀졌는지는 조사해야 한다.
print "Off-Line Mode: name1=value1&name2=value2\n";
chop($inputsting = <STDIN>); # 키보드에서 직접읽는 것이므로 chop 함수를
# 이용해서 개행문자를 삭제한다.
GET이나 POST가 아닌 경우.
사용자의 요청이 GET이나 POST가 아닌 경우는 Unix 명령행에서 CGI 프로그램을 실행한 경우이다.
일반적으로 CGI 프로그램을 디버깅하는 것은 상당히 까다로운데 그 이유는 CGI 프로그램의 입력은 웹상에서만 주어지며, Unix 명령행에서는 그 입력을 줄수 없기 때문이다.
따라서 Method가 GET이나 POST가 아닌 경우에는 CGI 입력을 명령행에서 읽어들이도록 처리한 것이다. 즉, CGI를 Unix 명령행에서 실행하고 URL 인코딩 형식으로 입력을 주면된다.
위의 방법을 이용하면 요청방법이 무엇이든지 사용자의 입력은 $inputstring라는 변수에 저장되며 사용자의 입력은 URL 인코딩되서 전달되므로 다음과 같은 형식을 갖게된다.
16: @in = split(/&/, $inputstring);
따라서 $inputstring를 split을 이용해서 분리하면 사용자의 입력과 <FORM>의 이름을 분리할 수 있다.
19: ($name, $value) = split(/=/, $in[$_], 2);
name=value 쌍이 몇 개가 될지 모르므로 split한 결과를 @in이라는 배열로 받았다.
18: $in[$_] =~ s/\+/ /g; # '+'를 공백문자로
일단 name=value 쌍으로 분리되며, 이 값은 항상 name과 value 값으로 구성되므로 ($name, $value)로 받은 것이다.
+를 공백으로 변환
폼에서 사용자가 입력한 공백은 +로 변환되어 CGI에 전달된다. 따라서 이러한 +를 공백으로 대치하기위해서는 앞에서 배운 패턴대치를 사용하면 된다.
22: $name =~ s/%(..)/pack("c", hex())/ge;
+는 정규식에서 하나 이상의 앞문자를 반복시키는 메타문자이므로 역슬래쉬(\)를 사용했다.
%HH를 원래의 문자로 변환
몇몇 구두점과 영어 대소문자를 제외한 모든 문자는 %HH 형식으로 변환되어 CGI로 전달된다. 따라서 %HH 형식을 원래의 문자로 변환해야 한다.
pack TEMPLATE,LIST
TEMPLATE
A ASCII 문자열. 공백이 삽입됨
a ASCII 문자열. Null이 삽입됨
b 비트 문자열(내림차순)
B 비트 문자열(오르차순)
h 16진수 문자열(하위 4비트를 먼저 표시)
H 16진수 문자열(상위 4비트를 먼저 표시)
c 부호를 갖는 문자값
C 부호를 갖지 않는 문자값
s 부호를 갖는 정수(Short 형)
S 부호를 갖지 않는 정수(Short 형)
I 부호를 갖는 정수
I 부호를 갖지 않는 정수
l 부호를 갖는 정수(Long 형)
L 부호를 갖지 않는 정수(Long 형)
%(..)
%HH 형식의 패턴을 검색하고, 일치되는 패턴이 있는 경우 $1에 저장
hex($1)
$1(HH)을 10진수로 변환. 펄에서 연산의 기준은 항상 10진수 이므로 16진수인 HH를 10진수 변환하기위해 사용되었다.
pack("c", hex($1))