一 、CGI 编程之前缀篇
1、CGI 入门简介
CGI:是通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。组成CGI通信系统的是两部分:一部分是html页面,就是在用户端浏览器上显示的页面。另一部分则是运行在服务器上的CGI程序。
首先,我们应该明确的是CGI只是一种接口模式,是现代的web开发的基础,这里的CGI程序可以是Python脚本,PERL脚本,SHELL脚本,C或者C++程序等。本篇文章会涉及到一些web后端处理程序(python3编写),一小部分前端H5部分,以及apache2 服务器的初级使用教程(涵盖基础配置,设置等)。
这里附上一张运行示意图:(如下)
2、Apache2 的安装以及配置(运行环境搭建)
注释:这里笔者用的是Ubuntu 16.04 + python3.5 +mysql数据库 运行环境
sudo apt-get install apache2
- 检查是否成功
systemctl status apache2
- 第二步,打开你的浏览器,在导航栏里输入
localhost
回车 - 此时,出现Apache2 在Ubuntu 的导航网页,说明初步成功
接下来,开始配置Apache2 的 CGI 编程环境,这里先讲述一下,默认安装后,有这几个目录需要注意一下。
/etc/apache2 , /var/www/html ,/var/log/apache2/error(日志文件,经常用)
- 为了我们方便编程,于是将编辑目录放在自己的用户目录,不用每次访问编写时,都需要sudo提高权限
apache2在/etc/apache2和/etc/apache2/sites-available两个文件夹下面分别有apache2.conf和000-default.conf两个配置文件需要改。然后,在自己的用户目录
mkdir -p www/html 和 mkdir -p www/cgi-bin
以后,html 和CGI都放置在相应得目录里面即可。编辑/etc/apache2/apache2.conf这个文件,找到
<DDirectory /var/www/>
这个选项,把其中的/var/www/修改为/home/chen/www
注意这里的chen是笔者的用户目录,改成自己的用户目录。(原来的配置删掉或注释)-这里是我的一些配置
<Directory /home/chen/www/>
Options Indexes FollowSymLinks ExecCGI
AllowOverride All
Order allow,deny
Allow from all
AddHandler cgi-script .cgi .pl .py
Require all granted
</Directory>
少的东西自行添加
- 编辑/etc/apache2/sites-available/000-default.conf这个文件,找到"DocumentRoot /var/www/html" 这个选项,把其中的/var/www/html修改为`/home/chen/www/html`。
- 使用命令`sudo /etc/init.d/apache2 restart`来重启**apache**服务。
- 在浏览器地址栏输入服务器地址,此时显示的是自定义目录下的文件(/home/chen/www/html ) 。
- 接下来配置CGI 相关
- 在`/etc/apache2/apache2.conf`文件中最后添加如下一行:
- `ScriptAlias /cgi-bin/ /home/chen/www/cgi-bin/`
- 这一行的意思是告诉Apache:任何以/cgi-bin/开头的资源都将映射到/home/chen/www/cgi-bin/目录中,且视之为CGI程序。
- 导入cgid包 ,接着在刚才文件最后加入 `LoadModule cgid_module /usr/lib/apache2/modules/mod_cgid.so`
- 接下来就可以测试一下,是否配置好了
- 在自定义的/cgi-bin/文件夹中创建一个测试文件simple1.py
#!/usr/bin/python
print 'Content-Type: text/html'
print ''
print '<html>'
print '<h2>CGI Script Output</h2>'
print '<p>This page was generated by a Python CGI script.</p>'
print '</html>
- 用命令chmod 755 simple1.py赋予文件执行权限浏览器地址栏中输入地址:`http://localhost/cgi-bin/simple1.py`
- 如果有如下输出,这说明安装成功了
![first CGI ](https://img-blog.csdn.net/20171201170430640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc21pbGVqaWFzbWlsZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
注:安装过程如果出现错误,实在不能解决,可重新安装Apache 恢复默认,这里附上,完全卸载的方法 Apache 完全卸载
二 、开始 CGI programming 之旅
注:以下的 CGI 程序运行时,都需要使用chmod 755 EXE
提高执行权限,才可以运行,下面就不在重复讲述了
1 、HTTP相关知识讲述 - - - first
- HTTP头部的格式如下:
HTTP 字段名: 字段内容
例如:
Content-type: text/html 即为HTTP头部的一部分,它告诉浏览器文件的内容类型是html格式。
- CGI程序HTTP头部常用信息:
CGI 的相关环境变量 — 通过环境变量进行相互通信
GET和POST方法
浏览器客户端通过两种方法向服务器传递信息,这两种方法就是 GET 方法和 POST 方法。将在后面结合代码讲解。
2 、demo 随后 - - - - second
- 输出Apache 相关的运行信息 ,建立
environment.py
文件
#!/usr/bin/python3
import codecs,sys
import os
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
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>")
前三句代码主要是为了防止中文乱码,chmod 755 ,在导航栏输入localhost/cgi-bin/environment.py
即可运行
2、- 使用GET方法传输数据
GET方法发送编码后的用户信息到服务端,数据信息包含在请求页面的URL上,以”?”号分割, 如下所示:
http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2 有关 GET 请求的其他一些注释:
- GET 请求可被缓存
- GET 请求可被收藏为书签
- GET 请求不应在处理敏感数据时使用
- GET请求有长度限制 GET 请求只应当用于取回数据
- 简单的url实例:GET方法
以下是一个简单的URL,使用GET方法向hello_get.py程序发送两个参数:
/cgi-bin/test.py?name=chen&url=http://Mr.chen’s site
#!/usr/bin/python3
import codecs ,sys
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
# 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>The site of Mr.chen </title>")
print ("</head>")
print ("<meta charset=\"utf-8\">")
print ("<title> Mr.chen </title>")
print ("</head>")
print ("<body>")
print ("<h2>%s官网:%s</h2>" % (site_name, site_url))
print ("</body>")
print ("</html>")
浏览器输入localhost/cgi-bin/test.py?name=chen&url=http://Mr.chen's site
访问
3 、简单的表单实例:GET方法,以下是一个通过HTML的表单使用GET方法向服务器发送两个数据,提交的服务器脚本同样是hello_get.py文件,H5代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> Mr.chen site</title>
</head>
<body>
<form action="/cgi-bin/hello-get.py" method="get">
this is www.futhureme.cn. Welcome Mr.chen arrived ! ha ha <br />
站点名称: <input type="text" name="name"> <br />
站点 URL: <input type="text" name="url" />
<input type="submit" value="提交 after sure" />
</form>
</body>
</html>
浏览器输入localhost/hello-get.html
访问
4 、使用POST方法传递数据,使用POST方法向服务器传递数据是更安全可靠的,像一些敏感信息如用户密码等需要使用POST传输数据。
以下同样是hello_get.py ,它也可以处理浏览器提交的POST表单数据:
#!/usr/bin/python3
import codecs ,sys
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
# 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> Mr.chen </title>")
print ("</head>")
print ("<body>")
print ("<h2>%s官网:%s</h2>" % (site_name, site_url))
print ("</body>")
print ("</html>")
表单通过POST方法(method=”post”)向服务器脚本 hello_get.py 提交数据,将上述的 html 中的 改为 method=”post” 即可。
5 、通过CGI程序传递checkbox数据
checkbox用于提交一个或者多个选项数据,HTML代码如下
<!DOCTYPE>
<html>
<head>
<meta charset="utf-8">
<title> Mr.chen(www.Mr_chen.cn) </title>
</head>
<body>
<form action = "/cgi-bin/checkbox.py" method = "POST" target = "_blank">
<input type = "checkbox" name = "http://blog.csdn.net/smilejiasmile" value = "on" /> The site of Mr.smile
<input type = "checkbox" name = "google" value = "on" /> Google <br /> <br />
<input type = "submit" value = "选择站点" />
</form>
</body>
</html>
checkbox.py 文件的代码为:
#!/usr/bin/python3
# 引入 CGI 处理模块
import cgi,cgitb
# 创建 FieldStorage
form = cgi.FieldStorage()
# 接收字段数据
if form.getvalue('google'):
google_flag = 'yes'
else:
google_flag = 'No'
if form.getvalue('http://blog.csdn.net/smilejiasmile'):
smile_flag = 'yes'
else:
smile_flag = 'No'
print ('Content-type:text/html')
print ()
print ('<html>')
print ('<head>')
print ('<meta charset = \'utf-8\'>')
print ('<title> Mr.chen\'s site </title>')
print ('</head>')
print ('<body>')
print ('<h2> Mr.chen\'s site is choised : %s </h2>'%smile_flag)
print ('<h2> Google is choised : %s </h2>' %google_flag)
print ('</body>')
print ('</html>')
改权限 755 ,浏览器输入`localhost/checkbox.html
6 、通过CGI程序传递 Textarea 数据
Textarea 向服务器传递多行数据,HTML代码如下:
<!DOCTYPE>
<html>
<head>
<meta charset = "utf-8">
<title> Mr.chen's site </title>
</head>
<body>
<form action = "/cgi-bin/textarea.py" method = "post"target ="_parent">
please enter you content - - - - <br />
<textarea name = "textcontent" cols = "80" rows = "6">
</textarea> <br /><br />
<input type = "submit" value = "click after suring" />
</form>
</body>
</html>
textarea.py 脚本代码
#!/usr/bin/python3
import codecs ,sys
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
# 引入 CGI 处理模块
import cgi,cgitb
# 创建 FieldStorage 的实例
form = cgi.FieldStorage()
# 接收字段数据
if form.getvalue('textcontent'):
text_content = form.getvalue('textcontent')
else:
text_content = 'nothing'
print ('Content-type:text/html')
print ()
print ('<html>')
print ('<head>')
print ("<meta charset = \'utf-8\'>")
print ('<title> The site of Mr.chen </title>')
print ('</head>')
print ('<body>')
print ('<h2> you input content is :<pre> %s </h2>'% text_content)
print ('</body>')
print ('</html>')
7 、通过CGI程序传递下拉数据框。
HTML 下拉框代码:
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<title> The site of Mr.chen </title>
</head>
<body>
<form action = "/cgi-bin/dropdown.py" method = "post" target = "_parent">
<select name = "dropdown">
<option value = "Mr.chen's site" selected> chen </option>
<option value = "Google"> Google </option>
</select>
<input type = "submit" value = "click after suring" />
</form>
</body>
</html>
dropdown.py 脚本代码:
#!/usr/bin/python3
# 引入 CGI 处理模块
import cgi,cgitb
# 创建 FieldStrorage 的实例
form = cgi.FieldStorage()
# 接受字段数据
if form.getvalue('dropdown'):
dropdown_value = form.getvalue('dropdown')
else:
dropdown_value = 'Nothing'
print ("Content-type:text/html")
print ()
print ('<html>')
print ('<meta charset = \'utf-8\'>')
print ('<title> The site of Mr.chen </title>')
print ('</head>')
print ('<body>')
print ('<h2> your choise is : %s </h2>' % dropdown_value)
print ('</body>')
print ('</html>')
8 、CGI中使用Cookie , cookie 就是在客户访问脚本的同时,通过客户的浏览器,在客户硬盘上写入纪录数据 ,当下次客户访问脚本时取回数据信息,从而达到身份判别的功能,cookie 常用在身份校验中。
- cookie的语法
http cookie的发送是通过http头部来实现的,他早于文件的传递,头部set-cookie的语法如下:
Set-cookie:name=name;expires=date;path=path;domain=domain;secure
- name=name: 需要设置cookie的值(name不能使用”;”和”,”号),有多个name值时用 “;” 分隔,例如:name1=name1;name2=name2;name3=name3。
- expires=date: cookie的有效期限,格式: expires=”Wdy,DD-Mon-YYYY HH:MM:SS”
- path=path: 设置cookie支持的路径,如果path是一个路径,则cookie对这个目录下的所有文件及子目录生效,例如: path=”/cgi-bin/”,如果path是一个文件,则cookie指对这个文件生效,例如:path=”/cgi-bin/cookie.cgi”。
- domain=domain: 对cookie生效的域名,例如:domain=”www.runoob.com”
secure: 如果给出此标志,表示cookie只能通过SSL协议的https服务器来传递。
-cookie的接收是通过设置环境变量HTTP_COOKIE来实现的,CGI程序可以通过检索该变量获取cookie信息。
9 、Cookie设置
Cookie的设置非常简单,cookie会在http头部单独发送。以下实例在cookie中设置了name 和 expires:
注意这儿的时间设置,不要让cookie过时了就行。
#!/usr/bin/python3
print ('Content-type:text/html')
print ("Set-Cookie: name = 'Mr.chen';expires = Wed,1 Dec 2017 18:30:00 GMT")
print ()
print ("""
<html>
<head>
<meta charset = "utf-8">
<title> The site of Mr.chen </title>
</head>
<body>
<h1> Cookie set OK ! </h1>
</body>
</html>
""")
修改权限 755 ,浏览器运行即可完成设置cookie
以上实例使用了 Set-Cookie 头信息来设置Cookie信息,可选项中设置了Cookie的其他属性,如过期时间Expires,域名Domain,路径Path。这些信息设置在 “Content-type:text/html”之前。
10 、检索Cookie信息
Cookie信息检索页非常简单,Cookie信息存储在CGI的环境变量HTTP_COOKIE中,存储格式如下:
key1=value1;key2=value2;key3=value3….
demo 如下:
#!/usr/bin/python3
import codecs ,sys
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
# 导入模块
import os
from http import cookies
print ("Content-type: text/html")
print ()
print ("""
<html>
<head>
<meta charset = "utf-8">
<title> The sie of chen </title>
</head>
<body>
<h1> reading cookie 信息 </h1>
""")
if 'HTTP_COOKIE' in os.environ:
cookie_string = os.environ.get('HTTP_COOKIE')
c = cookies.SimpleCookie()
c.load(cookie_string)
try: # 捕捉异常
data = c['name'].value
print ("<h2> cookie data: "+ data + "</h2> <br>")
except KeyError:
print ("cookie 没有设置或者已经过时 <br>")
print ("""
</body>
</html>
""")
修改权限 755 ,浏览器运行即可完成获取 。
11 、文件上传实例
HTML设置上传文件的表单需要设置 enctype 属性为 multipart/form-data,代码如下所示:
<!DOCTYPE>
<html>
<head>
<meta charset = "utf-8">
<title> The site of Mr.chen </title>
</head>
<body>
<meta charset = "utf-8">
<form enctype = "multipart/form-data"
action = "/cgi-bin/save_file.py" method = "post">
<p> 选中文件:
<imput type = "file" name = "filename" id = "file" class = "inputfile"/>
<imput type = "file" name = "filename" id = "file" class = "inputfile"/> </p>
<p><input type = "submit" value = "upload" /></p>
</form>
</body>
</html>
save_file.py脚本文件代码:
#!/usr/bin/python3
import cgi,os
import cgitb;
cgitb.enable()
form = cgi.FieldStorage()
# 获取文件名
fileitem = form['filename']
# 检测文件是否上传
if fileitem.filename:
# 设置文件路径
fn = os.path.basename(filename)
open('/tmp/'+fn,'wb').write(fileitem.file.read())
message = '文件 "' + fn + '" upload success'
else:
message = 'no file upload'
print("""\
Content-Type:text/html\n
<html>
<head>
<meta charset= 'utf-8'>
<title> The site of Mr.chen </title>
</head>
<body>
<p>%s </p>
</body>
</html>
"""%(message,))
修改权限 755 ,浏览器运行即可。
12 、文件下载对话框
我们先在当前目录下创建 foo.txt 文件,用于程序的下载。
文件下载通过设置HTTP头信息来实现,功能代码如下:
#!/usr/bin/python3
# HTTP 头部
print ("Content-Disposition:attachment;filename = \"foo.txt\"")
print ()
#打开文件
fo = open("foo.txt","rb")
str = fo.read();
print(str)
# 关闭文件
fo.close()
注: 本文参考,自己的学习笔记,以及一些网站,如,runoob 等,整合而成。
—- Mr.chen