Python 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 아키텍처 다이어그램

1026.png


웹 서버 지원 및 구성

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

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

CGI 디렉터리 설정:

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

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

CGI 파일의 확장자는 .cgi이며, 파이썬에서도 .py 확장자를 사용할 수 있습니다.

기본적으로 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에 .py 접미사를 추가하세요. .py로 끝나는 python 스크립트 파일:

AddHandler cgi-script .cgi .pl .py

첫 번째 CGI 프로그램

Python을 사용하여 첫 번째 CGI 프로그램을 만들며 파일 이름은 hello.py이고 파일은 다음과 같습니다. /var/에 위치 www/cgi-bin 디렉터리의 내용은 다음과 같습니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

print "Content-type:text/html"
print                               # 空行,告诉服务器结束头部
print '<html>'
print '<head>'
print '<meta charset="utf-8">'
print '<title>Hello Word - 我的第一个 CGI 程序!</title>'
print '</head>'
print '<body>'
print '<h2>Hello Word! 我是来自php中文网的第一CGI程序</h2>'
print '</body>'
print '</html>'

파일을 저장한 후 hello.py를 수정하고 파일 권한을 755로 수정합니다.

chmod 755 hello.py

위 프로그램은 브라우저에서 액세스할 때 다음 결과를 표시합니다.

1026.jpg

이 hello.py 스크립트는 간단한 Python 스크립트입니다. "Content-type: text/html" 스크립트가 브라우저로 전송되어 브라우저에 표시되는 콘텐츠 유형이 "text/html"임을 알려줍니다.

print를 사용하여 빈 줄을 출력하여 서버에 헤더 정보를 끝내도록 지시합니다.


HTTP 헤더

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

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

HTTP 字段名: 字段内容

예:

Content-type: text/html

다음 표는 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/python
# -*- coding: UTF-8 -*-
# filename:test.py

import os

print "Content-type: text/html"
print
print "<meta charset=\"utf-8\">"
print "<b>环境变量</b><br>";
print "<ul>"
for key in os.environ.keys():
    print "<li><span style='color:green'>%30s </span> : %s </li>" % (key,os.environ[key])
print "</ul>"

위의 내용을 test.py로 저장하고, 파일 권한을 755로 수정합니다. 실행 결과는 다음과 같습니다.

1027.jpg


GET 및 POST 방식

브라우저 클라이언트는 GET 방식과 POST 방식 두 가지 방식으로 서버에 정보를 전송합니다.

GET 방식으로 데이터 전송

GET 방식은 인코딩된 사용자 정보를 서버로 전송합니다. 데이터 정보는 요청한 페이지의 URL에 "?"로 구분되어 포함됩니다.

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

  • GET 요청은 브라우저 기록에 남아 있습니다

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

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

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

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

간단한 URL 예: GET 메서드

다음 GET 메소드를 사용하여 hello_get.py 프로그램에 두 개의 매개변수를 보내는 간단한 URL입니다:

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

다음은 hello_get.py 파일의 코드입니다:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# filename:test.py

# CGI处理模块
import cgi, cgitb 

# 创建 FieldStorage 的实例化
form = cgi.FieldStorage() 

# 获取数据
site_name = form.getvalue('name')
site_url  = form.getvalue('url')

print "Content-type:text/html"
print
print "<html>"
print "<head>"
print "<meta charset=\"utf-8\">"
print "<title>php中文网 CGI 测试实例</title>"
print "</head>"
print "<body>"
print "<h2>%s官网:%s</h2>" % (site_name, site_url)
print "</body>"
print "</html>"

저장 후 hello_get 수정 py에서 파일 권한을 755로 수정합니다:

chmod 755 hello_get.py

브라우저 요청 출력 결과:

1028.jpg

간단한 형식 예: GET 메서드

아래 GET 메소드를 사용하여 두 개의 데이터를 서버로 보내는 HTML 형식입니다. 제출된 서버 스크립트도 hello_get.html 코드는 다음과 같습니다.

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

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

기본적으로. , cgi-bin 디렉토리만 저장할 수 있습니다. 스크립트 파일의 경우 hello_get.html을 test 디렉토리에 저장하고 파일 권한을 755로 수정합니다.

chmod 755 hello_get.html

Gif 데모는 다음과 같습니다.

hello_get.gif

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

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

다음은 브라우저에서 제출한 POST 폼 데이터도 처리할 수 있는 hello_get.py입니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# CGI处理模块
import cgi, cgitb 

# 创建 FieldStorage 的实例化
form = cgi.FieldStorage() 

# 获取数据
site_name = form.getvalue('name')
site_url  = form.getvalue('url')

print "Content-type:text/html"
print
print "<html>"
print "<head>"
print "<meta charset=\"utf-8\">"
print "<title>php中文网 CGI 测试实例</title>"
print "</head>"
print "<body>"
print "<h2>%s官网:%s</h2>" % (site_name, site_url)
print "</body>"
print "</html>"

다음은 POST 메서드를 통한 폼입니다(method="post" ) 서버 스크립트 hello_get.py에 데이터를 제출합니다:

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

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

Gif 데모는 다음과 같습니다.

hello_post.gif

CGI 프로그램을 통해 체크박스 데이터 전달

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

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/checkbox.py" 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>

다음은 checkbox.py 파일의 코드입니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('google'):
   google_flag = "是"
else:
   google_flag = "否"

if form.getvalue('php'):
   php_flag = "是"
else:
   php_flag = "否"

print "Content-type:text/html"
print
print "<html>"
print "<head>"
print "<meta charset=\"utf-8\">"
print "<title>php中文网 CGI 测试实例</title>"
print "</head>"
print "<body>"
print "<h2> php中文网是否选择了 : %s</h2>" % php_flag
print "<h2> Google 是否选择了 : %s</h2>" % google_flag
print "</body>"
print "</html>"

Modify checkbox .py 권한:

chmod 755 checkbox.py

브라우저 액세스 Gif 데모 이미지:

checkbox.gif

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

라디오는 하나의 데이터만 서버로 전송하며, HTML 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/radiobutton.py" 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>

radiobutton.py 스크립트 코드는 다음과 같습니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('site'):
   site = form.getvalue('site')
else:
   site = "提交数据为空"

print "Content-type:text/html"
print
print "<html>"
print "<head>"
print "<meta charset=\"utf-8\">"
print "<title>php中文网 CGI 测试实例</title>"
print "</head>"
print "<body>"
print "<h2> 选中的网站是 %s</h2>" % site
print "</body>"
print "</html>"

radiobutton .py 권한 수정:

chmod 755 radiobutton.py

브라우저 액세스 Gif 데모 이미지:

radiobutton.gif

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

Textarea는 여러 메시지를 서버 행 데이터로 전송합니다. HTML 코드는 다음과 같습니다:

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

textarea.py 스크립트 코드는 다음과 같습니다:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('textcontent'):
   text_content = form.getvalue('textcontent')
else:
   text_content = "没有内容"

print "Content-type:text/html"
print
print "<html>"
print "<head>";
print "<meta charset=\"utf-8\">"
print "<title>php中文网 CGI 测试实例</title>"
print "</head>"
print "<body>"
print "<h2> 输入的内容是:%s</h2>" % text_content
print "</body>"
print "</html>"

textarea.py 수정:

chmod 755 textarea.py

브라우저 액세스 Gif 데모 이미지:

textarea.gif

CGI 프로그램을 통해 드롭다운 데이터를 전달합니다.

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

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<form action="/cgi-bin/dropdown.py" 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>

dropdown.py 스크립트 코드는 다음과 같습니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('dropdown'):
   dropdown_value = form.getvalue('dropdown')
else:
   dropdown_value = "没有内容"

print "Content-type:text/html"
print
print "<html>"
print "<head>"
print "<meta charset=\"utf-8\">"
print "<title>php中文网 CGI 测试实例</title>"
print "</head>"
print "<body>"
print "<h2> 选中的选项是:%s</h2>" % dropdown_value
print "</body>"
print "</html>"

dropdown.py 권한 수정:

chmod 755 dropdown.py

브라우저 Gif 데모 이미지 방문:

dropdown.gif


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 헤더에 별도로 전송됩니다. 다음 예에서는 쿠키에 이름을 설정하고 만료됩니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 
print 'Content-Type: text/html'
print 'Set-Cookie: name="php中文网";expires=Wed, 28 Aug 2016 18:30:00 GMT'
print
print """
<html>
	<head>
		<meta charset="utf-8">
		<title>php中文网(php.cn)</title>
	</head>
    <body>
        <h1>Cookie set OK!</h1>
    </body>
</html>
"""

위 코드를 cookie_set.py에 저장하고 cookie_set.py 권한을 수정합니다.

chmod 755 cookie_set.py

위 예에서는 Set- 쿠키 헤더 정보 쿠키 정보를 설정하기 위해 만료 시간, 도메인 이름, 경로 등 쿠키의 다른 속성을 선택적 옵션에 설정합니다. 이 정보는 "Content-type:text/html" 앞에 설정됩니다.


쿠키 정보 검색

쿠키 정보 검색 페이지는 매우 간단합니다. 쿠키 정보는 CGI 환경 변수 HTTP_COOKIE에 저장됩니다.

key1=value1;key2=value2;key3=value3....

다음은 쿠키 정보를 검색하는 간단한 CGI 프로그램입니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 导入模块
import os
import Cookie

print "Content-type: text/html"
print

print """
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
<h1>读取cookie信息</h1>
"""

if 'HTTP_COOKIE' in os.environ:
    cookie_string=os.environ.get('HTTP_COOKIE')
    c=Cookie.SimpleCookie()
    c.load(cookie_string)

    try:
        data=c['name'].value
        print "cookie data: "+data+"<br>"
    except KeyError:
        print "cookie 没有设置或者已过去<br>"
print """
</body>
</html>

"""

위 코드를 cookie_get.py에 저장하고 cookie_get.py 권한을 수정합니다.

chmod 755 cookie_get.py

위 쿠키 설정 색상 Gif

cookie.gif

파일 업로드 예시

파일 업로드를 위한 HTML 설정 양식에서 enctype 속성을 ​​으로 설정해야 합니다. multipart/form-data 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
 <form enctype="multipart/form-data" 
                     action="/cgi-bin/save_file.py" method="post">
   <p>选中文件: <input type="file" name="filename" /></p>
   <p><input type="submit" value="上传" /></p>
   </form>
</body>
</html>

save_file.py 스크립트 파일 코드는 다음과 같습니다.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import cgi, os
import cgitb; cgitb.enable()

form = cgi.FieldStorage()

# 获取文件名
fileitem = form['filename']

# 检测文件是否上传
if fileitem.filename:
   # 设置文件路径 
   fn = os.path.basename(fileitem.filename)
   open('/tmp/' + fn, 'wb').write(fileitem.file.read())

   message = '文件 "' + fn + '" 上传成功'
   
else:
   message = '文件没有上传'
   
print """\
Content-Type: text/html\n
<html>
<head>
<meta charset="utf-8">
<title>php中文网(php.cn)</title>
</head>
<body>
   <p>%s</p>
</body>
</html>
""" % (message,)

위 코드를 save_file.py에 저장하고 수정합니다. save_file.py 권한:

chmod 755 save_file.py

위 쿠키 설정 색상 Gif는 다음과 같습니다.

savefile.gif

사용하는 시스템이 Unix/Linux인 경우 반드시 파일 구분 기호를 바꾸십시오. 창에서는 open( ) 문만 사용해야 합니다:

fn = os.path.basename(fileitem.filename.replace("\", "/" ))

파일 다운로드 대화 상자

먼저 현재 디렉터리에 foo.txt 파일을 만듭니다. 프로그램을 다운로드하기 위해.

파일 다운로드는 HTTP 헤더 정보를 설정하여 이루어집니다. 함수 코드는

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# HTTP 头部
print "Content-Disposition: attachment; filename=\"foo.txt\"";
print
# 打开文件
fo = open("foo.txt", "rb")

str = fo.read();
print str

# 关闭文件
fo.close()
입니다.