Python - Lập trình CGI

Giao diện cổng chung, hoặc CGI, là một tập hợp các tiêu chuẩn xác định cách thông tin được trao đổi giữa máy chủ web và tập lệnh tùy chỉnh. Các thông số kỹ thuật CGI hiện được duy trì bởi NCSA.

CGI là gì?

  • Giao diện cổng thông thường, hoặc CGI, là một tiêu chuẩn cho các chương trình cổng bên ngoài để giao tiếp với máy chủ thông tin như máy chủ HTTP.

  • Phiên bản hiện tại là CGI / 1.1 và CGI / 1.2 đang được hoàn thiện.

Duyệt web

Để hiểu khái niệm về CGI, chúng ta hãy xem điều gì sẽ xảy ra khi chúng ta nhấp vào một siêu liên kết để duyệt qua một trang web hoặc URL cụ thể.

  • Trình duyệt của bạn liên hệ với máy chủ web HTTP và yêu cầu URL, tức là tên tệp.

  • Máy chủ Web phân tích cú pháp URL và tìm kiếm tên tệp. Nếu nó tìm thấy tệp đó thì hãy gửi nó trở lại trình duyệt, nếu không sẽ gửi thông báo lỗi cho biết rằng bạn đã yêu cầu một tệp sai.

  • Trình duyệt web nhận phản hồi từ máy chủ web và hiển thị tệp đã nhận hoặc thông báo lỗi.

Tuy nhiên, có thể thiết lập máy chủ HTTP để bất cứ khi nào tệp trong một thư mục nhất định được yêu cầu, tệp đó sẽ không được gửi lại; thay vào đó, nó được thực thi như một chương trình và bất cứ thứ gì mà chương trình đó xuất ra đều được gửi lại để trình duyệt của bạn hiển thị. Chức năng này được gọi là Giao diện cổng chung hoặc CGI và các chương trình được gọi là tập lệnh CGI. Các chương trình CGI này có thể là Python Script, PERL Script, Shell Script, chương trình C hoặc C ++, v.v.

Sơ đồ kiến ​​trúc CGI

Hỗ trợ và cấu hình máy chủ web

Trước khi bạn tiến hành Lập trình CGI, hãy đảm bảo rằng Máy chủ Web của bạn hỗ trợ CGI và nó được cấu hình để xử lý các Chương trình CGI. Tất cả các Chương trình CGI sẽ được thực thi bởi máy chủ HTTP được lưu giữ trong một thư mục được cấu hình trước. Thư mục này được gọi là Thư mục CGI và theo quy ước, nó được đặt tên là / var / www / cgi-bin. Theo quy ước, các tệp CGI có phần mở rộng là.cgi, nhưng bạn có thể giữ các tệp của mình bằng tiện ích mở rộng python .py cũng.

Theo mặc định, máy chủ Linux được định cấu hình để chỉ chạy các tập lệnh trong thư mục cgi-bin trong / var / www. Nếu bạn muốn chỉ định bất kỳ thư mục nào khác để chạy các tập lệnh CGI của mình, hãy nhận xét các dòng sau trong tệp httpd.conf -

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

<Directory "/var/www/cgi-bin">
Options All
</Directory>

Ở đây, chúng tôi giả định rằng bạn đã thiết lập và chạy thành công Máy chủ Web và bạn có thể chạy bất kỳ chương trình CGI nào khác như Perl hoặc Shell, v.v.

Chương trình CGI đầu tiên

Đây là một liên kết đơn giản, được liên kết với tập lệnh CGI có tên hello.py . Tệp này được lưu trong thư mục / var / www / cgi-bin và có nội dung sau. Trước khi chạy chương trình CGI, hãy đảm bảo rằng bạn đã thay đổi chế độ tệp bằng cách sử dụngchmod 755 hello.py Lệnh UNIX để thực thi tệp.

#!/usr/bin/python

print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Hello World - First CGI Program</title>'
print '</head>'
print '<body>'
print '<h2>Hello World! This is my first CGI program</h2>'
print '</body>'
print '</html>'

Nếu bạn nhấp vào hello.py, thì điều này sẽ tạo ra kết quả sau:

Chào thế giới! Đây là chương trình CGI đầu tiên của tôi

Tập lệnh hello.py này là một tập lệnh Python đơn giản, viết đầu ra của nó trên tệp STDOUT, tức là màn hình. Có một tính năng quan trọng và bổ sung có sẵn đó là dòng đầu tiên được inContent-type:text/html\r\n\r\n. Dòng này được gửi trở lại trình duyệt và nó chỉ định loại nội dung sẽ được hiển thị trên màn hình trình duyệt.

Đến đây chắc hẳn bạn đã hiểu khái niệm cơ bản về CGI và bạn có thể viết nhiều chương trình CGI phức tạp bằng Python. Tập lệnh này có thể tương tác với bất kỳ hệ thống bên ngoài nào khác cũng để trao đổi thông tin như RDBMS.

Tiêu đề HTTP

Dòng Content-type:text/html\r\n\r\nlà một phần của tiêu đề HTTP được gửi đến trình duyệt để hiểu nội dung. Tất cả tiêu đề HTTP sẽ ở dạng sau:

HTTP Field Name: Field Content

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

Có một số tiêu đề HTTP quan trọng khác mà bạn sẽ sử dụng thường xuyên trong Lập trình CGI của mình.

Sr.No. Tiêu đề & Mô tả
1

Content-type:

Một chuỗi MIME xác định định dạng của tệp được trả về. Ví dụ là Content-type: text / html

2

Expires: Date

Ngày thông tin trở nên không hợp lệ. Nó được trình duyệt sử dụng để quyết định khi nào một trang cần được làm mới. Chuỗi ngày hợp lệ có định dạng 01/01/1998 12:00:00 GMT.

3

Location: URL

URL được trả về thay vì URL được yêu cầu. Bạn có thể sử dụng trường này để chuyển hướng một yêu cầu đến bất kỳ tệp nào.

4

Last-modified: Date

Ngày sửa đổi cuối cùng của tài nguyên.

5

Content-length: N

Độ dài, tính bằng byte, của dữ liệu được trả về. Trình duyệt sử dụng giá trị này để báo cáo thời gian tải xuống ước tính cho một tệp.

6

Set-Cookie: String

Đặt cookie được chuyển qua chuỗi

Biến môi trường CGI

Tất cả các chương trình CGI đều có quyền truy cập vào các biến môi trường sau. Các biến này đóng một vai trò quan trọng trong khi viết bất kỳ chương trình CGI nào.

Sr.No. Tên và mô tả biến
1

CONTENT_TYPE

Kiểu dữ liệu của nội dung. Được sử dụng khi máy khách đang gửi nội dung đính kèm đến máy chủ. Ví dụ: tải lên tệp.

2

CONTENT_LENGTH

Độ dài của thông tin truy vấn. Nó chỉ có sẵn cho các yêu cầu ĐĂNG.

3

HTTP_COOKIE

Trả về các cookie đã đặt ở dạng cặp khóa & giá trị.

4

HTTP_USER_AGENT

Trường tiêu đề yêu cầu Tác nhân người dùng chứa thông tin về tác nhân người dùng bắt nguồn yêu cầu. Nó là tên của trình duyệt web.

5

PATH_INFO

Đường dẫn cho tập lệnh CGI.

6

QUERY_STRING

Thông tin mã hóa URL được gửi với yêu cầu phương thức GET.

7

REMOTE_ADDR

Địa chỉ IP của máy chủ từ xa thực hiện yêu cầu. Đây là cách ghi nhật ký hữu ích hoặc để xác thực.

số 8

REMOTE_HOST

Tên đầy đủ đủ điều kiện của máy chủ thực hiện yêu cầu. Nếu thông tin này không có sẵn, thì REMOTE_ADDR có thể được sử dụng để lấy địa chỉ IR.

9

REQUEST_METHOD

Phương pháp được sử dụng để thực hiện yêu cầu. Các phương pháp phổ biến nhất là GET và POST.

10

SCRIPT_FILENAME

Đường dẫn đầy đủ đến tập lệnh CGI.

11

SCRIPT_NAME

Tên của tập lệnh CGI.

12

SERVER_NAME

Tên máy chủ hoặc Địa chỉ IP của máy chủ

13

SERVER_SOFTWARE

Tên và phiên bản của phần mềm mà máy chủ đang chạy.

Here is small CGI program to list out all the CGI variables. Click this link to see the result Get Environment

#!/usr/bin/python

import os

print "Content-type: text/html\r\n\r\n";
print "<font size=+1>Environment</font><\br>";
for param in os.environ.keys():
   print "<b>%20s</b>: %s<\br>" % (param, os.environ[param])

GET and POST Methods

You must have come across many situations when you need to pass some information from your browser to web server and ultimately to your CGI Program. Most frequently, browser uses two methods two pass this information to web server. These methods are GET Method and POST Method.

Passing Information using GET method

The GET method sends the encoded user information appended to the page request. The page and the encoded information are separated by the ? character as follows −

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2

The GET method is the default method to pass information from browser to web server and it produces a long string that appears in your browser's Location:box. Never use GET method if you have password or other sensitive information to pass to the server. The GET method has size limitation: only 1024 characters can be sent in a request string. The GET method sends information using QUERY_STRING header and will be accessible in your CGI Program through QUERY_STRING environment variable.

You can pass information by simply concatenating key and value pairs along with any URL or you can use HTML <FORM> tags to pass information using GET method.

Simple URL Example:Get Method

Here is a simple URL, which passes two values to hello_get.py program using GET method.

/cgi-bin/hello_get.py?first_name=ZARA&last_name=ALI

Below is hello_get.py script to handle input given by web browser. We are going to use cgi module, which makes it very easy to access passed information −

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

This would generate the following result −

Hello ZARA ALI

Simple FORM Example:GET Method

This example passes two values using HTML FORM and submit button. We use same CGI script hello_get.py to handle this input.

<form action = "/cgi-bin/hello_get.py" method = "get">
First Name: <input type = "text" name = "first_name">  <br />

Last Name: <input type = "text" name = "last_name" />
<input type = "submit" value = "Submit" />
</form>

Here is the actual output of the above form, you enter First and Last Name and then click submit button to see the result.

Passing Information Using POST Method

A generally more reliable method of passing information to a CGI program is the POST method. This packages the information in exactly the same way as GET methods, but instead of sending it as a text string after a ? in the URL it sends it as a separate message. This message comes into the CGI script in the form of the standard input.

Below is same hello_get.py script which handles GET as well as POST method.

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

Let us take again same example as above which passes two values using HTML FORM and submit button. We use same CGI script hello_get.py to handle this input.

<form action = "/cgi-bin/hello_get.py" method = "post">
First Name: <input type = "text" name = "first_name"><br />
Last Name: <input type = "text" name = "last_name" />

<input type = "submit" value = "Submit" />
</form>

Here is the actual output of the above form. You enter First and Last Name and then click submit button to see the result.

Passing Checkbox Data to CGI Program

Checkboxes are used when more than one option is required to be selected.

Here is example HTML code for a form with two checkboxes −

<form action = "/cgi-bin/checkbox.cgi" method = "POST" target = "_blank">
<input type = "checkbox" name = "maths" value = "on" /> Maths
<input type = "checkbox" name = "physics" value = "on" /> Physics
<input type = "submit" value = "Select Subject" />
</form>

The result of this code is the following form −

Below is checkbox.cgi script to handle input given by web browser for checkbox button.

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('maths'):
   math_flag = "ON"
else:
   math_flag = "OFF"

if form.getvalue('physics'):
   physics_flag = "ON"
else:
   physics_flag = "OFF"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Checkbox - Third CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> CheckBox Maths is : %s</h2>" % math_flag
print "<h2> CheckBox Physics is : %s</h2>" % physics_flag
print "</body>"
print "</html>"

Passing Radio Button Data to CGI Program

Radio Buttons are used when only one option is required to be selected.

Here is example HTML code for a form with two radio buttons −

<form action = "/cgi-bin/radiobutton.py" method = "post" target = "_blank">
<input type = "radio" name = "subject" value = "maths" /> Maths
<input type = "radio" name = "subject" value = "physics" /> Physics
<input type = "submit" value = "Select Subject" />
</form>

The result of this code is the following form −

Below is radiobutton.py script to handle input given by web browser for radio button −

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('subject'):
   subject = form.getvalue('subject')
else:
   subject = "Not set"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Radio - Fourth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

Passing Text Area Data to CGI Program

TEXTAREA element is used when multiline text has to be passed to the CGI Program.

Here is example HTML code for a form with a TEXTAREA box −

<form action = "/cgi-bin/textarea.py" method = "post" target = "_blank">
<textarea name = "textcontent" cols = "40" rows = "4">
Type your text here...
</textarea>
<input type = "submit" value = "Submit" />
</form>

The result of this code is the following form −

Below is textarea.cgi script to handle input given by web browser −

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('textcontent'):
   text_content = form.getvalue('textcontent')
else:
   text_content = "Not entered"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>";
print "<title>Text Area - Fifth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Entered Text Content is %s</h2>" % text_content
print "</body>"

Passing Drop Down Box Data to CGI Program

Drop Down Box is used when we have many options available but only one or two will be selected.

Here is example HTML code for a form with one drop down box −

<form action = "/cgi-bin/dropdown.py" method = "post" target = "_blank">
<select name = "dropdown">
<option value = "Maths" selected>Maths</option>
<option value = "Physics">Physics</option>
</select>
<input type = "submit" value = "Submit"/>
</form>

The result of this code is the following form −

Below is dropdown.py script to handle input given by web browser.

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('dropdown'):
   subject = form.getvalue('dropdown')
else:
   subject = "Not entered"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Dropdown Box - Sixth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

Using Cookies in CGI

HTTP protocol is a stateless protocol. For a commercial website, it is required to maintain session information among different pages. For example, one user registration ends after completing many pages. How to maintain user's session information across all the web pages?

In many situations, using cookies is the most efficient method of remembering and tracking preferences, purchases, commissions, and other information required for better visitor experience or site statistics.

How It Works?

Your server sends some data to the visitor's browser in the form of a cookie. The browser may accept the cookie. If it does, it is stored as a plain text record on the visitor's hard drive. Now, when the visitor arrives at another page on your site, the cookie is available for retrieval. Once retrieved, your server knows/remembers what was stored.

Cookies are a plain text data record of 5 variable-length fields −

  • Expires − The date the cookie will expire. If this is blank, the cookie will expire when the visitor quits the browser.

  • Domain − The domain name of your site.

  • Path − The path to the directory or web page that sets the cookie. This may be blank if you want to retrieve the cookie from any directory or page.

  • Secure − If this field contains the word "secure", then the cookie may only be retrieved with a secure server. If this field is blank, no such restriction exists.

  • Name=Value − Cookies are set and retrieved in the form of key and value pairs.

Setting up Cookies

It is very easy to send cookies to browser. These cookies are sent along with HTTP Header before to Content-type field. Assuming you want to set UserID and Password as cookies. Setting the cookies is done as follows −

#!/usr/bin/python

print "Set-Cookie:UserID = XYZ;\r\n"
print "Set-Cookie:Password = XYZ123;\r\n"
print "Set-Cookie:Expires = Tuesday, 31-Dec-2007 23:12:40 GMT";\r\n"
print "Set-Cookie:Domain = www.tutorialspoint.com;\r\n"
print "Set-Cookie:Path = /perl;\n"
print "Content-type:text/html\r\n\r\n"
...........Rest of the HTML Content....

From this example, you must have understood how to set cookies. We use Set-Cookie HTTP header to set cookies.

It is optional to set cookies attributes like Expires, Domain, and Path. It is notable that cookies are set before sending magic line "Content-type:text/html\r\n\r\n.

Retrieving Cookies

It is very easy to retrieve all the set cookies. Cookies are stored in CGI environment variable HTTP_COOKIE and they will have following form −

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

Here is an example of how to retrieve cookies.

#!/usr/bin/python

# Import modules for CGI handling 
from os import environ
import cgi, cgitb

if environ.has_key('HTTP_COOKIE'):
   for cookie in map(strip, split(environ['HTTP_COOKIE'], ';')):
      (key, value ) = split(cookie, '=');
      if key == "UserID":
         user_id = value

      if key == "Password":
         password = value

print "User ID  = %s" % user_id
print "Password = %s" % password

This produces the following result for the cookies set by above script −

User ID = XYZ
Password = XYZ123

File Upload Example

To upload a file, the HTML form must have the enctype attribute set to multipart/form-data. The input tag with the file type creates a "Browse" button.

<html>
<body>
   <form enctype = "multipart/form-data" 
                     action = "save_file.py" method = "post">
   <p>File: <input type = "file" name = "filename" /></p>
   <p><input type = "submit" value = "Upload" /></p>
   </form>
</body>
</html>

The result of this code is the following form −

Above example has been disabled intentionally to save people uploading file on our server, but you can try above code with your server.

Here is the script save_file.py to handle file upload −

#!/usr/bin/python

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

form = cgi.FieldStorage()

# Get filename here.
fileitem = form['filename']

# Test if the file was uploaded
if fileitem.filename:
   # strip leading path from file name to avoid 
   # directory traversal attacks
   fn = os.path.basename(fileitem.filename)
   open('/tmp/' + fn, 'wb').write(fileitem.file.read())

   message = 'The file "' + fn + '" was uploaded successfully'
   
else:
   message = 'No file was uploaded'
   
print """\
Content-Type: text/html\n
<html>
<body>
   <p>%s</p>
</body>
</html>
""" % (message,)

If you run the above script on Unix/Linux, then you need to take care of replacing file separator as follows, otherwise on your windows machine above open() statement should work fine.

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

How To Raise a "File Download" Dialog Box?

Sometimes, it is desired that you want to give option where a user can click a link and it will pop up a "File Download" dialogue box to the user instead of displaying actual content. This is very easy and can be achieved through HTTP header. This HTTP header is be different from the header mentioned in previous section.

For example, if you want make a FileName file downloadable from a given link, then its syntax is as follows −

#!/usr/bin/python

# 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 here.
fo = open("foo.txt", "rb")

str = fo.read();
print str

# Close opend file
fo.close()

Hope you enjoyed this tutorial. If yes, please send me your feedback at: Contact Us