Perl CGI 프로그래밍



CGI란

NCSA는 현재 NCSA에서 관리하는 CGI를 다음과 같이 정의합니다.

CGI(Common Gateway Interface), 공통 게이트웨이 인터페이스입니다. 프로그램은 HTTP 서버와 같은 서버에서 실행되어 클라이언트 HTML 페이지와의 인터페이스를 제공합니다.


웹 탐색

CGI의 작동 방식을 더 잘 이해하기 위해 웹 페이지의 링크나 URL을 클릭하는 과정부터 시작할 수 있습니다.

  • 1. 브라우저를 사용하여 URL에 접속하고 HTTP 웹 서버에 연결합니다.

  • 2. 웹 서버는 요청 정보를 받은 후 URL을 구문 분석하여 해당 파일이 서버에 존재하는지 확인하고, 파일의 내용을 반환합니다. 그렇지 않으면 오류 메시지가 반환됩니다.

  • 3. 브라우저는 서버로부터 정보를 받아 수신된 파일이나 오류 메시지를 표시합니다.

CGI 프로그램은 Python 스크립트, PERL 스크립트, SHELL 스크립트, C 또는 C++ 프로그램 등이 될 수 있습니다.


CGI 아키텍처 다이어그램

cgiarch


웹 서버 지원 및 구성

CGI 프로그래밍을 하기 전에 다음 사항을 확인하세요. 웹 서버는 CGI를 지원하며 CGI 처리기가 구성되어 있습니다.

Apache는 CGI 구성을 지원합니다.

CGI 디렉터리 설정:

ScriptAlias /cgi-bin/ /var/www/cgi-bin/

모든 HTTP 서버 실행 CGI 프로그램은 미리 구성된 디렉터리에 저장됩니다. 이 디렉토리를 CGI 디렉토리라고 하며 관례적으로 이름은 /var/www/cgi-bin입니다.

CGI 파일의 확장자는 .cgi이며 Perl도 .pl 확장자를 사용할 수 있습니다.

기본적으로 Linux 서버가 실행되도록 구성된 cgi-bin 디렉터리는 /var/www입니다.

CGI 스크립트를 실행하기 위해 다른 디렉터리를 지정하려면 다음과 같이 httpd.conf 구성 파일을 수정할 수 있습니다.

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options +ExecCGI
   Order allow,deny
   Allow from all
</Directory>

우리가 액세스할 수 있도록 AddHandler에 .pl 접미사를 추가하세요. .pl로 끝나는 Perl 스크립트 파일:

AddHandler cgi-script .cgi .pl .py

첫 번째 CGI 프로그램

아래에서 test.cgi 파일을 생성하고 코드는 다음과 같습니다.

#!/usr/bin/perl

print "Content-type:text/html\r\n\r\n";
print '<html>';
print '<head>';
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print '</head>';
print '<body>';
print '<h2>Hello Word! </h2>';
print '<p>来自php中文网第一个 CGI 程序。</p>';
print '</body>';
print '</html>';

1;

browser http://localhost/cgi-bin/test.cgi를 열면 출력은 다음과 같습니다:

스크립트 첫 번째 줄의 출력 내용은 "Content"입니다. -type: text/htmlrnrn" 브라우저에 전송되며 표시할 콘텐츠 유형이 "text/html"임을 브라우저에 알립니다.


HTTP 헤더

test.cgi 파일 내용의 "Content-type: text/html"은 HTTP 헤더의 일부로 브라우저에 전송되어 이를 알립니다. 브라우저 서버 파일의 콘텐츠 유형입니다.

HTTP 헤더의 형식은 다음과 같습니다.

HTTP 字段名: 字段内容

예:

Content-type:text/html\r\n\r\n

다음 표는 CGI 프로그램에서 HTTP 헤더에 일반적으로 사용되는 정보를 소개합니다.

描述
Content-type:请求的与实体对应的MIME信息。例如: Content-type:text/html
Expires: Date响应过期的日期和时间
Location: URL用来重定向接收方到非请求URL的位置来完成请求或标识新的资源
Last-modified: Date请求资源的最后修改时间
Content-length: N请求的内容长度
Set-Cookie: String设置Http Cookie

CGI 환경 변수

모든 CGI 프로그램은 CGI 프로그램에서 중요한 역할을 하는 다음과 같은 환경 변수를 받습니다.

变量名描述
CONTENT_TYPE这个环境变量的值指示所传递来的信息的MIME类型。目前,环境变量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示数据来自于HTML表单。
CONTENT_LENGTH如果服务器与CGI程序信息的传递方式是POST,这个环境变量即使从标准输入STDIN中可以读到的有效数据的字节数。这个环境变量在读取所输入的数据时必须使用。
HTTP_COOKIE客户机内的 COOKIE 内容。
HTTP_USER_AGENT提供包含了版本数或其他专有数据的客户浏览器信息。
PATH_INFO这个环境变量的值表示紧接在CGI程序名之后的其他路径信息。它常常作为CGI程序的参数出现。
QUERY_STRING如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号'?'分隔。
REMOTE_ADDR这个环境变量的值是发送请求的客户机的IP地址,例如上面的192.168.1.67。这个值总是存在的。而且它是Web客户机需要提供给Web服务器的唯一标识,可以在CGI程序中用它来区分不同的Web客户机。
REMOTE_HOST这个环境变量的值包含发送CGI请求的客户机的主机名。如果不支持你想查询,则无需定义此环境变量。
REQUEST_METHOD提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义。
SCRIPT_FILENAMECGI脚本的完整路径
SCRIPT_NAMECGI脚本的的名称
SERVER_NAME这是你的 WEB 服务器的主机名、别名或IP地址。
SERVER_SOFTWARE这个环境变量的值包含了调用CGI程序的HTTP服务器的名称和版本号。例如,上面的值为Apache/2.2.14(Unix)

다음은 CGI 환경 변수를 출력하는 간단한 CGI 스크립트입니다.

#!/usr/bin/perl

print "Content-type: text/html\n\n";
print '<meta charset="utf-8">';
print "<font size=+1>环境变量:</font>\n";
foreach (sort keys %ENV)
{
  print "<b>$_</b>: $ENV{$_}<br>\n";
}

1;

파일 다운로드

Perl CGI를 통해 파일 다운로드를 구현하려면 다르게 설정해야 합니다. 헤더 정보는 아래와 같습니다.

#!/usr/bin/perl

# HTTP Header
print "Content-Type:application/octet-stream; name=\"FileName\"\r\n";
print "Content-Disposition: attachment; filename=\"FileName\"\r\n\n";

# Actual File Content will go hear.
open( FILE, "<FileName" );
while(read(FILE, $buffer, 100) )
{
   print("$buffer");
}

GET 메서드를 사용하여 데이터를 전송합니다

GET 메서드는 인코딩된 사용자 정보를 서버로 보냅니다. 데이터 정보는 URL에 포함됩니다. 요청된 페이지를 아래와 같이 "?"로 구분합니다.

http://www.test.com/cgi-bin/test.cgi?key1=value1&key2=value2
GET 요청에 대한 기타 참고 사항:
  • GET 요청은 캐시될 수 있습니다

  • GET 요청은 브라우저 기록에 보관

  • GET 요청은 북마크에 추가할 수 있습니다

  • 민감한 데이터를 처리할 때는 GET 요청을 사용하면 안 됩니다

  • GET 요청에는 길이 제한이 있습니다

  • GET 요청은 데이터 검색에만 사용해야 합니다

단순 URL 예: GET 메서드

다음은 GET 메서드를 사용하여 test.cgi 프로그램에 두 개의 매개변수를 보내는 간단한 URL입니다.

/cgi-bin/test.cgi?name=php中文网&url=http://www.php.cn

다음은 test.cgi 파일의 코드입니다. :

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# 读取文本信息
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "GET")
{
   $buffer = $ENV{'QUERY_STRING'};
}
# 读取 name/value 对信息
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex())/eg;
   $FORM{$name} = $value;
}
$name = $FORM{name};
$url  = $FORM{url};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print "</head>";
print "<body>";
print "<h2>$name网址:$url</h2>";
print "</body>";
print "</html>";

1;

브라우저를 보면 다음과 같이 출력됩니다.

간단한 양식 예: GET 메소드

다음은 양식입니다. HTML을 통해 GET 메소드를 사용하여 두 개의 데이터를 서버로 보냅니다. 제출된 서버 스크립트도 test.cgi 파일입니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/test.cgi" method="get">
站点名称: <input type="text" name="name">  <br />

站点 URL: <input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>

브라우저에서 실행 효과가 나타납니다.


POST 방식을 사용하여 데이터를 전송합니다

POST 방식을 사용하여 서버에 데이터를 전송하는 것이 더 안전하고 안정적입니다. 사용자 비밀번호와 같은 일부 민감한 정보는 POST를 사용하여 데이터를 전송해야 합니다.

다음은 브라우저에서 제출한 POST 양식 데이터도 처리할 수 있는 test.cgi입니다.

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# 读取文本信息
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST")
{
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else {
   $buffer = $ENV{'QUERY_STRING'};
}
# 读取 name/value 对信息
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex())/eg;
   $FORM{$name} = $value;
}
$name = $FORM{name};
$url  = $FORM{url};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print "</head>";
print "<body>";
print "<h2>$name网址:$url</h2>";
print "</body>";
print "</html>";

1;

다음은 GET 메서드를 사용하여 두 개의 데이터를 HTML을 통해 전송하는 양식입니다. 서버, submit 서버 스크립트도 test.cgi 파일이고, test.html 코드는

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/test.cgi" method="post">
站点名称: <input type="text" name="name">  <br />

站点 URL: <input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>

브라우저에서 실행 효과는 다음과 같다.

CGI를 통해 프로그램은 체크박스 데이터를 전달합니다

체크박스는 하나 이상의 옵션 데이터를 제출하는 데 사용됩니다. test.html 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/test.cgi" method="POST" target="_blank">
<input type="checkbox" name="php" value="on" /> php中文网
<input type="checkbox" name="google" value="on" /> Google
<input type="submit" value="选择站点" />
</form>
</body>
</html>

다음은 다음과 같습니다. test.cgi 파일의 코드는 다음과 같습니다.

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# 读取信息
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST")
{
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else {
   $buffer = $ENV{'QUERY_STRING'};
}
# 读取 name/value 对信息
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex())/eg;
   $FORM{$name} = $value;
}
if( $FORM{php} ){
   $php_flag ="ON";
}else{
   $php_flag ="OFF";
}
if( $FORM{google} ){
   $google_flag ="ON";
}else{
   $google_flag ="OFF";
}

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print "</head>";
print "<body>";
print "<h2> php中文网选中状态 : $php_flag</h2>";
print "<h2> Google 选择状态 : $google_flag</h2>";
print "</body>";
print "</html>";

1;

브라우저에서 실행 효과는 다음과 같습니다.


CGI 프로그램을 통해 라디오 데이터 전송

라디오는 서버에만 전송합니다. 데이터를 전달하면 test.html 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/test.cgi" method="post" target="_blank">
<input type="radio" name="site" value="php" /> php中文网
<input type="radio" name="site" value="google" /> Google
<input type="submit" value="提交" />
</form>
</body>
</html>

test.cgi 스크립트 코드는 다음과 같습니다.

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# 读取信息
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST")
{
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else {
   $buffer = $ENV{'QUERY_STRING'};
}
# 读取 name/value 对信息
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex())/eg;
   $FORM{$name} = $value;
}
$site = $FORM{site};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print "</head>";
print "<body>";
print "<h2> 选择的网站 $site</h2>";
print "</body>";
print "</html>";

1;

브라우저에서 실행 효과는 다음과 같습니다.


CGI 프로그램을 통해 Textarea 데이터 전송

Textarea 전송 여러 줄의 데이터를 서버에 전송하는 경우 test.html 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/test.cgi" method="post" target="_blank">
<textarea name="textcontent" cols="40" rows="4">
在这里输入内容...
</textarea>
<input type="submit" value="提交" />
</form>
</body>
</html>

test.cgi 스크립트 코드는 다음과 같습니다.

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# 读取信息
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST")
{
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else {
   $buffer = $ENV{'QUERY_STRING'};
}
# 读取 name/value 对信息
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex())/eg;
   $FORM{$name} = $value;
}
$text_content = $FORM{textcontent};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print "</head>";
print "<body>";
print "<h2>输入的文本内容为:$text_content</h2>";
print "</body>";
print "</html>";

1;

브라우저에서 실행 효과는 다음과 같습니다. :


CGI 프로그램을 통해 드롭다운 데이터 전송

HTML 드롭다운 상자 코드 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/test.cgi" method="post" target="_blank">
<select name="dropdown">
<option value="php" selected>php中文网</option>
<option value="google">Google</option>
</select>
<input type="submit" value="提交"/>
</form>
</body>
</html>

test .cgi 스크립트 코드는 다음과 같습니다:

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# 读取信息
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST")
{
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else {
   $buffer = $ENV{'QUERY_STRING'};
}
# 读取 name/value 对信息
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex())/eg;
   $FORM{$name} = $value;
}
$site = $FORM{dropdown};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print '<meta charset="utf-8">';
print '<title>php中文网(php.cn)</title>';
print "</head>";
print "<body>";
print "<h2>选择的网站是:$site</h2>";
print "</body>";
print "</html>";

1;

브라우저에서 실행 효과는 다음과 같습니다.


CGI에서 쿠키 사용

http 프로토콜의 큰 단점 단지 사용자의 신원을 판단하지 않는다는 점은 프로그래머들에게 큰 불편을 안겨줍니다. 쿠키 기능의 등장으로 이러한 단점이 보완되었습니다.

쿠키는 고객이 스크립트에 접속할 때 고객의 브라우저를 통해 고객의 하드디스크에 기록되는 데이터를 쓰는 것입니다. , 신원 식별 기능을 달성하기 위해 다음 번에 고객이 스크립트에 액세스할 때 데이터 정보가 검색됩니다. 쿠키는 신원 확인에 자주 사용됩니다.

 

쿠키 구문

http 쿠키는 파일 전송보다 빠른 http 헤더를 통해 전송됩니다. 헤더의 set-cookie 구문은 다음과 같습니다.

Set-cookie:name=name;expires=date;path=path;domain=domain;secure
  • name=name: 쿠키 ​​값을 설정해야 합니다(name은 ";" 및 ","을 사용할 수 없음). 다수 ";"을 사용하여 이름 값을 구분합니다(예: name1=name1;name2=name2;name3=name3).

  • expires=date: 쿠키 ​​유효 기간, 형식:expires="Wdy,DD-Mon-YYYY HH:MM:SS"


  • path=path: path가 경로인 경우 쿠키가 여기에 위치합니다. 모든 파일과 하위 디렉터리에 유효합니다(예: path="/cgi-bin/"). path가 파일인 경우 쿠키는 이 파일에 유효합니다(예: path="/cgi-bin/cookie). cgi".

  • domain=domain: 쿠키에 유효한 도메인 이름(예: domain="www.php.cn"

  • <🎜) >
  • secure: 이 플래그가 제공되면 쿠키는 SSL 프로토콜의 https 서버를 통해서만 전달될 수 있음을 의미합니다.

  • 쿠키 수신은 환경 변수 HTTP_COOKIE를 설정하여 이루어집니다. CGI 프로그램은 이 변수를 검색하여 쿠키 정보를 얻을 수 있습니다.


쿠키 설정

쿠키 설정은 매우 간단합니다. 쿠키는 http 헤더에 별도로 전송됩니다. 다음 예는 쿠키에 UserID, Password 및 만료를 설정합니다.

#!/usr/bin/perl

print "Set-Cookie:UserID=XYZ;\n";
print "Set-Cookie:Password=XYZ123;\n";
print "Set-Cookie:Expires=Tuesday, 31-Dec-2017 23:12:40 GMT";\n";
print "Set-Cookie:Domain=www.php.cn;\n";
print "Set-Cookie:Path=/perl;\n";
print "Content-type:text/html\r\n\r\n";
...........其他 HTML 内容

Find Cookie

쿠키 정보 검색 페이지는 매우 간단합니다. 쿠키 정보는 CGI 환경 변수인 HTTP_COOKIE에 저장되며 저장 형식은 다음과 같습니다.

#!/usr/bin/perl
$rcvd_cookies = $ENV{'HTTP_COOKIE'};
@cookies = split /;/, $rcvd_cookies;
foreach $cookie ( @cookies ){
   ($key, $val) = split(/=/, $cookie); # splits on the first =.
   $key =~ s/^\s+//;
   $val =~ s/^\s+//;
   $key =~ s/\s+$//;
   $val =~ s/\s+$//;
   if( $key eq "UserID" ){
      $user_id = $val;
   }elsif($key eq "Password"){
      $password = $val;
   }
}
print "User ID  = $user_id\n";
print "Password = $password\n";

위 예제의 출력 결과는 다음과 같습니다.

User ID = XYZ
Password = XYZ123


CGI 모듈

Perl은 다음 두 가지 내장 CGI 모듈을 제공합니다. 일반적으로 사용되는 모듈:

  • CGI 모듈

  • Berkeley cgi-lib.pl